Skip to content

Commit 1344005

Browse files
Merge pull request #22 from Michal-Martinek/STD/list
Std/list
2 parents 4b94f30 + cca5af9 commit 1344005

File tree

3 files changed

+563
-0
lines changed

3 files changed

+563
-0
lines changed

std/ds/list.mx

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
2+
%include "memory"
3+
%include "heap"
4+
%include "control"
5+
%include "math"
6+
%include "procedures"
7+
%include "structs"
8+
%include "exceptions"
9+
10+
; single node of linked list, with one-word value (int / ptr)
11+
%namespace list_node {
12+
%struct:begin()
13+
%struct:field(next, 1) ; *list_node
14+
%struct:field(value, 1)
15+
16+
%macro init() {
17+
str 0
18+
}
19+
%macro deinit() {
20+
str 0
21+
}
22+
; @list_node -> bool
23+
%macro has_next() {
24+
lmne 0
25+
}
26+
%macro mov_next() {
27+
movm
28+
}
29+
30+
%struct:end()
31+
}
32+
33+
;; singly linked list of list_nodes
34+
;; this parameter is pointer to list struct! (to list_node* this.head)
35+
%namespace list {
36+
%namespace helpers {
37+
; (this.head) -> (THIS)
38+
%macro head_to_this() {
39+
%seg:pointptr(%this, %this, %list:head)
40+
}
41+
; (THIS) -> bool (r)
42+
%macro this_has_next() {
43+
%seg:load(%this, %list_node:next)
44+
}
45+
; THIS = THIS.next
46+
%macro advance_this() {
47+
%seg:pointptr(%this, %this, %list_node:next)
48+
}
49+
}
50+
%using helpers
51+
52+
;; API
53+
%struct:begin()
54+
%struct:field(head, 1) ; *list_node
55+
56+
; @list
57+
; initialize to empty state
58+
%macro init() {
59+
str 0
60+
}
61+
; @list
62+
; free all list nodes
63+
%macro deinit() {
64+
%stack:pushh()
65+
%call(list_clear)
66+
}
67+
68+
; this ->
69+
; clears list by deallocating all it's nodes
70+
; node values should be deconstructed in advance
71+
%void_method{ list_clear, 1, 1, ; next=null
72+
%seg:set(%local, 0, 0)
73+
%while { %load(%this), ; THIS != null
74+
%seg:load(%this, %list_node:next) ; new_next <- THIS.next <- null
75+
str 0
76+
%stack:pushr() ; new_next
77+
%if { %seg:load(%local, 0), ; old_next != null
78+
%stack:dup_over(1)
79+
%call(free)
80+
}
81+
%seg:pop(%local, 0) ; next = new_next
82+
%storer(%this) ; THIS = new_next
83+
}
84+
}
85+
86+
; this -> value (THIS)
87+
; get value of first element
88+
%method{ list_first, 1, 0,
89+
%call(__list_assert_this_has_next)
90+
%head_to_this()
91+
%seg:load(%this, %list_node:value)
92+
}
93+
; this -> value (THIS)
94+
; get value of last element
95+
%method{ list_last, 1, 0,
96+
%call(__list_assert_this_has_next)
97+
%call(__list_index_last)
98+
%seg:load(%this, %list_node:value)
99+
}
100+
101+
; (THIS)
102+
; moves itrs: THIS - curr node, SRC - previous node
103+
; performs %instrs on each element
104+
; - value @h, current list_node at THIS
105+
; - element index at stack:top (readonly)
106+
; - after iteration: index in m (-1 if empty)
107+
%macro foreach(instrs) {
108+
%stack:push(%minus1)
109+
%while { %this_has_next(), ; THIS.next != null
110+
%seg:point(%src, %this, 0) ; SRC = THIS
111+
%advance_this() ; THIS = THIS.next
112+
%stack:top() ; index ++
113+
stra 1
114+
%seg:move(%this, %list_node:value)
115+
%instrs
116+
}
117+
%stack:drop()
118+
}
119+
120+
; this -> size
121+
%method{ list_size, 1, 0,
122+
%foreach { ld 0 }
123+
ldma 1
124+
}
125+
; this, index -> value (THIS)
126+
%method{ list_index, 2, 0,
127+
%foreach {
128+
%if { ; index == index
129+
%stack:top() ; loop idx
130+
%seg:arg(1, leqm)
131+
,
132+
%seg:load(%this, %list_node:value)
133+
%returnr(list_index)
134+
}
135+
}
136+
%error(2)
137+
}
138+
139+
; after: *node, value -> (THIS)
140+
; insert new value after node
141+
; for insert_first() set: after = this
142+
%void_method{ list_insert_after, 2, 0,
143+
; method: THIS = after
144+
%list_node:new() ; new node after
145+
%call(__list_insert_after_this)
146+
%seg:load(%arg, 1) ; new.value = value
147+
%seg:store(%this, %list_node:value)
148+
}
149+
; after: *node -> value
150+
; pop element after given, return it's value
151+
; for pop_first() set: after = this
152+
%method{ list_pop_after, 1, 0,
153+
; method: THIS = after
154+
%call(__list_detach_after_this__asserted)
155+
%seg:push_seg(%this) ; free THIS
156+
%call(free)
157+
%seg:load(%this, %list_node:value) ; return detached.value
158+
}
159+
; this, value -> (THIS)
160+
; insert new value at end of list
161+
%void_method{ list_insert_back, 2, 0,
162+
%list_node:new() ; new node after
163+
%call(__list_index_last)
164+
%call(__list_insert_after_this)
165+
%seg:load(%arg, 1) ; new.value = value
166+
%seg:store(%this, %list_node:value)
167+
}
168+
; this -> value
169+
; pop last element, return it's value
170+
%method{ list_pop_back, 1, 0,
171+
%foreach { ld 0 } ; nop ; SRC->before last
172+
%assert( lmne %minus1 ) ; -1 means empty
173+
%seg:point(%this, %src, 0) ; THIS = SRC
174+
%call(__list_detach_after_this__asserted)
175+
%seg:push_seg(%this); free THIS
176+
%call(free)
177+
%seg:load(%this, %list_node:value) ; return detached.value
178+
}
179+
180+
; this, other: *list ->
181+
; splice list elements from other to front of this
182+
; doesn't reallocate any nodes
183+
%void_method{ list_splice, 2, 1,
184+
%if { ; other is empty: do nothing
185+
%seg:movptr(%arg, 1)
186+
lmeq 0
187+
,
188+
%returnFunc(list_splice)
189+
}
190+
ldm ; other.first
191+
str 0
192+
%seg:move(%this, %head) ; tail = this.head, this.head = other.first
193+
swap
194+
%seg:store(%local, 0)
195+
%call(__list_index_last)
196+
%seg:load(%local, 0) ; last_spliced.next = tail
197+
%seg:store(%this, %list_node:next)
198+
}
199+
200+
; this ->
201+
%void_method{ list_print, 1, 0,
202+
outc '['
203+
%foreach {
204+
outum
205+
%if { %this_has_next(),
206+
outc ','
207+
outc ' '
208+
}
209+
}
210+
outc ']'
211+
}
212+
213+
%namespace impl {
214+
;; using procedures to save instructions, most IO happens via segment pointers
215+
216+
; (THIS)
217+
%proc{ __list_assert_this_has_next,
218+
%assert(
219+
%this_has_next()
220+
)
221+
}
222+
; (THIS) -> (THIS)
223+
; traverse list to last node
224+
%proc{ __list_index_last,
225+
%while { %this_has_next(),
226+
%advance_this()
227+
}
228+
}
229+
; (THIS), *node -> (THIS)
230+
; insert node after THIS, set THIS to inserted node
231+
%void_func{ __list_insert_after_this, 1, 0,
232+
%seg:push(%this, %list_node:next) ; tail = this.next
233+
%seg:load(%arg, 0) ; this.next = node
234+
%seg:store(%this, %list_node:next)
235+
%storer(%this) ; THIS = new
236+
%seg:pop(%this, %list_node:next) ; new.next = tail
237+
}
238+
; (THIS) -> (THIS)
239+
; detach single node after THIS, set THIS to detached
240+
; assert detachable node exists
241+
%proc{ __list_detach_after_this__asserted,
242+
%seg:push_seg(%this) ; save head
243+
%call(__list_assert_this_has_next)
244+
%advance_this() ; THIS = THIS.next
245+
%seg:load(%this, %list_node:next) ; detached.next = null
246+
str 0
247+
%stack:drop() ; head.next = detached.next
248+
movm
249+
strr
250+
}
251+
}
252+
253+
%struct:end()
254+
}

0 commit comments

Comments
 (0)