Skip to content

Commit a1f6360

Browse files
committed
micro-optimizes sorting
1 parent 3a8f44b commit a1f6360

File tree

4 files changed

+56
-32
lines changed

4 files changed

+56
-32
lines changed

code/__HELPERS/sorts/InsertSort.dm

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
//simple insertion sort - generally faster than merge for runs of 7 or smaller
22
/proc/sortInsert(list/L, cmp=/proc/cmp_numeric_asc, associative, fromIndex=1, toIndex=0)
3-
if(L && L.len >= 2)
4-
fromIndex = fromIndex % L.len
5-
toIndex = toIndex % (L.len+1)
3+
var/len = length(L)
4+
if(len >= 2)
5+
fromIndex = fromIndex % len
6+
toIndex = toIndex % (len + 1)
67
if(fromIndex <= 0)
7-
fromIndex += L.len
8+
fromIndex += len
89
if(toIndex <= 0)
9-
toIndex += L.len + 1
10+
toIndex += len + 1
1011

1112
var/datum/sort_instance/SI = GLOB.sortInstance
1213
if(!SI)

code/__HELPERS/sorts/MergeSort.dm

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
//merge-sort - gernerally faster than insert sort, for runs of 7 or larger
22
/proc/sortMerge(list/L, cmp=/proc/cmp_numeric_asc, associative, fromIndex=1, toIndex)
3-
if(L && L.len >= 2)
4-
fromIndex = fromIndex % L.len
5-
toIndex = toIndex % (L.len+1)
3+
var/len = length(L)
4+
if(len >= 2)
5+
fromIndex = fromIndex % len
6+
toIndex = toIndex % (len + 1)
67
if(fromIndex <= 0)
7-
fromIndex += L.len
8+
fromIndex += len
89
if(toIndex <= 0)
9-
toIndex += L.len + 1
10+
toIndex += len + 1
1011

1112
var/datum/sort_instance/SI = GLOB.sortInstance
1213
if(!SI)

code/__HELPERS/sorts/TimSort.dm

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
//TimSort interface
22
/proc/sortTim(list/L, cmp=/proc/cmp_numeric_asc, associative, fromIndex=1, toIndex=0)
3-
if(L && L.len >= 2)
4-
fromIndex = fromIndex % L.len
5-
toIndex = toIndex % (L.len+1)
3+
var/len = length(L)
4+
if(len >= 2)
5+
fromIndex = fromIndex % len
6+
toIndex = toIndex % (len + 1)
67
if(fromIndex <= 0)
7-
fromIndex += L.len
8+
fromIndex += len
89
if(toIndex <= 0)
9-
toIndex += L.len + 1
10+
toIndex += len + 1
1011

1112
var/datum/sort_instance/SI = GLOB.sortInstance
1213
if(!SI)

code/__HELPERS/sorts/__main.dm

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sort_instance, new())
1818
var/cmp = GLOBAL_PROC_REF(cmp_numeric_asc)
1919

2020
//whether we are sorting list keys (0: L[i]) or associated values (1: L[L[i]])
21-
var/associative = 0
21+
var/associative = FALSE
2222

2323
//This controls when we get *into* galloping mode. It is initialized to MIN_GALLOP.
2424
//The mergeLo and mergeHi methods nudge it higher for random data, and lower for highly structured data.
@@ -32,8 +32,10 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sort_instance, new())
3232

3333

3434
/datum/sort_instance/proc/timSort(start, end)
35-
runBases.Cut()
36-
runLens.Cut()
35+
var/list/runBases = src.runBases
36+
var/list/runLens = src.runLens
37+
runBases.len = 0
38+
runLens.len = 0
3739

3840
var/remaining = end - start
3941

@@ -59,8 +61,8 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sort_instance, new())
5961
runLen = force
6062

6163
//add data about run to queue
62-
runBases.Add(start)
63-
runLens.Add(runLen)
64+
runBases += start
65+
runLens += runLen
6466

6567
//maybe merge
6668
mergeCollapse()
@@ -101,6 +103,7 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sort_instance, new())
101103
if(start <= lo)
102104
start = lo + 1
103105

106+
var/list/L = src.L
104107
for(,start < hi, ++start)
105108
var/pivot = fetchElement(L,start)
106109

@@ -140,6 +143,7 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sort_instance, new())
140143
if(runHi >= hi)
141144
return 1
142145

146+
var/list/L = src.L
143147
var/last = fetchElement(L,lo)
144148
var/current = fetchElement(L,runHi++)
145149

