@@ -80,44 +80,45 @@ contains
80
80
! a non-increasing sort. The logic of the determination of indexing largely
81
81
! follows the `"Rust" sort` found in `slice.rs`:
82
82
! https://github.com/rust-lang/rust/blob/90eb44a5897c39e3dff9c7e48e3973671dcd9496/src/liballoc/slice.rs#L2159
83
- ! The Rust version is a simplification of the Timsort algorithm described
84
- ! in https://svn.python.org/projects/python/trunk/Objects/listsort.txt, as
83
+ ! The Rust version in turn is a simplification of the Timsort algorithm
84
+ ! described in
85
+ ! https://svn.python.org/projects/python/trunk/Objects/listsort.txt, as
85
86
! it drops both the use of 'galloping' to identify bounds of regions to be
86
87
! sorted and the estimation of the optimal `run size`. However it remains
87
88
! a hybrid sorting algorithm combining an iterative Merge sort controlled
88
89
! by a stack of `RUNS` identified by regions of uniformly decreasing or
89
- ! non-decreasing sequences that may be expanded to a minimum run size, with
90
- ! an insertion sort.
90
+ ! non-decreasing sequences that may be expanded to a minimum run size and
91
+ ! initially processed by an insertion sort.
91
92
!
92
93
! Note the Fortran implementation simplifies the logic as it only has to
93
94
! deal with Fortran arrays of intrinsic types and not the full generality
94
95
! of Rust's arrays and lists for arbitrary types. It also adds the
95
96
! estimation of the optimal `run size` as suggested in Tim Peters'
96
- ! original listsort.txt, and the optional `work` and `iwork` arrays to be
97
+ ! original ` listsort.txt` , and the optional `work` and `iwork` arrays to be
97
98
! used as scratch memory.
98
99
99
- ${t1}$, intent(inout) :: array(0:)
100
+ ${t1}$, intent(inout) :: array(0:)
100
101
${ti}$, intent(out) :: index(0:)
101
- ${t3}$, intent(out), optional :: work(0:)
102
+ ${t3}$, intent(out), optional :: work(0:)
102
103
${ti}$, intent(out), optional :: iwork(0:)
103
- logical, intent(in), optional :: reverse
104
+ logical, intent(in), optional :: reverse
104
105
105
- ${ti}$ :: array_size, i, stat
106
106
${t2}$, allocatable :: buf(:)
107
107
${ti}$, allocatable :: ibuf(:)
108
+ integer(int_index) :: array_size, i, stat
108
109
109
- if ( size(array, kind=int_index) > huge(1_${ki}$) ) then
110
+ array_size = size(array, kind=int_index)
111
+
112
+ if ( array_size > huge(index)) then
110
113
error stop "Too many entries for the kind of index."
111
114
end if
112
115
113
- array_size = size(array, kind=${ki}$)
114
-
115
- if ( size(index, kind=${ki}$) < array_size ) then
116
- error stop "index array is too small."
116
+ if ( array_size > size(index, kind=int_index) ) then
117
+ error stop "Too many entries for the size of index."
117
118
end if
118
119
119
120
do i = 0, array_size-1
120
- index(i) = i+1
121
+ index(i) = int( i+1, kind=${ki}$)
121
122
end do
122
123
123
124
if ( optval(reverse, .false.) ) then
@@ -126,11 +127,11 @@ contains
126
127
127
128
! If necessary allocate buffers to serve as scratch memory.
128
129
if ( present(work) ) then
129
- if ( size(work, kind=${ki}$ ) < array_size/2 ) then
130
+ if ( size(work, kind=int_index ) < array_size/2 ) then
130
131
error stop "work array is too small."
131
132
end if
132
133
if ( present(iwork) ) then
133
- if ( size(iwork, kind=${ki}$ ) < array_size/2 ) then
134
+ if ( size(iwork, kind=int_index ) < array_size/2 ) then
134
135
error stop "iwork array is too small."
135
136
endif
136
137
call merge_sort( array, index, work, iwork )
@@ -148,7 +149,7 @@ contains
148
149
#:endif
149
150
if ( stat /= 0 ) error stop "Allocation of array buffer failed."
150
151
if ( present(iwork) ) then
151
- if ( size(iwork, kind=${ki}$ ) < array_size/2 ) then
152
+ if ( size(iwork, kind=int_index ) < array_size/2 ) then
152
153
error stop "iwork array is too small."
153
154
endif
154
155
call merge_sort( array, index, buf, iwork )
@@ -169,17 +170,17 @@ contains
169
170
!! Returns the minimum length of a run from 32-63 so that N/MIN_RUN is
170
171
!! less than or equal to a power of two. See
171
172
!! https://svn.python.org/projects/python/trunk/Objects/listsort.txt
172
- ${ti}$ :: min_run
173
- ${ti}$ , intent(in) :: n
173
+ integer(int_index) :: min_run
174
+ integer(int_index) , intent(in) :: n
174
175
175
- ${ti}$ :: num, r
176
+ integer(int_index) :: num, r
176
177
177
178
num = n
178
- r = 0_${ki}$
179
+ r = 0_int_index
179
180
180
181
do while( num >= 64 )
181
- r = ior( r, iand(num, 1_${ki}$ ) )
182
- num = ishft(num, -1_${ki}$ )
182
+ r = ior( r, iand(num, 1_int_index ) )
183
+ num = ishft(num, -1_int_index )
183
184
end do
184
185
min_run = num + r
185
186
@@ -189,13 +190,14 @@ contains
189
190
pure subroutine insertion_sort( array, index )
190
191
! Sorts `ARRAY` using an insertion sort, while maintaining consistency in
191
192
! location of the indices in `INDEX` to the elements of `ARRAY`.
192
- ${t1}$, intent(inout) :: array(0:)
193
+ ${t1}$, intent(inout) :: array(0:)
193
194
${ti}$, intent(inout) :: index(0:)
194
195
195
- ${ti}$ :: i, j, key_index
196
+ integer(int_index) :: i, j
197
+ ${ti}$ :: key_index
196
198
${t3}$ :: key
197
199
198
- do j=1, size(array, kind=${ki}$ )-1
200
+ do j=1, size(array, kind=int_index )-1
199
201
key = array(j)
200
202
key_index = index(j)
201
203
i = j - 1
@@ -218,14 +220,13 @@ contains
218
220
!
219
221
! 1. len(-3) > len(-2) + len(-1)
220
222
! 2. len(-2) > len(-1)
223
+ integer(int_index) :: r
224
+ type(run_type), intent(in), target :: runs(0:)
221
225
222
- ${ti}$ :: r
223
- type(run_type_${namei}$), intent(in), target :: runs(0:)
224
-
225
- ${ti}$ :: n
226
+ integer(int_index) :: n
226
227
logical :: test
227
228
228
- n = size(runs, kind=${ki}$ )
229
+ n = size(runs, kind=int_index )
229
230
test = .false.
230
231
if (n >= 2) then
231
232
if ( runs( n-1 ) % base == 0 .or. &
@@ -273,15 +274,16 @@ contains
273
274
! Consistency of the indices in `index` with the elements of `array`
274
275
! are maintained.
275
276
276
- ${t1}$, intent(inout) :: array(0:)
277
+ ${t1}$, intent(inout) :: array(0:)
277
278
${ti}$, intent(inout) :: index(0:)
278
279
279
280
${t3}$ :: tmp
280
- ${ti}$ :: i, tmp_index
281
+ integer(int_index) :: i
282
+ ${ti}$ :: tmp_index
281
283
282
284
tmp = array(0)
283
285
tmp_index = index(0)
284
- find_hole: do i=1, size(array, kind=${ki}$ )-1
286
+ find_hole: do i=1, size(array, kind=int_index )-1
285
287
if ( array(i) >= tmp ) exit find_hole
286
288
array(i-1) = array(i)
287
289
index(i-1) = index(i)
@@ -313,16 +315,16 @@ contains
313
315
! worst-case. Consistency of the indices in `index` with the elements of
314
316
! `array` are maintained.
315
317
316
- ${t1}$, intent(inout) :: array(0:)
318
+ ${t1}$, intent(inout) :: array(0:)
317
319
${ti}$, intent(inout) :: index(0:)
318
- ${t3}$, intent(inout) :: buf(0:)
320
+ ${t3}$, intent(inout) :: buf(0:)
319
321
${ti}$, intent(inout) :: ibuf(0:)
320
322
321
- ${ti}$ :: array_size, finish, min_run, r, r_count, &
323
+ integer(int_index) :: array_size, finish, min_run, r, r_count, &
322
324
start
323
- type(run_type_${namei}$ ) :: runs(0:max_merge_stack-1), left, right
325
+ type(run_type ) :: runs(0:max_merge_stack-1), left, right
324
326
325
- array_size = size(array, kind=${ki}$ )
327
+ array_size = size(array, kind=int_index )
326
328
327
329
! Very short runs are extended using insertion sort to span at least this
328
330
! many elements. Slices of up to this length are sorted using insertion sort.
@@ -333,7 +335,6 @@ contains
333
335
return
334
336
end if
335
337
336
-
337
338
! Following Rust sort, natural runs in `array` are identified by traversing
338
339
! it backwards. By traversing it backward, merges more often go in the
339
340
! opposite direction (forwards). According to developers of Rust sort,
@@ -370,7 +371,7 @@ contains
370
371
end do Insert
371
372
if ( start == 0 .and. finish == array_size - 1 ) return
372
373
373
- runs(r_count) = run_type_${namei}$ ( base = start, &
374
+ runs(r_count) = run_type ( base = start, &
374
375
len = finish - start + 1 )
375
376
finish = start-1
376
377
r_count = r_count + 1
@@ -383,12 +384,12 @@ contains
383
384
left = runs( r + 1 )
384
385
right = runs( r )
385
386
call merge( array( left % base: &
386
- right % base + right % len - 1 ), &
387
+ right % base + right % len - 1 ), &
387
388
left % len, buf, &
388
389
index( left % base: &
389
390
right % base + right % len - 1 ), ibuf )
390
391
391
- runs(r) = run_type_${namei}$ ( base = left % base, &
392
+ runs(r) = run_type ( base = left % base, &
392
393
len = left % len + right % len )
393
394
if ( r == r_count - 3 ) runs(r+1) = runs(r+2)
394
395
r_count = r_count - 1
@@ -406,15 +407,15 @@ contains
406
407
! using `BUF` as temporary storage, and stores the merged runs into
407
408
! `ARRAY(0:)`. `MID` must be > 0, and < `SIZE(ARRAY)-1`. Buffer `BUF`
408
409
! must be long enough to hold the shorter of the two runs.
409
- ${t1}$, intent(inout) :: array(0:)
410
- ${ti}$ , intent(in) :: mid
411
- ${t3}$, intent(inout) :: buf(0:)
410
+ ${t1}$, intent(inout) :: array(0:)
411
+ integer(int_index) , intent(in) :: mid
412
+ ${t3}$, intent(inout) :: buf(0:)
412
413
${ti}$, intent(inout) :: index(0:)
413
414
${ti}$, intent(inout) :: ibuf(0:)
414
415
415
- ${ti}$ :: array_len, i, j, k
416
+ integer(int_index) :: array_len, i, j, k
416
417
417
- array_len = size(array, kind=${ki}$ )
418
+ array_len = size(array, kind=int_index )
418
419
419
420
! Merge first copies the shorter run into `buf`. Then, depending on which
420
421
! run was shorter, it traces the copied run and the longer run forwards
@@ -474,11 +475,12 @@ contains
474
475
${t1}$, intent(inout) :: array(0:)
475
476
${ti}$, intent(inout) :: index(0:)
476
477
477
- ${ti}$ :: itemp, lo, hi
478
+ ${ti}$ :: itemp
479
+ integer(int_index) :: lo, hi
478
480
${t3}$ :: temp
479
481
480
482
lo = 0
481
- hi = size( array, kind=${ki}$ ) - 1
483
+ hi = size( array, kind=int_index ) - 1
482
484
do while( lo < hi )
483
485
temp = array(lo)
484
486
array(lo) = array(hi)
0 commit comments