ludic/selfhost/tests/sort.ludic
Orkuncakilkaya 4aa2012231
Some checks are pending
docs / build-and-deploy (push) Waiting to run
feat(stdlib): sorting toolkit — sort_by/sort_desc_by/sort_with + stable merge sort (#11)
Grow List sorting from a numeric-only insertion sort into a small,
game-friendly toolkit that sorts records and query results by a key or a
full comparator, stably and in O(n log n).

- List.sort_by(s, keyfn)      ascending by a key (draw order, price)
- List.sort_desc_by(s, keyfn) descending (leaderboards)
- List.sort_with(s, cmpfn)    full cmp(a,b)->int comparator (multi-field)

Comparators/keys are passed as named top-level functions rather than
lambdas, so the toolkit ships without waiting on closures (#1).

Engine: a stable bottom-up merge sort. emit_takeright is the single
place stability is decided ("take the right run's head only on a strict
win" -> equal keys keep prior order). List.sort becomes a hybrid:
insertion sort for n<32, merge sort above; both stable, so output is
unchanged. Key functions must return an integer-ish type; record slices
hold pointer elements, so the key/comparator receives the record pointer.

Tests: selfhost/tests/sort.ludic (scalar large-n, sort_by, sort_desc_by,
stability, sort_with). Docs: list-sort_by/desc_by/with + updated
list-sort. All suites green (28 self-host / 46 test / 29 test-tools);
reseeded, C-free bootstrap fixpoint holds.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-30 11:39:26 +03:00

74 lines
1.7 KiB
Text

program T {
property P { key: int = 0, tag: int = 0 }
function pkey(p: P) -> int { return p.key }
function cmp_key(a: P, b: P) -> int { return a.key - b.key }
entry {
# 1) scalar large-n path (merge sort): 40 descending -> ascending
let xs = new []int
for i in 0 .. 40 { push(xs, 39 - i) }
List.sort(xs)
print(xs[0]) # 0
print(xs[39]) # 39
print(xs[20]) # 20
# 2) sort_by ascending on records by a field
let ps = new []P
let a = new P
a.key = 3
push(ps, a)
let b = new P
b.key = 1
push(ps, b)
let c = new P
c.key = 2
push(ps, c)
List.sort_by(ps, pkey)
print(ps[0].key) # 1
print(ps[1].key) # 2
print(ps[2].key) # 3
# 3) sort_desc_by (leaderboard)
List.sort_desc_by(ps, pkey)
print(ps[0].key) # 3
print(ps[2].key) # 1
# 4) stability: equal keys keep their prior order
let qs = new []P
let q0 = new P
q0.key = 1
q0.tag = 10
push(qs, q0)
let q1 = new P
q1.key = 1
q1.tag = 20
push(qs, q1)
let q2 = new P
q2.key = 0
q2.tag = 30
push(qs, q2)
let q3 = new P
q3.key = 1
q3.tag = 40
push(qs, q3)
List.sort_by(qs, pkey)
print(qs[0].tag) # 30 (key 0)
print(qs[1].tag) # 10 (key 1, original order)
print(qs[2].tag) # 20
print(qs[3].tag) # 40
# 5) sort_with (full comparator, ascending)
let rs = new []P
let r0 = new P
r0.key = 5
push(rs, r0)
let r1 = new P
r1.key = 2
push(rs, r1)
let r2 = new P
r2.key = 8
push(rs, r2)
List.sort_with(rs, cmp_key)
print(rs[0].key) # 2
print(rs[2].key) # 8
}
}