Skip to content

Commit f86bea3

Browse files
STD list datastructure implementation
1 parent 4b94f30 commit f86bea3

File tree

1 file changed

+217
-0
lines changed

1 file changed

+217
-0
lines changed

std/ds/list.mx

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
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+
; TODO remove?
23+
; @list_node -> bool
24+
%macro has_next() {
25+
lmne 0
26+
}
27+
%macro mov_next() {
28+
movm
29+
}
30+
31+
%struct:end()
32+
}
33+
34+
;; singly linked list of list_nodes
35+
;; this parameter is pointer to list struct! (to list_node* this.head)
36+
%namespace list {
37+
%namespace helpers {
38+
; (this.head) -> (THIS)
39+
%macro head_to_this() {
40+
%seg:pointptr(%this, %this, %list:head)
41+
}
42+
; (THIS) -> bool (r)
43+
%macro this_has_next() {
44+
%seg:load(%this, %list_node:next)
45+
}
46+
; THIS = THIS.next
47+
%macro advance_this() {
48+
%seg:pointptr(%this, %this, %list_node:next)
49+
}
50+
}
51+
%using helpers
52+
53+
;; API
54+
%struct:begin()
55+
%struct:field(head, 1) ; *list_node
56+
57+
; @list
58+
; initialize to empty state
59+
%macro init() {
60+
str 0
61+
}
62+
; @list
63+
; free all list nodes
64+
%macro deinit() {
65+
; TODO proper free
66+
str 0
67+
}
68+
69+
; this -> value (THIS)
70+
; get value of first element
71+
%method{ list_first, 1, 0,
72+
%call(__list_assert_this_has_next)
73+
%head_to_this()
74+
%seg:load(%this, %list_node:value)
75+
}
76+
; this -> value (THIS)
77+
; get value of last element
78+
%method{ list_last, 1, 0,
79+
%call(__list_assert_this_has_next)
80+
%call(__list_index_last)
81+
%seg:load(%this, %list_node:value)
82+
}
83+
84+
; (THIS)
85+
; moves itrs: THIS - curr node, SRC - previous node
86+
; performs %instrs on each element
87+
; - value @h, current list_node at THIS
88+
; - element index at stack:top (readonly)
89+
; - after iteration: index in m (-1 if empty)
90+
%macro foreach(instrs) {
91+
%stack:push(%minus1)
92+
%while { %this_has_next(), ; THIS.next != null
93+
%seg:point(%src, %this, 0) ; SRC = THIS
94+
%advance_this() ; THIS = THIS.next
95+
%stack:top() ; index ++
96+
stra 1
97+
%seg:move(%this, %list_node:value)
98+
%instrs
99+
}
100+
%stack:drop()
101+
}
102+
103+
; this -> size
104+
%method{ list_size, 1, 0,
105+
%foreach { ld 0 }
106+
ldma 1
107+
}
108+
; this, index -> value (THIS)
109+
%method{ list_index, 2, 0,
110+
%foreach {
111+
%if { ; index == index
112+
%stack:top() ; loop idx
113+
%seg:arg(1, leqm)
114+
,
115+
%seg:load(%this, %list_node:value)
116+
%returnr(list_index)
117+
}
118+
}
119+
%error(2)
120+
}
121+
122+
; after: *node, value -> (THIS)
123+
; insert new value after node
124+
; for insert_first() set: after = this
125+
%void_method{ list_insert_after, 2, 0,
126+
; method: THIS = after
127+
%list_node:new() ; new node after
128+
%call(__list_insert_after_this)
129+
%seg:load(%arg, 1) ; new.value = value
130+
%seg:store(%this, %list_node:value)
131+
}
132+
; after: *node -> value
133+
; pop element after given, return it's value
134+
; for pop_first() set: after = this
135+
%method{ list_pop_after, 1, 0,
136+
; method: THIS = after
137+
%call(__list_detach_after_this__asserted)
138+
%seg:push_seg(%this) ; free THIS
139+
%call(free)
140+
%seg:load(%this, %list_node:value) ; return detached.value
141+
}
142+
; this, value -> (THIS)
143+
; insert new value at end of list
144+
%void_method{ list_insert_back, 2, 0,
145+
%list_node:new() ; new node after
146+
%call(__list_index_last)
147+
%call(__list_insert_after_this)
148+
%seg:load(%arg, 1) ; new.value = value
149+
%seg:store(%this, %list_node:value)
150+
}
151+
; this -> value
152+
; pop last element, return it's value
153+
%method{ list_pop_back, 1, 0,
154+
%foreach { ld 0 } ; nop ; SRC->before last
155+
%assert( lmne %minus1 ) ; -1 means empty
156+
%seg:point(%this, %src, 0) ; THIS = SRC
157+
%call(__list_detach_after_this__asserted)
158+
%seg:push_seg(%this); free THIS
159+
%call(free)
160+
%seg:load(%this, %list_node:value) ; return detached.value
161+
}
162+
163+
; this ->
164+
%void_method{ list_print, 1, 0,
165+
outc '['
166+
%foreach {
167+
outum
168+
%if { %this_has_next(),
169+
outc ','
170+
outc ' '
171+
}
172+
}
173+
outc ']'
174+
}
175+
176+
%namespace impl {
177+
;; using procedures to save instructions, most IO happens via segment pointers
178+
179+
; (THIS)
180+
%proc{ __list_assert_this_has_next,
181+
%assert(
182+
%this_has_next()
183+
)
184+
}
185+
; (THIS) -> (THIS)
186+
; traverse list to last node
187+
%proc{ __list_index_last,
188+
%while { %this_has_next(),
189+
%advance_this()
190+
}
191+
}
192+
; (THIS), *node -> (THIS)
193+
; insert node after THIS, set THIS to inserted node
194+
%void_func{ __list_insert_after_this, 1, 0,
195+
%seg:push(%this, %list_node:next) ; tail = this.next
196+
%seg:load(%arg, 0) ; this.next = node
197+
%seg:store(%this, %list_node:next)
198+
%storer(%this) ; THIS = new
199+
%seg:pop(%this, %list_node:next) ; new.next = tail
200+
}
201+
; (THIS) -> (THIS)
202+
; detach single node after THIS, set THIS to detached
203+
; assert detachable node exists
204+
%proc{ __list_detach_after_this__asserted,
205+
%call(__list_assert_this_has_next)
206+
%seg:push_seg(%this) ; save head
207+
%advance_this() ; THIS = THIS.next
208+
%seg:load(%this, %list_node:next) ; detached.next = null
209+
str 0
210+
%stack:drop() ; head.next = detached.next
211+
movm
212+
strr
213+
}
214+
}
215+
216+
%struct:end()
217+
}

0 commit comments

Comments
 (0)