silo:std.collections.linkedlist

Source src/silo:std.collections.linkedlist

1##! LinkedList — doubly-linked list with O(1) push/pop at both ends.
2##!
3##! `LinkedList elem` is a newtype over `(Vec elem)` — runtime layout
4##! matches `Vec`, but dispatch treats it as a nominally distinct type.
5##!
6##! Methods currently panic at runtime; real bodies require a
7##! doubly-linked node allocation surface for O(1) splice and O(n)
8##! walks. `Cursor` / `CursorMut` are deferred; Seq-hierarchy impls
9##! (`Foldable`, `Mappable`, `Filterable`, `Chainable`, `Indexed`,
10##! `Zippable`) arrive alongside that wiring.
11##!
12##! Not re-exported by the prelude — use
13##! `:use :open silo:std.collections.linkedlist ...`.
14
15:use
16  :open core AnyInt Bool Option Vec Pair
17  :open effects.panic panic
18:end
19
20# si[impl coll.linkedlist.len]
21# si[impl coll.linkedlist.is-empty]
22# si[impl coll.linkedlist.push-front]
23# si[impl coll.linkedlist.push-back]
24# si[impl coll.linkedlist.pop-front]
25# si[impl coll.linkedlist.pop-back]
26# si[impl coll.linkedlist.front]
27# si[impl coll.linkedlist.back]
28# si[impl coll.linkedlist.append]
29# si[impl coll.linkedlist.prepend]
30# si[impl coll.linkedlist.split-at]
31# si[impl coll.linkedlist.reverse]
32# si[impl coll.linkedlist.get]
33# si[impl coll.linkedlist.zip]
34# si[impl coll.linkedlist.from-vec]
35# si[impl coll.linkedlist.to-vec]
36## Doubly-linked list. Runtime layout shares `(Vec elem)` but
37## `LinkedList` is a distinct type for dispatch — Vec methods like
38## `.push` do NOT resolve through `LinkedList`.
39:type(pub) LinkedList elem (Vec elem)
40
41:impl (LinkedList elem)
42  # si[impl coll.linkedlist.len+1]
43  ## Number of elements in O(1). Implementations MUST cache length.
44  .len ( (LinkedList elem) -> AnyInt )
45    linkedlist-len-intrinsic ;
46
47  # si[impl coll.linkedlist.is-empty+1]
48  ## True iff the list contains zero elements.
49  .is-empty ( (LinkedList elem) -> Bool )
50    linkedlist-is-empty-intrinsic ;
51
52  # si[impl coll.linkedlist.front]
53  ## `.front` returns `Some` with the first element or `None` if empty. O(1).
54  ## Real body: reads the first element of the backing Vec cell (LinkedList
55  ## is a newtype over `(Vec elem)`), wraps it in `Some`, or returns `None`
56  ## on an empty list. Real doubly-linked-node semantics arrive with a
57  ## follow-up WP; this body is correct for the Vec-layout stub.
58  .front ( (LinkedList elem) -> (Option elem) )
59    linkedlist-front-intrinsic ;
60
61  # si[impl coll.linkedlist.back]
62  ## `.back` returns `Some` with the last element or `None` if empty. O(1).
63  ## Real body: reads the last element of the backing Vec cell.
64  .back ( (LinkedList elem) -> (Option elem) )
65    linkedlist-back-intrinsic ;
66
67  # si[impl coll.linkedlist.push-front]
68  ## Prepend an element to the front. Spec-guaranteed O(1); on the
69  ## Vec-layout stub this rebuilds the backing Vec so it is O(n) until
70  ## the doubly-linked-node runtime lands.
71  .push-front ( elem (LinkedList elem) -> (LinkedList elem) )
72    linkedlist-push-front-intrinsic ;
73
74  # si[impl coll.linkedlist.push-back]
75  ## Append an element to the back. O(1).
76  .push-back ( elem (LinkedList elem) -> (LinkedList elem) )
77    :todo "awaits host doubly-linked-node intrinsics" ;
78
79  # si[impl coll.linkedlist.pop-front]
80  ## Remove and return the front element. O(1).
81  .pop-front ( (LinkedList elem) -> (LinkedList elem) (Option elem) )
82    :todo "awaits host doubly-linked-node intrinsics" ;
83
84  # si[impl coll.linkedlist.pop-back]
85  ## Remove and return the back element. O(1).
86  .pop-back ( (LinkedList elem) -> (LinkedList elem) (Option elem) )
87    :todo "awaits host doubly-linked-node intrinsics" ;
88
89  # si[impl coll.linkedlist.append]
90  ## Move all elements of the second list onto the back of the first.
91  ## Spec-guaranteed O(1); on the Vec-layout stub this copies both Vecs.
92  .append ( (LinkedList elem) (LinkedList elem) -> (LinkedList elem) )
93    linkedlist-append-intrinsic ;
94
95  # si[impl coll.linkedlist.prepend]
96  ## Move all elements of the second list onto the front of the first.
97  ## Spec-guaranteed O(1); on the Vec-layout stub this copies both Vecs.
98  .prepend ( (LinkedList elem) (LinkedList elem) -> (LinkedList elem) )
99    linkedlist-prepend-intrinsic ;
100
101  # si[impl coll.linkedlist.split-at]
102  ## Split the list at the given 0-based index, returning prefix + suffix.
103  ## Complexity O(min(n, len - n)); negative `n` is a runtime error.
104  .split-at ( AnyInt (LinkedList elem) -> (LinkedList elem) (LinkedList elem) )
105    :todo "awaits host doubly-linked-node intrinsics" ;
106
107  # si[impl coll.linkedlist.reverse]
108  ## Return a new list with elements in reverse order. O(n).
109  .reverse ( (LinkedList elem) -> (LinkedList elem) )
110    linkedlist-reverse-intrinsic ;
111
112  # si[impl coll.linkedlist.get]
113  ## Return `Some` with the element at the given 0-based index, or `None`
114  ## if out of bounds. O(n) — walks from nearer end.
115  .get ( AnyInt (LinkedList elem) -> (Option elem) )
116    :todo "awaits host doubly-linked-node intrinsics" ;
117
118  # si[impl coll.linkedlist.to-vec]
119  ## Convert a `(LinkedList elem)` to a `(Vec elem)` in front-to-back order.
120  ## Runtime identity cast — the backing cell is already a Vec.
121  .to-vec ( (LinkedList elem) -> (Vec elem) )
122    linkedlist-to-vec-intrinsic ;
123:end
124
125# si[impl coll.linkedlist.zip]
126## `.zip` — free-fn form. Methods dispatch on Self and `.zip` would
127## collide with `Zippable` once that trait is wired onto `LinkedList`;
128## until then the free fn keeps the surface reachable without deciding
129## the Zippable question. Pairs elements positionally; result length is
130## `min(a.len, b.len)`.
131:fn(pub) linkedlist-zip ( (LinkedList a) (LinkedList b) -> (LinkedList (Pair a b)) )
132  :todo "awaits host doubly-linked-node intrinsics"
133:end
134
135# si[impl coll.linkedlist.from-vec]
136## Convert a `(Vec elem)` to a `(LinkedList elem)`, preserving order.
137## Free fn rather than method because method dispatch on `(Vec elem)`
138## would collide across `VecDeque`, `LinkedList`, `BinaryHeap` et al.
139## Runtime identity cast — the underlying cell is already a Vec.
140:fn(pub) linkedlist-from-vec ( (Vec elem) -> (LinkedList elem) )
141  linkedlist-from-vec-intrinsic
142:end