@@ -177,8 +181,10 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sort_instance, new())
177181
//This method is called each time a new run is pushed onto the stack.
178182
//So the invariants are guaranteed to hold for i<stackSize upon entry to the method
179183
/datum/sort_instance/proc/mergeCollapse()
180-
while(runBases.len >= 2)
181-
var/n = runBases.len - 1
184+
var/list/runBases = src.runBases
185+
var/list/runLens = src.runLens
186+
while(length(runBases) >= 2)
187+
var/n = length(runBases) - 1
182188
if(n > 1 && runLens[n-1] <= runLens[n] + runLens[n+1])
183189
if(runLens[n-1] < runLens[n+1])
184190
--n
@@ -192,8 +198,10 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sort_instance, new())
192198
//Merges all runs on the stack until only one remains.
193199
//Called only once, to finalise the sort
194200
/datum/sort_instance/proc/mergeForceCollapse()
195-
while(runBases.len >= 2)
196-
var/n = runBases.len - 1
201+
var/list/runBases = src.runBases
202+
var/list/runLens = src.runLens
203+
while(length(runBases) >= 2)
204+
var/n = length(runBases) - 1
197205
if(n > 1 && runLens[n-1] < runLens[n+1])
198206
--n
199207
mergeAt(n)
@@ -206,6 +214,9 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sort_instance, new())
206214
//ASSERT(runBases.len >= 2)
207215
//ASSERT(i >= 1)
208216
//ASSERT(i == runBases.len - 1 || i == runBases.len - 2)
217+
var/list/runBases = src.runBases
218+
var/list/runLens = src.runLens
219+
var/list/L = src.L
209220

210221
var/base1 = runBases[i]
211222
var/base2 = runBases[i+1]
@@ -261,6 +272,7 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sort_instance, new())
261272

262273
var/lastOffset = 0
263274
var/offset = 1
275+
var/list/L = src.L
264276
if(call(cmp)(key, fetchElement(L,base+hint)) > 0)
265277
var/maxOffset = len - hint
266278
while(offset < maxOffset && call(cmp)(key, fetchElement(L,base+hint+offset)) > 0)
@@ -320,6 +332,7 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sort_instance, new())
320332

321333
var/offset = 1
322334
var/lastOffset = 0
335+
var/list/L = src.L
323336
if(call(cmp)(key, fetchElement(L,base+hint)) < 0) //key <= L[base+hint]
324337
var/maxOffset = hint + 1 //therefore we want to insert somewhere in the range [base,base+hint] = [base+,base+(hint+1))
325338
while(offset < maxOffset && call(cmp)(key, fetchElement(L,base+hint-offset)) < 0) //we are iterating backwards
@@ -368,6 +381,7 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sort_instance, new())
368381

369382
var/cursor1 = base1
370383
var/cursor2 = base2
384+
var/list/L = src.L
371385

372386
//degenerate cases
373387
if(len2 == 1)
@@ -384,7 +398,7 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sort_instance, new())
384398
--len2
385399

386400
outer:
387-
while(1)
401+
while(TRUE)
388402
var/count1 = 0 //# of times in a row that first run won
389403
var/count2 = 0 // " " " " " " second run won
390404

@@ -471,6 +485,7 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sort_instance, new())
471485
var/cursor1 = base1 + len1 - 1 //start at end of sublists
472486
var/cursor2 = base2 + len2 - 1
473487

488+
var/list/L = src.L
474489
//degenerate cases
475490
if(len2 == 1)
476491
move_element(L, base2, base1)
@@ -484,7 +499,7 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sort_instance, new())
484499
--len1
485500

486501
outer:
487-
while(1)
502+
while(TRUE)
488503
var/count1 = 0 //# of times in a row that first run won
489504
var/count2 = 0 // " " " " " " second run won
490505

@@ -574,24 +589,26 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sort_instance, new())
574589
return
575590

576591
var/minRun = minRunLength(remaining)
592+
var/list/runBases = src.runBases
593+
var/list/runLens = src.runLens
577594

578595
do
579596
var/runLen = (remaining <= minRun) ? remaining : minRun
580597

581598
binarySort(start, start+runLen, start)
582599

583600
//add data about run to queue
584-
runBases.Add(start)
585-
runLens.Add(runLen)
601+
runBases += start
602+
runLens += runLen
586603

587604
//Advance to find next run
588605
start += runLen
589606
remaining -= runLen
590607

591608
while(remaining > 0)
592609

593-
while(runBases.len >= 2)
594-
var/n = runBases.len - 1
610+
while(length(runBases) >= 2)
611+
var/n = length(runBases) - 1
595612
if(n > 1 && runLens[n-1] <= runLens[n] + runLens[n+1])
596613
if(runLens[n-1] < runLens[n+1])
597614
--n
@@ -601,15 +618,19 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sort_instance, new())
601618
else
602619
break //Invariant is established
603620

604-
while(runBases.len >= 2)
605-
var/n = runBases.len - 1
621+
while(length(runBases) >= 2)
622+
var/n = length(runBases) - 1
606623
if(n > 1 && runLens[n-1] < runLens[n+1])
607624
--n
608625
mergeAt2(n)
609626

610627
return L
611628

612629
/datum/sort_instance/proc/mergeAt2(i)
630+
var/list/runBases = src.runBases
631+
var/list/runLens = src.runLens
632+
var/list/L = src.L
633+
613634
var/cursor1 = runBases[i]
614635
var/cursor2 = runBases[i+1]
615636

0 commit comments

Comments
 (0)