Skip to content

Commit c08cab3

Browse files
authored
Merge pull request #39 from sourceryinstitute/smart-pointers
More clear, descriptive, and safe nomenclature
2 parents 974ebeb + 26e1718 commit c08cab3

17 files changed

+265
-245
lines changed

README.md

Lines changed: 61 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,75 @@
1-
Reference Counter
2-
=================
1+
Smart Pointers
2+
==============
33

44
```
5-
__________ _____
6-
\______ \ _____/ ____\___________ ____ ____ ____ ____
7-
| _// __ \ __\/ __ \_ __ \_/ __ \ / \_/ ___\/ __ \
8-
| | \ ___/| | \ ___/| | \/\ ___/| | \ \__\ ___/
9-
|____|_ /\___> |__| \___> |__| \___> |___| /\____>\___>
10-
\/
11-
_________ __
12-
\_ ___ \ ____ __ __ _____/ |_ ___________
13-
/ \ \/ / _ \| | \/ \ __\/ __ \_ __ \
14-
\ \___( <_> ) | / | \ | \ ___/| | \/
15-
\_______/ \____/|____/|___| /__| \___> __|
5+
_________ __
6+
/ _____/ _____ _____ ________/ |_
7+
\_____ \ / \\__ \\_ __ \ __\
8+
/ \ Y Y \/ __ \| | \/| |
9+
/_______ /__|_| (____ /__| |__|
10+
\/ \/ \/
11+
__________ .__ __
12+
\______ \____ |__| _____/ |_ ___________ ______
13+
| ___/ _ \| |/ \ __\/ __ \_ __ \/ ___/
14+
| | ( <_> ) | | \ | \ ___/| | \/\___ \
15+
|____| \____/|__|___| /__| \___ >__| /____ >
16+
\/ \/ \/
1617
\/
1718
```
1819

1920
Overview
2021
--------
21-
Reference Counter offers semi-automatic counting of references to program resources
22-
such as memory. A user accesses the provided reference-counting capability simply
23-
by defining a non-abstract derived type that
22+
The Smart-Pointers library tracks references to program resources and automates
23+
the freeing of those resources if and only if the reference count drops to zero.
24+
Most commonly, the reference is a pointer and the resource is memory. In that
25+
context, Smart-Pointers help to prevent memory leaks and dangling pointers, which
26+
commonly causes programs to crash due to memory limitations or segmentation faults,
27+
respectively.
2428

25-
1. Extends Reference Counter's `ref_reference_t` type and
26-
2. Implements the so-inherited `free` deferred binding.
29+
To use Smart-Pointers, define a non-abstract derived type that
2730

28-
Because the reference-counting algorithm involves copying references in certain
29-
circumstances, the user type that extends `ref_reference_t` should be a lightweight
30-
proxy for a more stateful entity stored elsewhere. For example, the user type might
31-
contain a Fortran `pointer` associated with some other object or it might contain
32-
a "shadow" object that serves as an identity tag for a larger object allocated
33-
(and later freed) in C or C++ at the direction of the user's `free` procedure.
31+
1. Extends Smart Pointer's `sp_smart_pointer_t` type,
32+
2. Implements the inherited `free` deferred binding, and
33+
3. Invokes the inherited `start_count` procedure inside object constructors.
34+
35+
You can then use intrinsic assignments to copy instances of a `sp_smart_pointer_t`
36+
child type, resulting in a [shallow copy] with the advantage that the target
37+
will be finalized only when it becomes safe to do so.
38+
39+
Example
40+
-------
41+
See the [example](./example) folder for a demonstration of the use of Smart-Pointers.
42+
43+
Background
44+
----------
3445

3546
For more background on the design philosophy and the internal mechanics of Reference
3647
Counter, see Rouson et al. (see [[1]], [[2]], [[3]]). This repository's code
3748
originated from refactoring the code in those publications to use more descriptive
38-
and more general nomenclature and more up-to-date coding conventions. For example,
39-
this repository separates interface bodies into modules and procedure definitions
40-
into submodules.
49+
more up-to-date coding conventions. For example, this repository separates interface
50+
bodies into modules and procedure definitions into submodules. This repository also
51+
uses more descriptive nomenclature for the types and procedures.
4152

42-
As compared to the original code, this repository also adds
53+
This repository also adds
4354
1. A [Fortran Package Manager] build system,
44-
2. Tests based on the [Vegetables] unit-testing software,
55+
2. Tests based on the [Veggies] unit-testing framework,
4556
3. Documentation generated by [`ford`] and deployed to the web via GitHub Actions, and
4657
4. Quality control via continuous integration testing using GitHub Actions.
4758

