This repository was archived by the owner on Mar 14, 2023. It is now read-only.
forked from openmc-dev/openmc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstl_vector.F90
351 lines (282 loc) · 10.2 KB
/
stl_vector.F90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
module stl_vector
! This module provides derived types that are meant to mimic the
! std::vector<T> type in C++. The vector type has numerous advantages over
! simple arrays and linked lists in that storage can grow and shrink
! dynamically, yet it is still contiguous in memory. Vectors can be filled
! element-by-element with automatic memory allocation in amortized constant
! time. In the implementation here, we grow the vector by a factor of 1.5 each
! time the capacity is exceed.
!
! The member functions which have been implemented here are:
!
! capacity -- Returns the size of the storage space currently allocated for
! the vector
!
! clear -- Remove all elements from the vector, leaving it with a size of
! 0. Note that this doesn't imply that storage is deallocated.
!
! initialize -- Set the storage size of the vector and optionally fill it with
! a particular value.
!
! pop_back -- Remove the last element of the vector, reducing the size by one.
!
! push_back -- Add a new element at the end of the vector. This increases the
! size of the vector by one. Note that the underlying storage is
! reallocated only if the size exceeds the capacity.
!
! reserve -- Requests that the capacity of the vector be a certain size.
!
! resize -- Resize the vector so it contains n elements. If n is larger than
! the current size, an optional fill value can be used to set the
! extra elements.
!
! shrink_to_fit -- Request that the capacity be reduced to fit the size.
!
! size -- Returns the number of elements in the vector.
implicit none
private
real(8), parameter :: GROWTH_FACTOR = 1.5
type, public :: VectorInt
integer, private :: size_ = 0
integer, private :: capacity_ = 0
integer, allocatable :: data(:)
contains
procedure :: capacity => capacity_int
procedure :: clear => clear_int
generic :: initialize => &
initialize_fill_int
procedure, private :: initialize_fill_int
procedure :: pop_back => pop_back_int
procedure :: push_back => push_back_int
procedure :: reserve => reserve_int
procedure :: resize => resize_int
procedure :: shrink_to_fit => shrink_to_fit_int
procedure :: size => size_int
end type VectorInt
type, public :: VectorReal
integer, private :: size_ = 0
integer, private :: capacity_ = 0
real(8), allocatable :: data(:)
contains
procedure :: capacity => capacity_real
procedure :: clear => clear_real
generic :: initialize => &
initialize_fill_real
procedure, private :: initialize_fill_real
procedure :: pop_back => pop_back_real
procedure :: push_back => push_back_real
procedure :: reserve => reserve_real
procedure :: resize => resize_real
procedure :: shrink_to_fit => shrink_to_fit_real
procedure :: size => size_real
end type VectorReal
contains
!===============================================================================
! Implementation of VectorInt
!===============================================================================
pure function capacity_int(this) result(capacity)
class(VectorInt), intent(in) :: this
integer :: capacity
capacity = this%capacity_
end function capacity_int
subroutine clear_int(this)
class(VectorInt), intent(inout) :: this
! Since integer is trivially destructible, we only need to set size to zero
! and can leave capacity as is
this%size_ = 0
end subroutine clear_int
subroutine initialize_fill_int(this, n, val)
class(VectorInt), intent(inout) :: this
integer, intent(in) :: n
integer, optional, intent(in) :: val
integer :: val_
! If no value given, fill the vector with zeros
if (present(val)) then
val_ = val
else
val_ = 0
end if
if (allocated(this%data)) deallocate(this%data)
allocate(this%data(n), SOURCE=val_)
this%size_ = n
this%capacity_ = n
end subroutine initialize_fill_int
subroutine pop_back_int(this)
class(VectorInt), intent(inout) :: this
if (this%size_ > 0) this%size_ = this%size_ - 1
end subroutine pop_back_int
subroutine push_back_int(this, val)
class(VectorInt), intent(inout) :: this
integer, intent(in) :: val
integer :: capacity
integer, allocatable :: data(:)
if (this%capacity_ == this%size_) then
! Create new data array that is GROWTH_FACTOR larger. Note that
if (this%capacity_ == 0) then
capacity = 8
else
capacity = int(GROWTH_FACTOR*this%capacity_)
end if
allocate(data(capacity))
! Copy existing elements
if (this%size_ > 0) data(1:this%size_) = this%data
! Move allocation
call move_alloc(FROM=data, TO=this%data)
this%capacity_ = capacity
end if
! Increase size of vector by one and set new element
this%size_ = this%size_ + 1
this%data(this%size_) = val
end subroutine push_back_int
subroutine reserve_int(this, n)
class(VectorInt), intent(inout) :: this
integer, intent(in) :: n
integer, allocatable :: data(:)
if (n > this%capacity_) then
allocate(data(n))
! Copy existing elements
if (this%size_ > 0) data(1:this%size_) = this%data(1:this%size_)
! Move allocation
call move_alloc(FROM=data, TO=this%data)
this%capacity_ = n
end if
end subroutine reserve_int
subroutine resize_int(this, n, val)
class(VectorInt), intent(inout) :: this
integer, intent(in) :: n
integer, intent(in), optional :: val
if (n < this%size_) then
this%size_ = n
elseif (n > this%size_) then
! If requested size is greater than capacity, first reserve that many
! elements
if (n > this%capacity_) call this%reserve(n)
! Fill added elements with specified value and increase size
if (present(val)) this%data(this%size_ + 1 : n) = val
this%size_ = n
end if
end subroutine resize_int
subroutine shrink_to_fit_int(this)
class(VectorInt), intent(inout) :: this
integer, allocatable :: data(:)
if (this%capacity_ > this%size_) then
if (this%size_ > 0) then
allocate(data(this%size_))
data(:) = this%data(1:this%size_)
call move_alloc(FROM=data, TO=this%data)
this%capacity_ = this%size_
else
if (allocated(this%data)) deallocate(this%data)
end if
end if
end subroutine shrink_to_fit_int
pure function size_int(this) result(size)
class(VectorInt), intent(in) :: this
integer :: size
size = this%size_
end function size_int
!===============================================================================
! Implementation of VectorReal
!===============================================================================
pure function capacity_real(this) result(capacity)
class(VectorReal), intent(in) :: this
integer :: capacity
capacity = this%capacity_
end function capacity_real
subroutine clear_real(this)
class(VectorReal), intent(inout) :: this
! Since real is trivially destructible, we only need to set size to zero and
! can leave capacity as is
this%size_ = 0
end subroutine clear_real
subroutine initialize_fill_real(this, n, val)
class(VectorReal), intent(inout) :: this
integer, intent(in) :: n
real(8), optional, intent(in) :: val
real(8) :: val_
! If no value given, fill the vector with zeros
if (present(val)) then
val_ = val
else
val_ = 0
end if
if (allocated(this%data)) deallocate(this%data)
allocate(this%data(n), SOURCE=val_)
this%size_ = n
this%capacity_ = n
end subroutine initialize_fill_real
subroutine pop_back_real(this)
class(VectorReal), intent(inout) :: this
if (this%size_ > 0) this%size_ = this%size_ - 1
end subroutine pop_back_real
subroutine push_back_real(this, val)
class(VectorReal), intent(inout) :: this
real(8), intent(in) :: val
integer :: capacity
real(8), allocatable :: data(:)
if (this%capacity_ == this%size_) then
! Create new data array that is GROWTH_FACTOR larger. Note that
if (this%capacity_ == 0) then
capacity = 8
else
capacity = int(GROWTH_FACTOR*this%capacity_)
end if
allocate(data(capacity))
! Copy existing elements
if (this%size_ > 0) data(1:this%size_) = this%data
! Move allocation
call move_alloc(FROM=data, TO=this%data)
this%capacity_ = capacity
end if
! Increase size of vector by one and set new element
this%size_ = this%size_ + 1
this%data(this%size_) = val
end subroutine push_back_real
subroutine reserve_real(this, n)
class(VectorReal), intent(inout) :: this
integer, intent(in) :: n
real(8), allocatable :: data(:)
if (n > this%capacity_) then
allocate(data(n))
! Copy existing elements
if (this%size_ > 0) data(1:this%size_) = this%data(1:this%size_)
! Move allocation
call move_alloc(FROM=data, TO=this%data)
this%capacity_ = n
end if
end subroutine reserve_real
subroutine resize_real(this, n, val)
class(VectorReal), intent(inout) :: this
integer, intent(in) :: n
real(8), intent(in), optional :: val
if (n < this%size_) then
this%size_ = n
elseif (n > this%size_) then
! If requested size is greater than capacity, first reserve that many
! elements
if (n > this%capacity_) call this%reserve(n)
! Fill added elements with specified value and increase size
if (present(val)) this%data(this%size_ + 1 : n) = val
this%size_ = n
end if
end subroutine resize_real
subroutine shrink_to_fit_real(this)
class(VectorReal), intent(inout) :: this
real(8), allocatable :: data(:)
if (this%capacity_ > this%size_) then
if (this%size_ > 0) then
allocate(data(this%size_))
data(:) = this%data(1:this%size_)
call move_alloc(FROM=data, TO=this%data)
this%capacity_ = this%size_
else
if (allocated(this%data)) deallocate(this%data)
end if
end if
end subroutine shrink_to_fit_real
pure function size_real(this) result(size)
class(VectorReal), intent(in) :: this
integer :: size
size = this%size_
end function size_real
end module stl_vector