root/trunk/minid/arraylib.d

Revision 412, 19.7 kB (checked in by JarrettBillingsley, 1 month ago)

MiniD's int type is now defined as a 64-bit integer. Also the beginnings of the Vector object are in the base library.

Line 
1 /******************************************************************************
2 License:
3 Copyright (c) 2008 Jarrett Billingsley
4
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the
7 use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it freely,
11 subject to the following restrictions:
12
13     1. The origin of this software must not be misrepresented; you must not
14     claim that you wrote the original software. If you use this software in a
15     product, an acknowledgment in the product documentation would be
16     appreciated but is not required.
17
18     2. Altered source versions must be plainly marked as such, and must not
19     be misrepresented as being the original software.
20
21     3. This notice may not be removed or altered from any source distribution.
22 ******************************************************************************/
23
24 module minid.arraylib;
25
26 import tango.core.Array;
27 import tango.core.Tuple;
28 import tango.math.Math;
29
30 import minid.array;
31 import minid.ex;
32 import minid.interpreter;
33 import minid.types;
34
35 struct ArrayLib
36 {
37 static:
38     public void init(MDThread* t)
39     {
40         pushGlobal(t, "modules");
41         field(t, -1, "customLoaders");
42
43         newFunction(t, function uword(MDThread* t, uword numParams)
44         {
45             newFunction(t, &array_new, "new");     newGlobal(t, "new");
46             newFunction(t, &range,     "range");   newGlobal(t, "range");
47
48             newNamespace(t, "array");
49                 newFunction(t, &sort,      "sort");       fielda(t, -2, "sort");
50                 newFunction(t, &reverse,   "reverse");    fielda(t, -2, "reverse");
51                 newFunction(t, &array_dup, "dup");        fielda(t, -2, "dup");
52
53                     newFunction(t, &iterator,        "iterator");
54                     newFunction(t, &iteratorReverse, "iteratorReverse");
55                 newFunction(t, &opApply,   "opApply", 2); fielda(t, -2, "opApply");
56
57                 newFunction(t, &expand,    "expand");     fielda(t, -2, "expand");
58                 newFunction(t, &toString,  "toString");   fielda(t, -2, "toString");
59                 newFunction(t, &apply,     "apply");      fielda(t, -2, "apply");
60                 newFunction(t, &map,       "map");        fielda(t, -2, "map");
61                 newFunction(t, &reduce,    "reduce");     fielda(t, -2, "reduce");
62                 newFunction(t, &each,      "each");       fielda(t, -2, "each");
63                 newFunction(t, &filter,    "filter");     fielda(t, -2, "filter");
64                 newFunction(t, &find,      "find");       fielda(t, -2, "find");
65                 newFunction(t, &findIf,    "findIf");     fielda(t, -2, "findIf");
66                 newFunction(t, &bsearch,   "bsearch");    fielda(t, -2, "bsearch");
67                 newFunction(t, &array_pop, "pop");        fielda(t, -2, "pop");
68                 newFunction(t, &set,       "set");        fielda(t, -2, "set");
69                 newFunction(t, &min,       "min");        fielda(t, -2, "min");
70                 newFunction(t, &max,       "max");        fielda(t, -2, "max");
71                 newFunction(t, &extreme,   "extreme");    fielda(t, -2, "extreme");
72                 newFunction(t, &any,       "any");        fielda(t, -2, "any");
73                 newFunction(t, &all,       "all");        fielda(t, -2, "all");
74                 newFunction(t, &fill,      "fill");       fielda(t, -2, "fill");
75                 newFunction(t, &append,    "append");     fielda(t, -2, "append");
76
77                     newTable(t);
78                 newFunction(t, &flatten,   "flatten", 1); fielda(t, -2, "flatten");
79
80                 newFunction(t, &makeHeap,  "makeHeap");   fielda(t, -2, "makeHeap");
81                 newFunction(t, &pushHeap,  "pushHeap");   fielda(t, -2, "pushHeap");
82                 newFunction(t, &popHeap,   "popHeap");    fielda(t, -2, "popHeap");
83                 newFunction(t, &sortHeap,  "sortHeap");   fielda(t, -2, "sortHeap");
84                 newFunction(t, &count,     "count");      fielda(t, -2, "count");
85                 newFunction(t, &countIf,   "countIf");    fielda(t, -2, "countIf");
86             setTypeMT(t, MDValue.Type.Array);
87
88             return 0;
89         }, "array");
90
91         fielda(t, -2, "array");
92         importModule(t, "array");
93         pop(t, 3);
94     }
95
96     uword array_new(MDThread* t, uword numParams)
97     {
98         auto length = checkIntParam(t, 1);
99
100         if(length < 0 || length > uword.max)
101             throwException(t, "Invalid length: {}", length);
102
103         newArray(t, cast(uword)length);
104
105         if(numParams > 1)
106         {
107             dup(t, 2);
108             fillArray(t, -2);
109         }
110
111         return 1;
112     }
113
114     uword range(MDThread* t, uword numParams)
115     {
116         auto v1 = checkIntParam(t, 1);
117         mdint v2;
118         mdint step = 1;
119
120         if(numParams == 1)
121         {
122             v2 = v1;
123             v1 = 0;
124         }
125         else if(numParams == 2)
126             v2 = checkIntParam(t, 2);
127         else
128         {
129             v2 = checkIntParam(t, 2);
130             step = checkIntParam(t, 3);
131         }
132
133         if(step <= 0)
134             throwException(t, "Step may not be negative or 0");
135
136         mdint range = abs(v2 - v1);
137         mdint size = range / step;
138
139         if((range % step) != 0)
140             size++;
141            
142         if(size > uword.max)
143             throwException(t, "Array is too big");
144
145         newArray(t, cast(uword)size);
146         auto a = getArray(t, -1);
147
148         auto val = v1;
149
150         if(v2 < v1)
151         {
152             for(uword i = 0; val > v2; i++, val -= step)
153                 a.slice[i] = val;
154         }
155         else
156         {
157             for(uword i = 0; val < v2; i++, val += step)
158                 a.slice[i] = val;
159         }
160
161         return 1;
162     }
163
164     uword sort(MDThread* t, uword numParams)
165     {
166         checkParam(t, 0, MDValue.Type.Array);
167
168         bool delegate(MDValue, MDValue) pred;
169
170         if(numParams > 0)
171         {
172             if(isString(t, 1) && getString(t, 1) == "reverse")
173             {
174                 pred = (MDValue v1, MDValue v2)
175                 {
176                     push(t, v1);
177                     push(t, v2);
178                     auto v = cmp(t, -2, -1);
179                     pop(t, 2);
180                     return v > 0;
181                 };
182             }
183             else
184             {
185                 checkParam(t, 1, MDValue.Type.Function);
186                 dup(t);
187
188                 pred = (MDValue v1, MDValue v2)
189                 {
190                     auto reg = dup(t);
191                     pushNull(t);
192                     push(t, v1);
193                     push(t, v2);
194                     rawCall(t, reg, 1);
195                    
196                     if(!isInt(t, -1))
197                     {
198                         pushTypeString(t, -1);
199                         throwException(t, "comparison function expected to return 'int', not '{}'", getString(t, -1));
200                     }
201                    
202                     auto v = getInt(t, -1);
203                     pop(t);
204                     return v < 0;
205                 };
206             }
207         }
208         else
209         {
210             pred = (MDValue v1, MDValue v2)
211             {
212                 push(t, v1);
213                 push(t, v2);
214                 auto v = cmp(t, -2, -1);
215                 pop(t, 2);
216                 return v < 0;
217             };
218         }
219        
220         .sort(getArray(t, 0).slice, pred);
221         dup(t, 0);
222         return 1;
223     }
224
225     uword reverse(MDThread* t, uword numParams)
226     {
227         checkParam(t, 0, MDValue.Type.Array);
228         getArray(t, 0).slice.reverse;
229         dup(t, 0);
230         return 1;
231     }
232
233     uword array_dup(MDThread* t, uword numParams)
234     {
235         checkParam(t, 0, MDValue.Type.Array);
236         newArray(t, cast(uword)len(t, 0)); // this should be fine?  since arrays can't be longer than uword.max
237         getArray(t, -1).slice[] = getArray(t, 0).slice[];
238         return 1;
239     }
240
241     uword iterator(MDThread* t, uword numParams)
242     {
243         checkParam(t, 0, MDValue.Type.Array);
244         auto index = checkIntParam(t, 1) + 1;
245
246         if(index >= len(t, 0))
247             return 0;
248
249         pushInt(t, index);
250         dup(t);
251         idx(t, 0);
252
253         return 2;
254     }
255
256     uword iteratorReverse(MDThread* t, uword numParams)
257     {
258         checkParam(t, 0, MDValue.Type.Array);
259         auto index = checkIntParam(t, 1) - 1;
260
261         if(index < 0)
262             return 0;
263
264         pushInt(t, index);
265         dup(t);
266         idx(t, 0);
267
268         return 2;
269     }
270
271     uword opApply(MDThread* t, uword numParams)
272     {
273         checkParam(t, 0, MDValue.Type.Array);
274
275         if(optStringParam(t, 1, "") == "reverse")
276         {
277             getUpval(t, 1);
278             dup(t, 0);
279             pushLen(t, 0);
280         }
281         else
282         {
283             getUpval(t, 0);
284             dup(t, 0);
285             pushInt(t, -1);
286         }
287
288         return 3;
289     }
290
291     uword expand(MDThread* t, uword numParams)
292     {
293         checkParam(t, 0, MDValue.Type.Array);
294         auto a = getArray(t, 0);
295
296         foreach(ref val; a.slice)
297             push(t, val);
298
299         return a.slice.length;
300     }
301
302     uword toString(MDThread* t, uword numParams)
303     {
304         auto buf = StrBuffer(t);
305         buf.addChar('[');
306    
307         auto length = len(t, 0);
308    
309         for(uword i = 0; i < length; i++)
310         {
311             pushInt(t, i);
312             idx(t, 0);
313    
314             if(isString(t, -1))
315             {
316                 // this is GC-safe since the string is stored in the array
317                 auto s = getString(t, -1);
318                 pop(t);
319                 buf.addChar('"');
320                 buf.addString(s);
321                 buf.addChar('"');
322             }
323             else if(isChar(t, -1))
324             {
325                 auto c = getChar(t, -1);
326                 pop(t);
327                 buf.addChar('\'');
328                 buf.addChar(c);
329                 buf.addChar('\'');
330             }
331             else
332             {
333                 pushToString(t, -1, true);
334                 insertAndPop(t, -2);
335                 buf.addTop();
336             }
337    
338             if(i < length - 1)
339                 buf.addString(", ");
340         }
341    
342         buf.addChar(']');
343         buf.finish();
344    
345         return 1;
346     }
347
348     uword apply(MDThread* t, uword numParams)
349     {
350         checkParam(t, 0, MDValue.Type.Array);
351         checkParam(t, 1, MDValue.Type.Function);
352
353         auto data = getArray(t, 0).slice;
354
355         foreach(i, ref v; data)
356         {
357             auto reg = dup(t, 1);
358             dup(t, 0);
359             push(t, v);
360             rawCall(t, reg, 1);
361             idxai(t, 0, i, true);
362         }
363
364         dup(t, 0);
365         return 1;
366     }
367
368     uword map(MDThread* t, uword numParams)
369     {
370         checkParam(t, 0, MDValue.Type.Array);
371         checkParam(t, 1, MDValue.Type.Function);
372         auto newArr = newArray(t, cast(uword)len(t, 0));
373         auto data = getArray(t, -1).slice;
374
375         foreach(i, ref v; getArray(t, 0).slice)
376         {
377             auto reg = dup(t, 1);
378             dup(t, 0);
379             push(t, v);
380             rawCall(t, reg, 1);
381             idxai(t, newArr, i, true);
382         }
383
384         return 1;
385     }
386
387     uword reduce(MDThread* t, uword numParams)
388     {
389         checkParam(t, 0, MDValue.Type.Array);
390         checkParam(t, 1, MDValue.Type.Function);
391         uword length = cast(uword)len(t, 0);
392
393         if(length == 0)
394         {
395             pushNull(t);
396             return 1;
397         }
398
399         idxi(t, 0, 0, true);
400
401         for(uword i = 1; i < length; i++)
402         {
403             dup(t, 1);
404             insert(t, -2);
405             pushNull(t);
406             insert(t, -2);
407             idxi(t, 0, i, true);
408             rawCall(t, -4, 1);
409         }
410
411         return 1;
412     }
413
414     uword each(MDThread* t, uword numParams)
415     {
416         checkParam(t, 0, MDValue.Type.Array);
417         checkParam(t, 1, MDValue.Type.Function);
418
419         foreach(i, ref v; getArray(t, 0).slice)
420         {
421             dup(t, 1);
422             dup(t, 0);
423             pushInt(t, i);
424             push(t, v);
425             rawCall(t, -4, 1);
426            
427             if(isBool(t, -1) && getBool(t, -1) == false)
428                 break;
429         }
430        
431         dup(t, 0);
432         return 1;
433     }
434
435     uword filter(MDThread* t, uword numParams)
436     {
437         checkParam(t, 0, MDValue.Type.Array);
438         checkParam(t, 1, MDValue.Type.Function);
439
440         auto newLen = len(t, 0) / 2;
441         auto retArray = newArray(t, cast(uword)newLen);
442         uword retIdx = 0;
443
444         foreach(i, ref v; getArray(t, 0).slice)
445         {
446             dup(t, 1);
447             dup(t, 0);
448             pushInt(t, i);
449             push(t, v);
450             rawCall(t, -4, 1);
451            
452             if(!isBool(t, -1))
453             {
454                 pushTypeString(t, -1);
455                 throwException(t, "filter function expected to return 'bool', not '{}'", getString(t, -1));
456             }
457
458             if(getBool(t, -1))
459             {
460                 if(retIdx >= newLen)
461                 {
462                     newLen += 10;
463                     pushInt(t, newLen);
464                     lena(t, retArray);
465                 }
466
467                 push(t, v);
468                 idxai(t, retArray, retIdx, true);
469                 retIdx++;
470             }
471            
472             pop(t);
473         }
474  
475         pushInt(t, retIdx);
476         lena(t, retArray);
477         dup(t, retArray);
478         return 1;
479     }
480
481     uword find(MDThread* t, uword numParams)
482     {
483         checkParam(t, 0, MDValue.Type.Array);
484         checkAnyParam(t, 1);
485
486         foreach(i, ref v; getArray(t, 0).slice)
487         {
488             push(t, v);
489
490             if(type(t, 1) == v.type && cmp(t, 1, -1) == 0)
491             {
492                 pushInt(t, i);
493                 return 1;
494             }
495         }
496
497         pushLen(t, 0);
498         return 1;
499     }
500
501     uword findIf(MDThread* t, uword numParams)
502     {
503         checkParam(t, 0, MDValue.Type.Array);
504         checkParam(t, 1, MDValue.Type.Function);
505        
506         foreach(i, ref v; getArray(t, 0).slice)
507         {
508             auto reg = dup(t, 1);
509             pushNull(t);
510             push(t, v);
511             rawCall(t, reg, 1);
512            
513             if(!isBool(t, -1))
514             {
515                 pushTypeString(t, -1);
516                 throwException(t, "find function expected to return 'bool', not '{}'", getString(t, -1));
517             }
518            
519             if(getBool(t, -1))
520             {
521                 pushInt(t, i);
522                 return 1;
523             }
524
525             pop(