1 #include "ml_map.h"
2 #include "minilang.h"
3 #include "ml_macros.h"
4 #include "ml_iterfns.h"
5 #include <string.h>
6
7 ML_TYPE(MLMapT, (MLIteratableT), "map",
8 // A map of key-value pairs.
9 // Keys can be of any type supporting hashing and comparison.
10 // Insert order is preserved.
11 );
12
ml_map_node_deref(ml_map_node_t * Node)13 static ml_value_t *ml_map_node_deref(ml_map_node_t *Node) {
14 return Node->Value;
15 }
16
ml_map_node_assign(ml_map_node_t * Node,ml_value_t * Value)17 static ml_value_t *ml_map_node_assign(ml_map_node_t *Node, ml_value_t *Value) {
18 return (Node->Value = Value);
19 }
20
ml_map_node_call(ml_state_t * Caller,ml_map_node_t * Node,int Count,ml_value_t ** Args)21 static void ml_map_node_call(ml_state_t *Caller, ml_map_node_t *Node, int Count, ml_value_t **Args) {
22 return ml_call(Caller, Node->Value, Count, Args);
23 }
24
25 ML_TYPE(MLMapNodeT, (), "map-node",
26 // A node in a :mini:`map`.
27 // Dereferencing a :mini:`mapnode` returns the corresponding value from the :mini:`map`.
28 // Assigning to a :mini:`mapnode` updates the corresponding value in the :mini:`map`.
29 .deref = (void *)ml_map_node_deref,
30 .assign = (void *)ml_map_node_assign,
31 .call = (void *)ml_map_node_call
32 );
33
ml_map()34 ml_value_t *ml_map() {
35 ml_map_t *Map = new(ml_map_t);
36 Map->Type = MLMapT;
37 return (ml_value_t *)Map;
38 }
39
ML_METHOD(MLMapT)40 ML_METHOD(MLMapT) {
41 return ml_map();
42 }
43
ML_METHODV(MLMapT,MLNamesT)44 ML_METHODV(MLMapT, MLNamesT) {
45 ml_value_t *Map = ml_map();
46 ml_value_t **Values = Args + 1;
47 ML_NAMES_FOREACH(Args[0], Iter) ml_map_insert(Map, Iter->Value, *Values++);
48 return Map;
49 }
50
51 static void map_iterate(ml_iter_state_t *State, ml_value_t *Value);
52
map_iter_value(ml_iter_state_t * State,ml_value_t * Value)53 static void map_iter_value(ml_iter_state_t *State, ml_value_t *Value) {
54 Value = ml_deref(Value);
55 if (ml_is_error(Value)) ML_CONTINUE(State->Base.Caller, Value);
56 ml_map_insert(State->Values[0], State->Values[1], Value);
57 State->Base.run = (void *)map_iterate;
58 return ml_iter_next((ml_state_t *)State, State->Iter);
59 }
60
map_iter_key(ml_iter_state_t * State,ml_value_t * Value)61 static void map_iter_key(ml_iter_state_t *State, ml_value_t *Value) {
62 Value = ml_deref(Value);
63 if (ml_is_error(Value)) ML_CONTINUE(State->Base.Caller, Value);
64 if (Value == MLNil) Value = ml_integer(ml_map_size(State->Values[0]) + 1);
65 State->Values[1] = Value;
66 State->Base.run = (void *)map_iter_value;
67 return ml_iter_value((ml_state_t *)State, State->Iter);
68 }
69
map_iterate(ml_iter_state_t * State,ml_value_t * Value)70 static void map_iterate(ml_iter_state_t *State, ml_value_t *Value) {
71 if (ml_is_error(Value)) ML_CONTINUE(State->Base.Caller, Value);
72 if (Value == MLNil) ML_CONTINUE(State->Base.Caller, State->Values[0]);
73 State->Base.run = (void *)map_iter_key;
74 return ml_iter_key((ml_state_t *)State, State->Iter = Value);
75 }
76
ML_METHOD(MLIterCount,MLMapT)77 ML_METHOD(MLIterCount, MLMapT) {
78 //!internal
79 return ml_integer(ml_map_size(Args[0]));
80 }
81
ML_METHODVX(MLMapT,MLIteratableT)82 ML_METHODVX(MLMapT, MLIteratableT) {
83 //<Iteratable
84 //>map
85 // Returns a map of all the key and value pairs produced by :mini:`Iteratable`.
86 ml_iter_state_t *State = xnew(ml_iter_state_t, 2, ml_value_t *);
87 State->Base.Caller = Caller;
88 State->Base.run = (void *)map_iterate;
89 State->Base.Context = Caller->Context;
90 State->Values[0] = ml_map();
91 return ml_iterate((ml_state_t *)State, ml_chained(Count, Args));
92 }
93
94 extern ml_value_t *CompareMethod;
95
ml_map_find_node(ml_map_t * Map,ml_value_t * Key)96 static ml_map_node_t *ml_map_find_node(ml_map_t *Map, ml_value_t *Key) {
97 ml_map_node_t *Node = Map->Root;
98 long Hash = ml_typeof(Key)->hash(Key, NULL);
99 while (Node) {
100 int Compare;
101 if (Hash < Node->Hash) {
102 Compare = -1;
103 } else if (Hash > Node->Hash) {
104 Compare = 1;
105 } else {
106 ml_value_t *Args[2] = {Key, Node->Key};
107 ml_value_t *Result = ml_simple_call(CompareMethod, 2, Args);
108 if (ml_is_error(Result)) return NULL;
109 Compare = ml_integer_value(Result);
110 }
111 if (!Compare) {
112 return Node;
113 } else {
114 Node = Compare < 0 ? Node->Left : Node->Right;
115 }
116 }
117 return NULL;
118 }
119
ml_map_search(ml_value_t * Map0,ml_value_t * Key)120 ml_value_t *ml_map_search(ml_value_t *Map0, ml_value_t *Key) {
121 ml_map_node_t *Node = ml_map_find_node((ml_map_t *)Map0, Key);
122 return Node ? Node->Value : MLNil;
123 }
124
ml_map_search0(ml_value_t * Map0,ml_value_t * Key)125 ml_value_t *ml_map_search0(ml_value_t *Map0, ml_value_t *Key) {
126 ml_map_node_t *Node = ml_map_find_node((ml_map_t *)Map0, Key);
127 return Node ? Node->Value : NULL;
128 }
129
ml_map_balance(ml_map_node_t * Node)130 static int ml_map_balance(ml_map_node_t *Node) {
131 int Delta = 0;
132 if (Node->Left) Delta = Node->Left->Depth;
133 if (Node->Right) Delta -= Node->Right->Depth;
134 return Delta;
135 }
136
ml_map_update_depth(ml_map_node_t * Node)137 static void ml_map_update_depth(ml_map_node_t *Node) {
138 int Depth = 0;
139 if (Node->Left) Depth = Node->Left->Depth;
140 if (Node->Right && Depth < Node->Right->Depth) Depth = Node->Right->Depth;
141 Node->Depth = Depth + 1;
142 }
143
ml_map_rotate_left(ml_map_node_t ** Slot)144 static void ml_map_rotate_left(ml_map_node_t **Slot) {
145 ml_map_node_t *Ch = Slot[0]->Right;
146 Slot[0]->Right = Slot[0]->Right->Left;
147 Ch->Left = Slot[0];
148 ml_map_update_depth(Slot[0]);
149 Slot[0] = Ch;
150 ml_map_update_depth(Slot[0]);
151 }
152
ml_map_rotate_right(ml_map_node_t ** Slot)153 static void ml_map_rotate_right(ml_map_node_t **Slot) {
154 ml_map_node_t *Ch = Slot[0]->Left;
155 Slot[0]->Left = Slot[0]->Left->Right;
156 Ch->Right = Slot[0];
157 ml_map_update_depth(Slot[0]);
158 Slot[0] = Ch;
159 ml_map_update_depth(Slot[0]);
160 }
161
ml_map_rebalance(ml_map_node_t ** Slot)162 static void ml_map_rebalance(ml_map_node_t **Slot) {
163 int Delta = ml_map_balance(Slot[0]);
164 if (Delta == 2) {
165 if (ml_map_balance(Slot[0]->Left) < 0) ml_map_rotate_left(&Slot[0]->Left);
166 ml_map_rotate_right(Slot);
167 } else if (Delta == -2) {
168 if (ml_map_balance(Slot[0]->Right) > 0) ml_map_rotate_right(&Slot[0]->Right);
169 ml_map_rotate_left(Slot);
170 }
171 }
172
ml_map_node(ml_map_t * Map,ml_map_node_t ** Slot,long Hash,ml_value_t * Key)173 static ml_map_node_t *ml_map_node(ml_map_t *Map, ml_map_node_t **Slot, long Hash, ml_value_t *Key) {
174 if (!Slot[0]) {
175 ++Map->Size;
176 ml_map_node_t *Node = Slot[0] = new(ml_map_node_t);
177 Node->Type = MLMapNodeT;
178 ml_map_node_t *Prev = Map->Tail;
179 if (Prev) {
180 Prev->Next = Node;
181 Node->Prev = Prev;
182 } else {
183 Map->Head = Node;
184 }
185 Map->Tail = Node;
186 Node->Depth = 1;
187 Node->Hash = Hash;
188 Node->Key = Key;
189 return Node;
190 }
191 int Compare;
192 if (Hash < Slot[0]->Hash) {
193 Compare = -1;
194 } else if (Hash > Slot[0]->Hash) {
195 Compare = 1;
196 } else {
197 ml_value_t *Args[2] = {Key, Slot[0]->Key};
198 ml_value_t *Result = ml_simple_call(CompareMethod, 2, Args);
199 Compare = ml_integer_value(Result);
200 }
201 if (!Compare) {
202 return Slot[0];
203 } else {
204 ml_map_node_t *Node = ml_map_node(Map, Compare < 0 ? &Slot[0]->Left : &Slot[0]->Right, Hash, Key);
205 ml_map_rebalance(Slot);
206 ml_map_update_depth(Slot[0]);
207 return Node;
208 }
209 }
210
ml_map_slot(ml_value_t * Map0,ml_value_t * Key)211 ml_map_node_t *ml_map_slot(ml_value_t *Map0, ml_value_t *Key) {
212 ml_map_t *Map = (ml_map_t *)Map0;
213 return ml_map_node(Map, &Map->Root, ml_typeof(Key)->hash(Key, NULL), Key);
214 }
215
ml_map_insert(ml_value_t * Map0,ml_value_t * Key,ml_value_t * Value)216 ml_value_t *ml_map_insert(ml_value_t *Map0, ml_value_t *Key, ml_value_t *Value) {
217 ml_map_t *Map = (ml_map_t *)Map0;
218 ml_map_node_t *Node = ml_map_node(Map, &Map->Root, ml_typeof(Key)->hash(Key, NULL), Key);
219 ml_value_t *Old = Node->Value ?: MLNil;
220 Node->Value = Value;
221 #ifdef ML_GENERICS
222 if (Map->Size == 1 && Map->Type == MLMapT) {
223 ml_type_t *Types[] = {MLMapT, ml_typeof(Key), ml_typeof(Value)};
224 Map->Type = ml_generic_type(3, Types);
225 } else if (Map->Type->Type == MLGenericTypeT) {
226 ml_type_t *KeyType = ml_generic_type_args(Map->Type)[1];
227 ml_type_t *ValueType = ml_generic_type_args(Map->Type)[2];
228 if (KeyType != ml_typeof(Key) || ValueType != ml_typeof(Value)) {
229 ml_type_t *KeyType2 = ml_type_max(KeyType, ml_typeof(Key));
230 ml_type_t *ValueType2 = ml_type_max(ValueType, ml_typeof(Value));
231 if (KeyType != KeyType2 || ValueType != ValueType2) {
232 ml_type_t *Types[] = {MLMapT, KeyType2, ValueType2};
233 Map->Type = ml_generic_type(3, Types);
234 }
235 }
236 }
237 #endif
238 return Old;
239 }
240
ml_map_remove_depth_helper(ml_map_node_t * Node)241 static void ml_map_remove_depth_helper(ml_map_node_t *Node) {
242 if (Node) {
243 ml_map_remove_depth_helper(Node->Right);
244 ml_map_update_depth(Node);
245 }
246 }
247
ml_map_remove_internal(ml_map_t * Map,ml_map_node_t ** Slot,long Hash,ml_value_t * Key)248 static ml_value_t *ml_map_remove_internal(ml_map_t *Map, ml_map_node_t **Slot, long Hash, ml_value_t *Key) {
249 if (!Slot[0]) return MLNil;
250 ml_map_node_t *Node = Slot[0];
251 int Compare;
252 if (Hash < Node->Hash) {
253 Compare = -1;
254 } else if (Hash > Node->Hash) {
255 Compare = 1;
256 } else {
257 ml_value_t *Args[2] = {Key, Node->Key};
258 ml_value_t *Result = ml_simple_call(CompareMethod, 2, Args);
259 Compare = ml_integer_value(Result);
260 }
261 ml_value_t *Removed = MLNil;
262 if (!Compare) {
263 --Map->Size;
264 Removed = Node->Value;
265 if (Node->Prev) Node->Prev->Next = Node->Next; else Map->Head = Node->Next;
266 if (Node->Next) Node->Next->Prev = Node->Prev; else Map->Tail = Node->Prev;
267 if (Node->Left && Node->Right) {
268 ml_map_node_t **Y = &Node->Left;
269 while (Y[0]->Right) Y = &Y[0]->Right;
270 ml_map_node_t *Node2 = Y[0];
271 Y[0] = Node2->Left;
272 Node2->Left = Node->Left;
273 Node2->Right = Node->Right;
274 Slot[0] = Node2;
275 ml_map_remove_depth_helper(Node2->Left);
276 } else if (Node->Left) {
277 Slot[0] = Node->Left;
278 } else if (Node->Right) {
279 Slot[0] = Node->Right;
280 } else {
281 Slot[0] = 0;
282 }
283 } else {
284 Removed = ml_map_remove_internal(Map, Compare < 0 ? &Node->Left : &Node->Right, Hash, Key);
285 }
286 if (Slot[0]) {
287 ml_map_update_depth(Slot[0]);
288 ml_map_rebalance(Slot);
289 }
290 return Removed;
291 }
292
ml_map_delete(ml_value_t * Map0,ml_value_t * Key)293 ml_value_t *ml_map_delete(ml_value_t *Map0, ml_value_t *Key) {
294 ml_map_t *Map = (ml_map_t *)Map0;
295 return ml_map_remove_internal(Map, &Map->Root, ml_typeof(Key)->hash(Key, NULL), Key);
296 }
297
ml_map_foreach(ml_value_t * Value,void * Data,int (* callback)(ml_value_t *,ml_value_t *,void *))298 int ml_map_foreach(ml_value_t *Value, void *Data, int (*callback)(ml_value_t *, ml_value_t *, void *)) {
299 ml_map_t *Map = (ml_map_t *)Value;
300 for (ml_map_node_t *Node = Map->Head; Node; Node = Node->Next) {
301 if (callback(Node->Key, Node->Value, Data)) return 1;
302 }
303 return 0;
304 }
305
306 ML_METHOD("size", MLMapT) {
307 //<Map
308 //>integer
309 // Returns the number of entries in :mini:`Map`.
310 ml_map_t *Map = (ml_map_t *)Args[0];
311 return ml_integer(Map->Size);
312 }
313
314 ML_METHOD("count", MLMapT) {
315 //<Map
316 //>integer
317 // Returns the number of entries in :mini:`Map`.
318 ml_map_t *Map = (ml_map_t *)Args[0];
319 return ml_integer(Map->Size);
320 }
321
ml_map_index_deref(ml_map_node_t * Index)322 static ml_value_t *ml_map_index_deref(ml_map_node_t *Index) {
323 return MLNil;
324 }
325
326
ml_map_insert_node(ml_map_t * Map,ml_map_node_t ** Slot,long Hash,ml_map_node_t * Index)327 static ml_map_node_t *ml_map_insert_node(ml_map_t *Map, ml_map_node_t **Slot, long Hash, ml_map_node_t *Index) {
328 if (!Slot[0]) {
329 ++Map->Size;
330 ml_map_node_t *Node = Slot[0] = Index;
331 Node->Type = MLMapNodeT;
332 ml_map_node_t *Prev = Map->Tail;
333 if (Prev) {
334 Prev->Next = Node;
335 Node->Prev = Prev;
336 } else {
337 Map->Head = Node;
338 }
339 Map->Tail = Node;
340 Node->Depth = 1;
341 Node->Hash = Hash;
342 return Node;
343 }
344 int Compare;
345 if (Hash < Slot[0]->Hash) {
346 Compare = -1;
347 } else if (Hash > Slot[0]->Hash) {
348 Compare = 1;
349 } else {
350 ml_value_t *Args[2] = {Index->Key, Slot[0]->Key};
351 ml_value_t *Result = ml_simple_call(CompareMethod, 2, Args);
352 Compare = ml_integer_value(Result);
353 }
354 if (!Compare) {
355 return Slot[0];
356 } else {
357 ml_map_node_t *Node = ml_map_insert_node(Map, Compare < 0 ? &Slot[0]->Left : &Slot[0]->Right, Hash, Index);
358 ml_map_rebalance(Slot);
359 ml_map_update_depth(Slot[0]);
360 return Node;
361 }
362 }
363
ml_map_index_assign(ml_map_node_t * Index,ml_value_t * Value)364 static ml_value_t *ml_map_index_assign(ml_map_node_t *Index, ml_value_t *Value) {
365 ml_map_t *Map = (ml_map_t *)Index->Value;
366 ml_map_node_t *Node = ml_map_insert_node(Map, &Map->Root, ml_typeof(Index->Key)->hash(Index->Key, NULL), Index);
367 return Node->Value = Value;
368 }
369
ml_map_index_call(ml_state_t * Caller,ml_map_node_t * Index,int Count,ml_value_t ** Args)370 static void ml_map_index_call(ml_state_t *Caller, ml_map_node_t *Index, int Count, ml_value_t **Args) {
371 return ml_call(Caller, MLNil, Count, Args);
372 }
373
374 ML_TYPE(MLMapIndexT, (), "map-index",
375 //!internal
376 .deref = (void *)ml_map_index_deref,
377 .assign = (void *)ml_map_index_assign,
378 .call = (void *)ml_map_index_call
379 );
380
381 ML_METHOD("[]", MLMapT, MLAnyT) {
382 //<Map
383 //<Key
384 //>mapnode
385 // Returns the node corresponding to :mini:`Key` in :mini:`Map`. If :mini:`Key` is not in :mini:`Map` then a new floating node is returned with value :mini:`nil`. This node will insert :mini:`Key` into :mini:`Map` if assigned.
386 ml_map_node_t *Node = ml_map_find_node((ml_map_t *)Args[0], Args[1]);
387 if (!Node) {
388 Node = new(ml_map_node_t);
389 Node->Type = MLMapIndexT;
390 Node->Value = Args[0];
391 Node->Key = Args[1];
392 }
393 return (ml_value_t *)Node;
394 }
395
396 typedef struct {
397 ml_state_t Base;
398 ml_value_t *Key;
399 ml_map_node_t *Node;
400 } ml_ref_state_t;
401
ml_node_state_run(ml_ref_state_t * State,ml_value_t * Value)402 static void ml_node_state_run(ml_ref_state_t *State, ml_value_t *Value) {
403 if (ml_is_error(Value)) {
404 ML_CONTINUE(State->Base.Caller, Value);
405 } else {
406 State->Node->Value = Value;
407 ML_CONTINUE(State->Base.Caller, State->Node);
408 }
409 }
410
411 ML_METHODX("[]", MLMapT, MLAnyT, MLFunctionT) {
412 //<Map
413 //<Key
414 //<Default
415 //>mapnode
416 // Returns the node corresponding to :mini:`Key` in :mini:`Map`. If :mini:`Key` is not in :mini:`Map` then :mini:`Default(Key)` is called and the result inserted into :mini:`Map`.
417 ml_map_t *Map = (ml_map_t *)Args[0];
418 ml_value_t *Key = Args[1];
419 ml_map_node_t *Node = ml_map_node(Map, &Map->Root, ml_typeof(Key)->hash(Key, NULL), Key);
420 if (!Node->Value) {
421 Node->Value = MLNil;
422 ml_ref_state_t *State = new(ml_ref_state_t);
423 State->Base.Caller = Caller;
424 State->Base.Context = Caller->Context;
425 State->Base.run = (void *)ml_node_state_run;
426 State->Key = Key;
427 State->Node = Node;
428 ml_value_t *Function = Args[2];
429 return ml_call(State, Function, 1, &State->Key);
430 } else {
431 ML_RETURN(Node);
432 }
433 }
434
435 ML_METHOD("::", MLMapT, MLStringT) {
436 //<Map
437 //<Key
438 //>mapnode
439 // Same as :mini:`Map[Key]`. This method allows maps to be used as modules.
440 ml_map_node_t *Node = ml_map_find_node((ml_map_t *)Args[0], Args[1]);
441 if (!Node) {
442 Node = new(ml_map_node_t);
443 Node->Type = MLMapIndexT;
444 Node->Value = Args[0];
445 Node->Key = Args[1];
446 }
447 return (ml_value_t *)Node;
448 }
449
450 ML_METHOD("insert", MLMapT, MLAnyT, MLAnyT) {
451 //<Map
452 //<Key
453 //<Value
454 //>any | nil
455 // Inserts :mini:`Key` into :mini:`Map` with corresponding value :mini:`Value`.
456 // Returns the previous value associated with :mini:`Key` if any, otherwise :mini:`nil`.
457 ml_value_t *Map = (ml_value_t *)Args[0];
458 ml_value_t *Key = Args[1];
459 ml_value_t *Value = Args[2];
460 return ml_map_insert(Map, Key, Value);
461 }
462
463 ML_METHOD("delete", MLMapT, MLAnyT) {
464 //<Map
465 //<Key
466 //>any | nil
467 // Removes :mini:`Key` from :mini:`Map` and returns the corresponding value if any, otherwise :mini:`nil`.
468 ml_value_t *Map = (ml_value_t *)Args[0];
469 ml_value_t *Key = Args[1];
470 return ml_map_delete(Map, Key);
471 }
472
ml_map_fn(void * Data,int Count,ml_value_t ** Args)473 ml_value_t *ml_map_fn(void *Data, int Count, ml_value_t **Args) {
474 ml_map_t *Map = new(ml_map_t);
475 Map->Type = MLMapT;
476 for (int I = 0; I < Count; I += 2) ml_map_insert((ml_value_t *)Map, Args[I], Args[I + 1]);
477 return (ml_value_t *)Map;
478 }
479
480 ML_METHOD("missing", MLMapT, MLAnyT) {
481 //<Map
482 //<Key
483 //>any | nil
484 // Inserts :mini:`Key` into :mini:`Map` with corresponding value :mini:`Value`.
485 // Returns the previous value associated with :mini:`Key` if any, otherwise :mini:`nil`.
486 ml_map_t *Map = (ml_map_t *)Args[0];
487 ml_value_t *Key = Args[1];
488 ml_map_node_t *Node = ml_map_node(Map, &Map->Root, ml_typeof(Key)->hash(Key, NULL), Key);
489 if (!Node->Value) return Node->Value = MLSome;
490 return MLNil;
491 }
492
493 ML_METHOD("append", MLStringBufferT, MLMapT) {
494 ml_stringbuffer_t *Buffer = (ml_stringbuffer_t *)Args[0];
495 ml_stringbuffer_add(Buffer, "{", 1);
496 ml_map_t *Map = (ml_map_t *)Args[1];
497 ml_map_node_t *Node = Map->Head;
498 if (Node) {
499 ml_stringbuffer_append(Buffer, Node->Key);
500 if (Node->Value != MLSome) {
501 ml_stringbuffer_add(Buffer, " is ", 4);
502 ml_stringbuffer_append(Buffer, Node->Value);
503 }
504 while ((Node = Node->Next)) {
505 ml_stringbuffer_add(Buffer, ", ", 2);
506 ml_stringbuffer_append(Buffer, Node->Key);
507 if (Node->Value != MLSome) {
508 ml_stringbuffer_add(Buffer, " is ", 4);
509 ml_stringbuffer_append(Buffer, Node->Value);
510 }
511 }
512 }
513 ml_stringbuffer_add(Buffer, "}", 1);
514 return (ml_value_t *)Buffer;
515 }
516
ML_TYPED_FN(ml_iter_next,MLMapNodeT,ml_state_t * Caller,ml_map_node_t * Node)517 static void ML_TYPED_FN(ml_iter_next, MLMapNodeT, ml_state_t *Caller, ml_map_node_t *Node) {
518 ML_RETURN((ml_value_t *)Node->Next ?: MLNil);
519 }
520
ML_TYPED_FN(ml_iter_key,MLMapNodeT,ml_state_t * Caller,ml_map_node_t * Node)521 static void ML_TYPED_FN(ml_iter_key, MLMapNodeT, ml_state_t *Caller, ml_map_node_t *Node) {
522 ML_RETURN(Node->Key);
523 }
524
ML_TYPED_FN(ml_iter_value,MLMapNodeT,ml_state_t * Caller,ml_map_node_t * Node)525 static void ML_TYPED_FN(ml_iter_value, MLMapNodeT, ml_state_t *Caller, ml_map_node_t *Node) {
526 ML_RETURN(Node);
527 }
528
ML_TYPED_FN(ml_iterate,MLMapT,ml_state_t * Caller,ml_map_t * Map)529 static void ML_TYPED_FN(ml_iterate, MLMapT, ml_state_t *Caller, ml_map_t *Map) {
530 ML_RETURN((ml_value_t *)Map->Head ?: MLNil);
531 }
532
533 ML_METHOD("+", MLMapT, MLMapT) {
534 //<Map/1
535 //<Map/2
536 //>map
537 // Returns a new map combining the entries of :mini:`Map/1` and :mini:`Map/2`.
538 // If the same key is in both :mini:`Map/1` and :mini:`Map/2` then the corresponding value from :mini:`Map/2` is chosen.
539 ml_value_t *Map = ml_map();
540 ML_MAP_FOREACH(Args[0], Node) ml_map_insert(Map, Node->Key, Node->Value);
541 ML_MAP_FOREACH(Args[1], Node) ml_map_insert(Map, Node->Key, Node->Value);
542 return Map;
543 }
544
545 ML_METHOD("*", MLMapT, MLMapT) {
546 //<Map/1
547 //<Map/2
548 //>map
549 // Returns a new map containing the entries of :mini:`Map/1` which are also in :mini:`Map/2`. The values are chosen from :mini:`Map/1`.
550 ml_value_t *Map = ml_map();
ML_MAP_FOREACH(Args[0],Node)551 ML_MAP_FOREACH(Args[0], Node) {
552 if (ml_map_search0(Args[1], Node->Key)) ml_map_insert(Map, Node->Key, Node->Value);
553 }
554 return Map;
555 }
556
557 ML_METHOD("/", MLMapT, MLMapT) {
558 //<Map/1
559 //<Map/2
560 //>map
561 // Returns a new map containing the entries of :mini:`Map/1` which are not in :mini:`Map/2`.
562 ml_value_t *Map = ml_map();
ML_MAP_FOREACH(Args[0],Node)563 ML_MAP_FOREACH(Args[0], Node) {
564 if (!ml_map_search0(Args[1], Node->Key)) ml_map_insert(Map, Node->Key, Node->Value);
565 }
566 return Map;
567 }
568
569 typedef struct ml_map_stringer_t {
570 const char *Seperator, *Equals;
571 ml_stringbuffer_t Buffer[1];
572 int SeperatorLength, EqualsLength, First;
573 ml_value_t *Error;
574 } ml_map_stringer_t;
575
ml_map_stringer(ml_value_t * Key,ml_value_t * Value,ml_map_stringer_t * Stringer)576 static int ml_map_stringer(ml_value_t *Key, ml_value_t *Value, ml_map_stringer_t *Stringer) {
577 if (!Stringer->First) {
578 ml_stringbuffer_add(Stringer->Buffer, Stringer->Seperator, Stringer->SeperatorLength);
579 } else {
580 Stringer->First = 0;
581 }
582 Stringer->Error = ml_stringbuffer_append(Stringer->Buffer, Key);
583 if (ml_is_error(Stringer->Error)) return 1;
584 ml_stringbuffer_add(Stringer->Buffer, Stringer->Equals, Stringer->EqualsLength);
585 Stringer->Error = ml_stringbuffer_append(Stringer->Buffer, Value);
586 if (ml_is_error(Stringer->Error)) return 1;
587 return 0;
588 }
589
ML_METHOD(MLStringT,MLMapT)590 ML_METHOD(MLStringT, MLMapT) {
591 //<Map
592 //>string
593 // Returns a string containing the entries of :mini:`Map` surrounded by :mini:`"{"`, :mini:`"}"` with :mini:`" is "` between keys and values and :mini:`", "` between entries.
594 ml_map_stringer_t Stringer[1] = {{
595 ", ", " is ",
596 {ML_STRINGBUFFER_INIT},
597 2, 4,
598 1
599 }};
600 ml_stringbuffer_add(Stringer->Buffer, "{", 1);
601 if (ml_map_foreach(Args[0], Stringer, (void *)ml_map_stringer)) {
602 return Stringer->Error;
603 }
604 ml_stringbuffer_add(Stringer->Buffer, "}", 1);
605 return ml_string(ml_stringbuffer_get(Stringer->Buffer), -1);
606 }
607
ML_METHOD(MLStringT,MLMapT,MLStringT,MLStringT)608 ML_METHOD(MLStringT, MLMapT, MLStringT, MLStringT) {
609 //<Map
610 //<Seperator
611 //<Connector
612 //>string
613 // Returns a string containing the entries of :mini:`Map` with :mini:`Connector` between keys and values and :mini:`Seperator` between entries.
614 ml_map_stringer_t Stringer[1] = {{
615 ml_string_value(Args[1]), ml_string_value(Args[2]),
616 {ML_STRINGBUFFER_INIT},
617 ml_string_length(Args[1]), ml_string_length(Args[2]),
618 1
619 }};
620 if (ml_map_foreach(Args[0], Stringer, (void *)ml_map_stringer)) return Stringer->Error;
621 return ml_stringbuffer_value(Stringer->Buffer);
622 }
623
624 typedef struct {
625 ml_state_t Base;
626 ml_map_t *Map;
627 ml_value_t *Compare;
628 ml_value_t *Args[4];
629 ml_map_node_t *Head, *Tail;
630 ml_map_node_t *P, *Q;
631 int Count, Size;
632 int InSize, NMerges;
633 int PSize, QSize;
634 } ml_map_sort_state_t;
635
ml_map_sort_state_run(ml_map_sort_state_t * State,ml_value_t * Result)636 static void ml_map_sort_state_run(ml_map_sort_state_t *State, ml_value_t *Result) {
637 if (Result) goto resume;
638 for (;;) {
639 State->P = State->Head;
640 State->Tail = State->Head = NULL;
641 State->NMerges = 0;
642 while (State->P) {
643 State->NMerges++;
644 State->Q = State->P;
645 State->PSize = 0;
646 for (int I = 0; I < State->InSize; I++) {
647 State->PSize++;
648 State->Q = State->Q->Next;
649 if (!State->Q) break;
650 }
651 State->QSize = State->InSize;
652 while (State->PSize > 0 || (State->QSize > 0 && State->Q)) {
653 ml_map_node_t *E;
654 if (State->PSize == 0) {
655 E = State->Q; State->Q = State->Q->Next; State->QSize--;
656 } else if (State->QSize == 0 || !State->Q) {
657 E = State->P; State->P = State->P->Next; State->PSize--;
658 } else {
659 State->Args[0] = State->P->Key;
660 State->Args[1] = State->Q->Key;
661 State->Args[2] = State->P->Value;
662 State->Args[3] = State->Q->Value;
663 return ml_call((ml_state_t *)State, State->Compare, State->Count, State->Args);
664 resume:
665 if (ml_is_error(Result)) {
666 ml_map_node_t *Node = State->P, *Next;
667 if (State->Tail) {
668 State->Tail->Next = Node;
669 } else {
670 State->Head = Node;
671 }
672 Node->Prev = State->Tail;
673 for (int Size = State->PSize; --Size > 0;) {
674 Next = Node->Next; Next->Prev = Node; Node = Next;
675 }
676 Next = State->Q;
677 Node->Next = Next;
678 Next->Prev = Node;
679 Node = Next;
680 while (Node->Next) {
681 Next = Node->Next; Next->Prev = Node; Node = Next;
682 }
683 Node->Next = NULL;
684 State->Tail = Node;
685 goto finished;
686 } else if (Result == MLNil) {
687 E = State->Q; State->Q = State->Q->Next; State->QSize--;
688 } else {
689 E = State->P; State->P = State->P->Next; State->PSize--;
690 }
691 }
692 if (State->Tail) {
693 State->Tail->Next = E;
694 } else {
695 State->Head = E;
696 }
697 E->Prev = State->Tail;
698 State->Tail = E;
699 }
700 State->P = State->Q;
701 }
702 State->Tail->Next = 0;
703 if (State->NMerges <= 1) {
704 Result = (ml_value_t *)State->Map;
705 goto finished;
706 }
707 State->InSize *= 2;
708 }
709 finished:
710 State->Map->Head = State->Head;
711 State->Map->Tail = State->Tail;
712 State->Map->Size = State->Size;
713 ML_CONTINUE(State->Base.Caller, Result);
714 }
715
716 extern ml_value_t *LessMethod;
717
718 ML_METHODX("sort", MLMapT) {
719 //<Map
720 //>Map
721 if (!ml_map_size(Args[0])) ML_RETURN(Args[0]);
722 ml_map_sort_state_t *State = new(ml_map_sort_state_t);
723 State->Base.Caller = Caller;
724 State->Base.Context = Caller->Context;
725 State->Base.run = (ml_state_fn)ml_map_sort_state_run;
726 ml_map_t *Map = (ml_map_t *)Args[0];
727 State->Map = Map;
728 State->Count = 2;
729 State->Compare = LessMethod;
730 State->Head = State->Map->Head;
731 State->Size = Map->Size;
732 State->InSize = 1;
733 // TODO: Improve ml_map_sort_state_run so that List is still valid during sort
734 Map->Head = Map->Tail = NULL;
735 Map->Size = 0;
736 return ml_map_sort_state_run(State, NULL);
737 }
738
739 ML_METHODX("sort", MLMapT, MLFunctionT) {
740 //<Map
741 //<Compare
742 //>Map
743 if (!ml_map_size(Args[0])) ML_RETURN(Args[0]);
744 ml_map_sort_state_t *State = new(ml_map_sort_state_t);
745 State->Base.Caller = Caller;
746 State->Base.Context = Caller->Context;
747 State->Base.run = (ml_state_fn)ml_map_sort_state_run;
748 ml_map_t *Map = (ml_map_t *)Args[0];
749 State->Map = Map;
750 State->Count = 2;
751 State->Compare = Args[1];
752 State->Head = State->Map->Head;
753 State->Size = Map->Size;
754 State->InSize = 1;
755 // TODO: Improve ml_map_sort_state_run so that List is still valid during sort
756 Map->Head = Map->Tail = NULL;
757 Map->Size = 0;
758 return ml_map_sort_state_run(State, NULL);
759 }
760
761 ML_METHODX("sort2", MLMapT, MLFunctionT) {
762 //<Map
763 //<Compare
764 //>Map
765 if (!ml_map_size(Args[0])) ML_RETURN(Args[0]);
766 ml_map_sort_state_t *State = new(ml_map_sort_state_t);
767 State->Base.Caller = Caller;
768 State->Base.Context = Caller->Context;
769 State->Base.run = (ml_state_fn)ml_map_sort_state_run;
770 ml_map_t *Map = (ml_map_t *)Args[0];
771 State->Map = Map;
772 State->Count = 4;
773 State->Compare = Args[1];
774 State->Head = State->Map->Head;
775 State->Size = Map->Size;
776 State->InSize = 1;
777 // TODO: Improve ml_map_sort_state_run so that List is still valid during sort
778 Map->Head = Map->Tail = NULL;
779 Map->Size = 0;
780 return ml_map_sort_state_run(State, NULL);
781 }
782
ml_map_init()783 void ml_map_init() {
784 #include "ml_map_init.c"
785 #ifdef ML_GENERICS
786 ml_type_add_rule(MLMapT, MLIteratableT, ML_TYPE_ARG(1), ML_TYPE_ARG(2), NULL);
787 #endif
788 }
789