48-
Documentation
49-
-------------
50-
See [Reference Counter's GitHub Pages site] for HTML documentation generated with [`ford`].
51-
52-
See the [doc/] subdirectory for a [PlantUML] script that generates the Unified Modeling Langauge (UML) class diagram below of the three derived types in reference-counter.
53-
54-
![class_diagram](https://user-images.githubusercontent.com/13108868/165135689-4d2e85fe-6946-472f-a154-aaabebf6d4f5.png)
55-
56-
The above image was created with the PlantuML package in the [Atom] editor.
57-
58-
59-
Compiler Status
60-
---------------
59+
Supported Compilers
60+
-------------------
6161
Correct execution of the Reference Counter library code requires comprehensive
6262
compiler support for Fortran's type finalization semantics. The unit test suite
63-
includes compiler standard-conformance tests. We have attempted to include at least
64-
one example of each scenario in which the Fortran 2018 standard requires compilers
65-
to finalize objects. The table below summarizes the observed compiler behaviors:
63+
includes compiler standard-conformance tests that include a test for each scenario
64+
in which the Fortran 2018 standard requires that an object be finalized.
65+
The table below summarizes the observed compiler behaviors:
6666

6767
| _Compiler_ | _Test failures_ | _Version tested_ |
6868
| :--- | :---: | :--- |
6969
| NAG | 0 | `nagfor` 7.1 Build 7113 |
70-
| GCC | 6 | `gfortran` 12.2.0 |
7170
| Intel | 2 | `ifort` 2021.5.0 Build 20211109\_000000 |
71+
| Cray | 3 | `ftn` 13.0.1 |
72+
| GCC | 6 | `gfortran` 12.2.0 |
7273
| NVIDIA | Fails to build (ICE) | `nvfortran` 2022.2 |
7374
| AMD | Fails to build (ICE) | `flang` 13.0.0 (AOCC_3.2.0-Build\#128 2021\_11\_12) |
7475

@@ -80,19 +81,19 @@ Downloading, Building, and Testing
8081
On Linux, macOS, or Windows Subsystem for Linux, download, build, and test with
8182
the following shell commands:
8283
```
83-
git clone git@github.com:sourceryinstitute/reference-counter
84-
cd reference-counter
84+
git clone https://github.com/sourceryinstitute/smart-pointer
85+
cd smart-pointer
8586
```
86-
followed by one of the commands below depending on your compiler choice.
87+
followed by one of the commands below corresponding to your compiler choice.
8788

88-
### GCC (`gfortran`)
89+
### Numerical Algorithms Group (`nagfor`)
8990
```
90-
fpm test
91+
fpm test --compiler nagfor --flag -fpp
9192
```
9293

93-
### Numerical Algorithms Group (`nagfor`)
94+
### GCC (`gfortran`)
9495
```
95-
fpm test --compiler nagfor --flag -fpp
96+
fpm test
9697
```
9798

9899
### Intel (`ifort`)
@@ -110,6 +111,12 @@ fpm test --compiler nvfortran --flag -Mpreprocess
110111
fpm test --compiler flang --flag -cpp
111112
```
112113

114+
Documentation
115+
-------------
116+
See [Reference Counter's GitHub Pages site] for HTML documentation generated with [`ford`].
117+
See the [doc/] subdirectory for a [PlantUML] script that generates the Unified Modeling Langauge (UML)
118+
class diagram below of the three derived types in reference-counter.
119+
113120
[1]: https://doi.org/10.1016/j.procs.2010.04.166
114121
[2]: https://doi.org/10.1017/cbo9780511977381
115122
[3]: https://doi.org/10.1109/MCSE.2012.33
@@ -120,3 +127,4 @@ fpm test --compiler flang --flag -cpp
120127
[Atom]: https://atom.io
121128
[PlantUML]: https://plantuml.com
122129
[doc/]: ./doc
130+
[shallow copy]: https://en.wikipedia.org/wiki/Object_copying#Shallow_copy

doc/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Classes
2+
-------
3+
4+
The Unified Modeling Language (UML) class diagram below depicts the classes
5+
in the Smart-Pointer library. Non-abstract user-defined derived types that
6+
extend `sp_smart_pointer_t` inherit an obligation to define the `free` deferred
7+
binding according to the `free_interface` abstract interface defined in
8+
`sp_resource_m`. The user-defined `free` subroutine must free the associated
9+
resource, which usually means deallocating the associated memory.
10+
11+
![class_diagram](https://user-images.githubusercontent.com/13108868/165135689-4d2e85fe-6946-472f-a154-aaabebf6d4f5.png)
12+

example/smart_pointer.f90

Lines changed: 42 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,25 @@
1-
module foo_m
1+
module user_object_m
2+
use smart_pointer_m, only: sp_smart_pointer_t
23
implicit none
34

45
private
5-
public :: foo_t
6+
public :: user_object_t, user_object_ptr_t
67

7-
type foo_t
8+
type user_object_t
89
end type
910

10-
end module
11-
12-
module smart_pointer_m
13-
use reference_counter_m, only: ref_reference_t
14-
use foo_m, only : foo_t
15-
16-
implicit none
17-
private
18-
public :: smart_pointer_t
19-
20-
type, extends(ref_reference_t) :: smart_pointer_t
21-
type(foo_t), pointer :: ref => null()
11+
type, extends(sp_smart_pointer_t) :: user_object_ptr_t
12+
type(user_object_t), pointer :: ref => null()
2213
contains
2314
procedure :: free
2415
end type
2516

26-
interface smart_pointer_t
17+
interface user_object_ptr_t
2718

28-
module function construct(foo) result(smart_pointer)
19+
module function construct(user_object) result(user_object_ptr)
2920
implicit none
30-
type(foo_t), intent(in), pointer:: foo
31-
type(smart_pointer_t) :: smart_pointer
21+
type(user_object_t), intent(in), pointer:: user_object
22+
type(user_object_ptr_t) :: user_object_ptr
3223
end function
3324

3425
end interface
@@ -37,65 +28,73 @@ module function construct(foo) result(smart_pointer)
3728

3829
module subroutine free(self)
3930
implicit none
40-
class(smart_pointer_t), intent(inout) :: self
31+
class(user_object_ptr_t), intent(inout) :: self
4132
end subroutine
4233

4334
end interface
4435

4536
end module
4637

47-
submodule(smart_pointer_m) smart_pointer_s
38+
submodule(user_object_m) user_object_ptr_s
4839
use assert_m, only : assert
4940
implicit none
5041

5142
contains
5243

5344
module procedure construct
54-
call assert(associated(foo), "construct_from_pointer: associated(foo)")
55-
smart_pointer%ref => foo
56-
call smart_pointer%start_ref_counter
45+
call assert(associated(user_object), "construct_from_pointer: associated(user_object)")
46+
user_object_ptr%ref => user_object
47+
call user_object_ptr%start_counter
5748
end procedure
5849

5950
module procedure free
6051
if (associated(self%ref)) then
6152
deallocate(self%ref)
6253
nullify(self%ref)
63-
print *,"free(): foo deallocated"
54+
print *,"free(): user_object deallocated"
6455
end if
6556
end procedure
6657

6758
end submodule
6859

6960
program main
70-
use smart_pointer_m, only : smart_pointer_t
71-
use foo_m, only : foo_t
61+
use user_object_m, only : user_object_t, user_object_ptr_t
62+
use assert_m, only : assert
7263
implicit none
7364

7465
block
66+
type(user_object_ptr_t) smart_pointer_1, smart_pointer_2
67+
type(user_object_t), pointer :: user_object => null()
7568

76-
type(smart_pointer_t) ptr_1, ptr_2
77-
type(foo_t), pointer :: foo => null()
69+
print *, "Allocating user_object pointer."
70+
allocate(user_object, source = user_object_t())
7871

79-
allocate(foo, source = foo_t())
80-
ptr_1 = smart_pointer_t(foo) ! 1st reference
81-
print *, ptr_1%reference_count()
82-
ptr_2 = ptr_1 ! 2nd reference
83-
print *, ptr_2%reference_count()
84-
call new_reference(ptr_2)
85-
print *, ptr_2%reference_count() ! 2 remaining references
72+
print *, "Defining smart_pointer_1."
73+
smart_pointer_1 = user_object_ptr_t(user_object)
74+
print *, "Reference count = ", smart_pointer_1%reference_count()
75+
print *, "Copying smart_pointer_1 into smart_pointer_2."
8676

87-
end block ! ref_reference_counter frees the memory after the 2 remaining references go out of scope
77+
smart_pointer_2 = smart_pointer_1
78+
print *, "Reference count = ", smart_pointer_1%reference_count()
79+
call assert(smart_pointer_1%reference_count()==smart_pointer_2%reference_count(), "consistent counts")
8880

89-
print *,"All references gone"
81+
call new_reference(smart_pointer_2)
82+
call assert(smart_pointer_1%reference_count()==smart_pointer_2%reference_count(), "consistent counts")
83+
print *, "Reference count = ", smart_pointer_1%reference_count()
84+
print *, "smart_pointer_1 and smart_pointer_2 going out of scope"
85+
end block
9086

9187
contains
9288

93-
subroutine new_reference(obj)
94-
type(smart_pointer_t), intent(in) :: obj
95-
type(smart_pointer_t) local_ptr
89+
subroutine new_reference(dummy_argument)
90+
type(user_object_ptr_t), intent(in) :: dummy_argument
91+
type(user_object_ptr_t) smart_pointer_3
9692

97-
local_ptr = obj ! 3rd reference
98-
print *, local_ptr%reference_count()
93+
print *, "Copying smart_pointer_2 into smart_pointer_3."
94+
smart_pointer_3 = dummy_argument
95+
call assert(dummy_argument%reference_count()==smart_pointer_3%reference_count(), "consistent counts")
96+
print *, "Reference count = ", smart_pointer_3%reference_count()
97+
print *, "smart_pointer_3 going out of scope."
9998
end subroutine
10099

101100
end program

src/reference_counter/ref_counter_m.f90

Lines changed: 0 additions & 64 deletions
This file was deleted.

0 commit comments

Comments
 (0)