Fixed a lazySlot bug where lazy slots in different objects end up pointing to the...
[io/quag.git] / libs / iovm / source / IoSeq_immutable.c
blob73330b21316806c1af20aef195c00a0569beae4b
1 /*#io
2 Sequence ioDoc(
3 docCopyright("Steve Dekorte", 2002)
4 docLicense("BSD revised")
5 docObject("ImmutableSequence")
6 docDescription("""A Sequence is a container for a list of data elements. Immutable Sequences are also called "Symbols". """)
7 docCategory("Core")
8 */
10 #define _GNU_SOURCE // for NAN macro
11 #include "IoSeq.h"
12 #include "IoState.h"
13 #include "IoCFunction.h"
14 #include "IoObject.h"
15 #include "IoNumber.h"
16 #include "IoMessage.h"
17 #include "IoList.h"
18 #include <ctype.h>
19 #include <errno.h>
20 #include <math.h> // for NAN macro
21 #ifdef _MSC_VER
22 static double dNaN()
24 double a = 0, b = 0;
25 return a / b;
27 #define NAN dNaN()
28 #endif
29 #ifndef NAN
30 #define NAN 0.0/0.0
31 #endif
33 #define DATA(self) ((UArray *)IoObject_dataPointer(self))
36 IoObject *IoSeq_rawAsSymbol(IoSeq *self)
38 if (ISSYMBOL(self))
40 return self;
43 return IoState_symbolWithUArray_copy_(IOSTATE, DATA(self), 1);
46 IoObject *IoSeq_with(IoSeq *self, IoObject *locals, IoMessage *m)
48 /*#io
49 docSlot("with(aSequence, ...)",
50 "Returns a new Sequence which is the concatination of the arguments.
51 The returned sequence will have the same mutability status as the receiver.")
54 int n, argCount = IoMessage_argCount(m);
55 UArray *ba = UArray_clone(DATA(self));
57 for (n = 0; n < argCount; n ++)
59 IoSeq *v = IoMessage_locals_seqArgAt_(m, locals, n);
60 UArray_append_(ba, DATA(v));
63 if (ISSYMBOL(self))
65 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
68 return IoSeq_newWithUArray_copy_(IOSTATE, ba, 0);
71 IoObject *IoSeq_itemType(IoSeq *self, IoObject *locals, IoMessage *m)
73 /*#io
74 docSlot("itemType", "Returns machine type of elements. ")
77 return IOSYMBOL(CTYPE_name(UArray_itemType(DATA(self))));
80 IoObject *IoSeq_itemSize(IoSeq *self, IoObject *locals, IoMessage *m)
82 /*#io
83 docSlot("itemSize", "Returns number of bytes in each element. ")
86 return IONUMBER(UArray_itemSize(DATA(self)));
89 IoObject *IoSeq_encoding(IoSeq *self, IoObject *locals, IoMessage *m)
91 /*#io
92 docSlot("encoding", "Returns the encoding of the elements. ")
95 return IOSYMBOL(CENCODING_name(UArray_encoding(DATA(self))));
98 IoObject *IoSeq_asUTF8(IoSeq *self, IoObject *locals, IoMessage *m)
100 /*#io
101 docSlot("asUTF8", "Returns a new copy of the receiver converted to utf8 encoding. ")
104 return IoSeq_newWithUArray_copy_(IOSTATE, UArray_asUTF8(DATA(self)), 0);
107 IoObject *IoSeq_asUTF16(IoSeq *self, IoObject *locals, IoMessage *m)
109 /*#io
110 docSlot("asUTF16", "Returns a new copy of the receiver converted to utf16 encoding. ")
113 return IoSeq_newWithUArray_copy_(IOSTATE, UArray_asUTF16(DATA(self)), 0);
116 IoObject *IoSeq_asUTF32(IoSeq *self, IoObject *locals, IoMessage *m)
118 /*#io
119 docSlot("asUTF32", "Returns a new copy of the receiver converted to utf32 encoding. ")
122 return IoSeq_newWithUArray_copy_(IOSTATE, UArray_asUTF32(DATA(self)), 0);
125 IoObject *IoSeq_asFixedSizeType(IoSeq *self, IoObject *locals, IoMessage *m)
127 /*#io
128 docSlot("asFixedSizeType", "Returns a new sequence with the receiver encoded in the minimal fixed width text encoding that it's characters can fit into (either, ascii, utf8, utf16 or utf32). ")
131 IOASSERT(1 == 0, "IoSeq_asFixedSizeType unimplemented");
132 //return IoSeq_newWithUArray_copy_(IOSTATE, UArray_asFixedSizeType(DATA(self)), 0);
133 return self;
136 IoObject *IoSeq_asBinaryNumber(IoSeq *self, IoObject *locals, IoMessage *m)
138 /*#io
139 docSlot("asBinaryNumber",
140 "Returns a Number containing the first 8 bytes of the
141 receiver without casting them to a double.")
144 IoNumber *byteCount = IoMessage_locals_valueArgAt_(m, locals, 0);
145 size_t max = UArray_size(DATA(self));
146 int bc = sizeof(double);
147 double d = 0;
149 if (!ISNIL(byteCount))
151 bc = IoNumber_asInt(byteCount);
154 if (max < bc)
156 IoState_error_(IOSTATE, m, "requested first %i bytes, but Sequence only contians %i bytes", bc, max);
159 memcpy(&d, UArray_bytes(DATA(self)), bc);
160 return IONUMBER(d);
163 IoObject *IoSeq_asSymbol(IoSeq *self, IoObject *locals, IoMessage *m)
165 /*#io
166 docSlot("asSymbol",
167 "Returns a immutable Sequence (aka Symbol) version of the receiver.")
170 return IoSeq_rawAsSymbol(self);
173 IoObject *IoSeq_isSymbol(IoSeq *self, IoObject *locals, IoMessage *m)
175 /*#io
176 docSlot("isSymbol",
177 "Returns true if the receiver is a
178 immutable Sequence (aka, a Symbol) or false otherwise.")
181 return IOBOOL(self, ISSYMBOL(self));
184 IoObject *IoSeq_isMutable(IoSeq *self, IoObject *locals, IoMessage *m)
186 /*#io
187 docSlot("isMutable",
188 "Returns true if the receiver is a mutable Sequence or false otherwise.")
191 return IOBOOL(self, !ISSYMBOL(self));
195 IoObject *IoSeq_print(IoSeq *self, IoObject *locals, IoMessage *m)
197 /*#io
198 docSlot("print",
199 "Prints the receiver as a string. Returns self.")
202 IoState_justPrintba_(IOSTATE, DATA(self));
203 return self;
206 IoObject *IoSeq_linePrint(IoSeq *self, IoObject *locals, IoMessage *m)
208 /*#io
209 docSlot("linePrint",
210 "Prints the Sequence and a newline character.")
213 IoState_justPrintba_(IOSTATE, DATA(self));
214 IoState_justPrintln_(IOSTATE);
215 return self;
218 IoObject *IoSeq_isEmpty(IoSeq *self, IoObject *locals, IoMessage *m)
220 /*#io
221 docSlot("isEmpty", """Returns true if the size of the receiver is 0, false otherwise.""")
224 return IOBOOL(self, UArray_size(DATA(self)) == 0);
227 IoObject *IoSeq_isZero(IoSeq *self, IoObject *locals, IoMessage *m)
229 /*#io
230 docSlot("isZero", """Returns true if all elements are 0, false otherwise.""")
233 return IOBOOL(self, UArray_isZero(DATA(self)));
236 IoObject *IoSeq_size(IoSeq *self, IoObject *locals, IoMessage *m)
238 /*#io
239 docSlot("size", """Returns the length in bytes of the receiver. For example,
240 <pre>
241 "abc" size == 3
242 <pre>
243 """)
246 return IONUMBER(UArray_size(DATA(self)));
249 IoObject *IoSeq_at(IoSeq *self, IoObject *locals, IoMessage *m)
251 /*#io
252 docSlot("at(aNumber)",
253 "Returns a value at the index specified by aNumber.
254 Returns nil if the index is out of bounds.")
257 size_t i = IoMessage_locals_sizetArgAt_(m, locals, 0);
258 UArray *a = DATA(self);
260 //IOASSERT((i < UArray_size(DATA(self))), "index out of bounds");
261 if(i >= UArray_size(DATA(self))) return IONIL(self);
263 if(UArray_isFloatType(a))
265 return IONUMBER(UArray_doubleAt_(a, i));
267 else
269 return IONUMBER(UArray_longAt_(a, i));
273 IoObject *IoSeq_slice(IoSeq *self, IoObject *locals, IoMessage *m)
275 /*#io
276 docSlot("slice(startIndex, endIndex)",
277 "Returns a new string containing the subset of the
278 receiver from the startIndex to the endIndex. The endIndex argument
279 is optional. If not given, it is assumed to be the end of the string. ")
282 long fromIndex = IoMessage_locals_longArgAt_(m, locals, 0);
283 long last = UArray_size(DATA(self));
284 UArray *ba;
286 if (IoMessage_argCount(m) > 1)
288 last = IoMessage_locals_longArgAt_(m, locals, 1);
291 ba = UArray_slice(DATA(self), fromIndex, last);
293 if (ISSYMBOL(self))
295 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
298 return IoSeq_newWithUArray_copy_(IOSTATE, ba, 0);
301 IoObject *IoSeq_between(IoSeq *self, IoObject *locals, IoMessage *m)
303 /*#io
304 docSlot("between(aSequence, anotherSequence)",
305 "Returns a new Sequence containing the bytes between the
306 occurance of aSequence and anotherSequence in the receiver.")
309 long start = 0;
310 long end = 0;
311 IoSeq *fromSeq, *toSeq;
313 fromSeq = (IoSeq *)IoMessage_locals_valueArgAt_(m, locals, 0);
315 if (ISSEQ(fromSeq))
317 start = UArray_find_from_(DATA(self), DATA(fromSeq), 0) + IoSeq_rawSize(fromSeq);
319 if (start == -1)
321 start = 0;
324 else if (ISNIL(fromSeq))
326 start = 0;
328 else
330 IoState_error_(IOSTATE, m, "Nil or Sequence argument required for arg 0, not a %s",
331 IoObject_name((IoObject *)fromSeq));
334 toSeq = (IoSeq *)IoMessage_locals_valueArgAt_(m, locals, 1);
336 if (ISSEQ(toSeq))
338 end = UArray_find_from_(DATA(self), DATA(toSeq), start);
339 if (end == -1) start = UArray_size(DATA(self));
341 else if (ISNIL(toSeq))
343 end = UArray_size(DATA(self));
345 else
347 IoState_error_(IOSTATE, m, "Nil or Sequence argument required for arg 1, not a %s",
348 IoObject_name((IoObject *)toSeq));
352 UArray *ba = UArray_slice(DATA(self), start, end);
353 IoSeq *result = IoSeq_newWithUArray_copy_(IOSTATE, ba, 0);
354 return result;
358 // find ----------------------------------------------------------
360 IoObject *IoSeq_findSeqs(IoSeq *self, IoObject *locals, IoMessage *m)
362 /*#io
363 docSlot("findSeqs(listOfSequences, optionalStartIndex)",
364 "Returns a object with two slots - an "index" slot which contains the first occurrence of any of the sequences in listOfSequences found in the receiver after the startIndex, and a "match" slot, which contains a reference to the matching sequence from listOfSequences. If no startIndex is specified, the search starts at index 0. nil is returned if no occurences are found. ")
367 IoList *others = IoMessage_locals_listArgAt_(m, locals, 0);
368 List *delims = IoList_rawList(others);
369 long f = 0;
370 long firstIndex = -1;
371 int match = 0;
373 if (IoMessage_argCount(m) > 1)
375 f = IoMessage_locals_longArgAt_(m, locals, 1);
379 int index;
381 LIST_FOREACH(delims, i, s,
382 if (!ISSEQ((IoSeq *)s))
384 IoState_error_(IOSTATE, m, "requires Sequences as arguments, not %ss", IoObject_name((IoSeq *)s));
387 index = UArray_find_from_(DATA(self), DATA(((IoSeq *)s)), f);
389 if(index != -1 && (firstIndex == -1 || index < firstIndex)) { firstIndex = index; match = i; }
394 if (firstIndex == -1)
396 return IONIL(self);
398 else
400 IoObject *result = IoObject_new(IOSTATE);
401 IoObject_setSlot_to_(result, IOSYMBOL("index"), IONUMBER(firstIndex));
402 IoObject_setSlot_to_(result, IOSYMBOL("match"), (IoObject *)List_at_(delims, match));
403 return result;
408 IoObject *IoSeq_findSeq(IoSeq *self, IoObject *locals, IoMessage *m)
410 /*#io
411 docSlot("findSeq(aSequence, optionalStartIndex)",
412 "Returns a number with the first occurrence of aSequence in
413 the receiver after the startIndex. If no startIndex is specified,
414 the search starts at index 0.
415 nil is returned if no occurences are found. ")
418 IoSeq *otherSequence = IoMessage_locals_seqArgAt_(m, locals, 0);
419 long f = 0;
420 long index;
422 if (IoMessage_argCount(m) > 1)
424 f = IoMessage_locals_longArgAt_(m, locals, 1);
427 index = UArray_find_from_(DATA(self), DATA(otherSequence), f);
429 return (index == -1) ? IONIL(self) : IONUMBER(index);
432 IoObject *IoSeq_reverseFindSeq(IoSeq *self, IoObject *locals, IoMessage *m)
434 /*#io
435 docSlot("reverseFindSeq(aSequence, startIndex)",
436 "Returns a number with the first occurrence of aSequence in
437 the receiver before the startIndex. The startIndex argument is optional.
438 By default reverseFind starts at the end of the string. Nil is
439 returned if no occurrences are found. ")
442 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
443 long from = UArray_size(DATA(self));
444 long index;
446 if (IoMessage_argCount(m) > 1)
448 from = IoMessage_locals_intArgAt_(m, locals, 1);
451 index = UArray_rFind_from_(DATA(self), DATA(other), from);
453 if (index == -1)
455 return IONIL(self);
458 return IONUMBER((double)index);
461 IoObject *IoSeq_beginsWithSeq(IoSeq *self, IoObject *locals, IoMessage *m)
463 /*#io
464 docSlot("beginsWithSeq(aSequence)",
465 "Returns true if the receiver begins with aSequence, false otherwise.")
468 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
470 return IOBOOL(self, UArray_beginsWith_(DATA(self), DATA(other)));
473 IoObject *IoSeq_endsWithSeq(IoSeq *self, IoObject *locals, IoMessage *m)
475 /*#io
476 docSlot("endsWithSeq(aSequence)",
477 "Returns true if the receiver ends with aSequence, false otherwise. ")
480 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
481 return IOBOOL(self, UArray_endsWith_(DATA(self), DATA(other)));
484 IoObject *IoSeq_contains(IoSeq *self, IoObject *locals, IoMessage *m)
486 /*#io
487 docSlot("contains(aNumber)",
488 "Returns true if the receiver contains an element equal in value to aNumber, false otherwise. ")
491 // will make this more efficient when Numbers are Arrays
493 IoNumber *n = IoMessage_locals_numberArgAt_(m, locals, 0);
495 UArray tmp = IoNumber_asStackUArray(n);
496 return IOBOOL(self, UArray_contains_(DATA(self), &tmp));
499 IoObject *IoSeq_containsSeq(IoSeq *self, IoObject *locals, IoMessage *m)
501 /*#io
502 docSlot("containsSeq(aSequence)",
503 "Returns true if the receiver contains the substring
504 aSequence, false otherwise. ")
507 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
509 return IOBOOL(self, UArray_contains_(DATA(self), DATA(other)));
512 IoObject *IoSeq_containsAnyCaseSeq(IoSeq *self, IoObject *locals, IoMessage *m)
514 /*#io
515 docSlot("containsAnyCaseSeq(aSequence)",
516 "Returns true if the receiver contains the aSequence
517 regardless of casing, false otherwise. ")
520 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
521 return IOBOOL(self, UArray_containsAnyCase_(DATA(self), DATA(other)));
524 IoObject *IoSeq_isLowercase(IoSeq *self, IoObject *locals, IoMessage *m)
526 /*#io
527 docSlot("isLowercase",
528 "Returns self if all the characters in the string are lower case.")
531 return IOBOOL(self, UArray_isLowercase(DATA(self)));
534 IoObject *IoSeq_isUppercase(IoSeq *self, IoObject *locals, IoMessage *m)
536 /*#io
537 docSlot("isUppercase",
538 "Returns self if all the characters in the string are upper case.")
541 return IOBOOL(self, UArray_isUppercase(DATA(self)));
544 IoObject *IoSeq_isEqualAnyCase(IoSeq *self, IoObject *locals, IoMessage *m)
546 /*#io
547 docSlot("isEqualAnyCase(aSequence)",
548 "Returns true if aSequence is equal to the receiver
549 ignoring case differences, false otherwise.")
552 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
554 return IOBOOL(self, UArray_equalsAnyCase_(DATA(self), DATA(other)));
557 IoObject *IoSeq_asNumber(IoSeq *self, IoObject *locals, IoMessage *m)
559 /*#io
560 docSlot("asNumber",
561 "Returns the receiver converted to a number.
562 Initial whitespace is ignored.")
565 size_t size = UArray_size(DATA(self));
566 char *s = (char *)UArray_bytes(DATA(self));
567 char *endp;
568 double d = strtod(s, &endp);
570 if (size > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
572 return IONUMBER(IoSeq_rawAsDoubleFromHex(self));
575 if (errno == ERANGE || endp == s)
577 return IONUMBER(NAN);
580 return IONUMBER(d);
583 IoList *IoSeq_whiteSpaceStrings(IoSeq *self, IoObject *locals, IoMessage *m)
585 /*#io
586 docSlot("whiteSpaceStrings",
587 "Returns a List of strings. Each string contains a different
588 whitespace character.")
591 IoList *strings = IoList_new(IOSTATE);
592 IoList_rawAppend_(strings, IOSYMBOL(" "));
593 IoList_rawAppend_(strings, IOSYMBOL("\t"));
594 IoList_rawAppend_(strings, IOSYMBOL("\n"));
595 IoList_rawAppend_(strings, IOSYMBOL("\r"));
596 return strings;
599 // split ---------------------------------------------------------------------
601 IoList *IoSeq_stringListForArgs(IoSeq *self, IoObject *locals, IoMessage *m)
603 if (IoMessage_argCount(m) == 0)
605 return IoSeq_whiteSpaceStrings(self, locals, m);
607 return IoMessage_evaluatedArgs(m, locals, m);
610 List *IoSeq_byteArrayListForSeqList(IoSeq *self, IoObject *locals, IoMessage *m, IoList *seqs)
612 List *args = IoList_rawList(seqs);
613 List *list = List_new();
615 LIST_FOREACH(args, i, s,
616 if (!ISSEQ((IoSeq *)s))
618 List_free(list);
619 IoState_error_(IOSTATE, m,
620 "requires Sequences as arguments, not %ss",
621 IoObject_name((IoSeq *)s));
624 List_append_(list, DATA(((IoSeq *)s)));
627 return list;
630 IoObject *IoSeq_splitToFunction(IoSeq *self,
631 IoObject *locals,
632 IoMessage *m,
633 IoSplitFunction *func)
635 IoList *output = IoList_new(IOSTATE);
636 List *others = IoSeq_byteArrayListForSeqList(self, locals, m, IoSeq_stringListForArgs(self, locals, m));
637 int i;
639 for (i = 0; i < List_size(others); i ++)
641 if (UArray_size(List_at_(others, i)) == 0)
643 IoState_error_(IOSTATE, m, "empty string argument");
648 UArray othersArray = List_asStackAllocatedUArray(others);
649 UArray *results = UArray_split_(DATA(self), &othersArray);
651 for (i = 0; i < UArray_size(results); i ++)
653 UArray *ba = UArray_pointerAt_(results, i);
654 IoObject *item = (*func)(IOSTATE, ba, 0);
655 IoList_rawAppend_(output, item);
658 UArray_free(results);
661 List_free(others);
662 return output;
665 IoObject *IoSeq_split(IoSeq *self, IoObject *locals, IoMessage *m)
667 /*#io
668 docSlot("split(optionalArg1, optionalArg2, ...)", """
669 Returns a list containing the sub-sequences of the receiver divided by the given arguments.
670 If no arguments are given the sequence is split on white space.
671 Examples:
672 <pre>
673 "a b c d" split == list("a", "b", "c", "d")
674 "a*b*c*d" split("*") == list("a", "b", "c", "d")
675 "a*b|c,d" split("*", "|", ",") == list("a", "b", "c", "d")
676 "a b c d" split == list("a", "", "", "", "b", "", "", "c", "", "d")
677 </pre>
678 """)
681 return IoSeq_splitToFunction(self, locals, m, IoSeq_newWithUArray_copy_);
684 IoObject *IoSeq_splitAt(IoSeq *self, IoObject *locals, IoMessage *m)
686 int index = IoMessage_locals_intArgAt_(m, locals, 0);
687 IoList *splitSeqs = IoList_new(IOSTATE);
688 index = UArray_wrapPos_(DATA(self), index);
691 const char *s = UArray_asCString(DATA(self));
692 IoSeq *s1 = IoState_symbolWithCString_length_(IOSTATE, s, index);
693 IoSeq *s2 = IoState_symbolWithCString_(IOSTATE, s + index);
694 IoList_rawAppend_(splitSeqs, (IoObject *)s1);
695 IoList_rawAppend_(splitSeqs, (IoObject *)s2);
698 return splitSeqs;
701 /* --- base -------------------------------------------------------------- */
703 IoObject *IoSeq_fromBase(IoSeq *self, IoObject *locals, IoMessage *m)
705 /*#io
706 docSlot("fromBase(aNumber)",
707 "Returns a number with a base 10 representation of the receiver
708 converted from the specified base. Only base 2 through 32 are currently supported.")
711 int base = IoMessage_locals_intArgAt_(m, locals, 0);
712 char *s = CSTRING(self);
713 unsigned long r;
714 char *tail;
715 errno = 0;
716 r = strtoul(s, &tail, base);
718 if (errno == EINVAL)
720 errno = 0;
721 IoState_error_(IOSTATE, m, "conversion from base %i not supported", base);
723 else if (errno == ERANGE)
725 errno = 0;
726 IoState_error_(IOSTATE, m, "resulting value \"%s\" was out of range", s);
728 else if (*s == 0 || *tail != 0 || errno != 0)
730 errno = 0;
731 IoState_error_(IOSTATE, m, "conversion of \"%s\" to base %i failed", s, base);
734 return IONUMBER(r);
737 IoObject *IoSeq_toBase(IoSeq *self, IoObject *locals, IoMessage *m)
739 /*#io
740 docSlot("toBase(aNumber)",
741 "Returns a Sequence containing the receiver(which is
742 assumed to be a base 10 number) converted to the specified base.
743 Only base 8 and 16 are currently supported. ")
746 const char * const table = "0123456789abcdefghijklmnopqrstuvwxyz";
747 int base = IoMessage_locals_intArgAt_(m, locals, 0);
748 unsigned long n = (unsigned long) IoSeq_asDouble(self);
749 char buf[64], *ptr = buf + 64;
751 if (base < 2 || base > 36)
753 IoState_error_(IOSTATE, m, "conversion to base %i not supported", base);
756 /* Build the converted string backwards. */
757 *(--ptr) = '\0';
759 if (n == 0)
761 *(--ptr) = '0';
763 else
767 *(--ptr) = table[n % base];
769 while ((n /= base) != 0);
772 return IoSeq_newWithCString_(IOSTATE, ptr);
775 IoObject *IoSeq_each(IoSeq *self, IoObject *locals, IoMessage *m)
777 IoState *state = IOSTATE;
778 IoObject *result = IONIL(self);
779 IoMessage *doMessage = IoMessage_rawArgAt_(m, 0);
780 size_t i;
782 IoState_pushRetainPool(state);
784 for (i = 0; i < UArray_size(DATA(self)); i ++)
786 IoState_clearTopPool(IOSTATE);
788 if (UArray_isFloatType(DATA(self)))
790 result = IoMessage_locals_performOn_(doMessage, locals, IONUMBER(UArray_doubleAt_(DATA(self), i)));
792 else
794 result = IoMessage_locals_performOn_(doMessage, locals, IONUMBER(UArray_longAt_(DATA(self), i)));
797 if (IoState_handleStatus(IOSTATE))
799 goto done;
803 done:
804 IoState_popRetainPoolExceptFor_(state, result);
805 return result;
809 IoObject *IoSeq_foreach(IoSeq *self, IoObject *locals, IoMessage *m)
811 /*#io
812 docSlot("foreach(optionalIndex, value, message)",
813 """For each element, set index to the index of the
814 element and value the element value and execute message. Example:
815 <pre>
816 aSequence foreach(i, v, writeln("value at index ", i, " is ", v))
817 aSequence foreach(v, writeln("value ", v))
818 </pre>""")
821 IoObject *result = IONIL(self);
822 IoMessage *doMessage;
824 IoSymbol *indexSlotName;
825 IoSymbol *characterSlotName;
827 size_t i;
829 if (IoMessage_argCount(m) == 1)
831 return IoSeq_each(self, locals, m);
834 IoMessage_foreachArgs(m, self, &indexSlotName, &characterSlotName, &doMessage);
836 IoState_pushRetainPool(IOSTATE);
838 for (i = 0; i < UArray_size(DATA(self)); i ++)
840 IoState_clearTopPool(IOSTATE);
842 if (indexSlotName)
844 IoObject_setSlot_to_(locals, indexSlotName, IONUMBER(i));
847 if(UArray_isFloatType(DATA(self)))
849 IoObject_setSlot_to_(locals, characterSlotName, IONUMBER(UArray_doubleAt_(DATA(self), i)));
851 else
853 IoObject_setSlot_to_(locals, characterSlotName, IONUMBER(UArray_longAt_(DATA(self), i)));
855 result = IoMessage_locals_performOn_(doMessage, locals, locals);
857 if (IoState_handleStatus(IOSTATE))
859 goto done;
862 done:
863 IoState_popRetainPoolExceptFor_(IOSTATE, result);
864 return result;
867 IoObject *IoSeq_asMessage(IoSeq *self, IoObject *locals, IoMessage *m)
869 /*#io
870 docSlot("asMessage(optionalLabel)",
871 "Returns the compiled message object for the string.")
874 IoSymbol *label;
876 if (IoMessage_argCount(m) >= 1)
877 label = IoMessage_locals_symbolArgAt_(m, locals, 0);
878 else
879 label = IOSYMBOL("[asMessage]");
881 return IoMessage_newFromText_labelSymbol_(IOSTATE, CSTRING(self), label);
884 /*#io
885 docSlot("..(aSequence)", "Returns a copy of the receiver with aSequence appended to it. ")
888 IoObject *IoSeq_cloneAppendSeq(IoSeq *self, IoObject *locals, IoMessage *m)
890 IoObject *other = IoMessage_locals_valueArgAt_(m, locals, 0);
891 UArray *ba;
893 if (ISNUMBER(other))
895 other = IoNumber_justAsString((IoNumber *)other, (IoObject *)locals, m);
898 if (!ISSEQ(other))
900 IoState_error_(IOSTATE, m, "argument 0 to method '%s' must be a number or string, not a '%s'",
901 CSTRING(IoMessage_name(m)),
902 IoObject_name(other));
905 if (UArray_size(DATA(other)) == 0)
907 return self;
910 ba = UArray_clone(DATA(self));
911 UArray_append_(ba, DATA(other));
912 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
916 IoObject *IoSeq_asMutable(IoSeq *self, IoObject *locals, IoMessage *m)
918 /*#io
919 docSlot("asMutable",
920 "Returns a mutable copy of the receiver. ")
923 return IoSeq_rawMutableCopy(self);
926 /* --- case ------------------------------------------------ */
928 IoObject *IoSeq_asUppercase(IoSeq *self, IoObject *locals, IoMessage *m)
930 /*#io
931 docSlot("asUppercase",
932 "Returns a symbol containing the reveiver made uppercase. ")
935 UArray *ba = UArray_clone(DATA(self));
936 UArray_toupper(ba);
937 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
940 IoObject *IoSeq_asLowercase(IoSeq *self, IoObject *locals, IoMessage *m)
942 /*#io
943 docSlot("asLowercase",
944 "Returns a symbol containing the reveiver made Lowercase. ")
947 UArray *ba = UArray_clone(DATA(self));
948 UArray_tolower(ba);
949 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
952 /* --- path ------------------------------------------------ */
955 IoObject *IoSeq_lastPathComponent(IoSeq *self, IoObject *locals, IoMessage *m)
957 /*#io
958 docSlot("lastPathComponent",
959 "Returns a string containing the receiver clipped up
960 to the last path separator. ")
963 UArray *ba = UArray_lastPathComponent(DATA(self));
964 return IoSeq_newWithUArray_copy_(IOSTATE, ba, 0);
967 IoObject *IoSeq_pathExtension(IoSeq *self, IoObject *locals, IoMessage *m)
969 /*#io
970 docSlot("pathExtension",
971 "Returns a string containing the receiver clipped up to the last period. ")
974 UArray *path = UArray_pathExtension(DATA(self));
975 return IoState_symbolWithUArray_copy_(IOSTATE, path, 0);
978 IoObject *IoSeq_fileName(IoSeq *self, IoObject *locals, IoMessage *m)
980 /*#io
981 docSlot("fileName",
982 "Returns the last path component sans the path extension.")
985 UArray *path = UArray_fileName(DATA(self));
986 return IoState_symbolWithUArray_copy_(IOSTATE, path, 0);
989 IoObject *IoSeq_cloneAppendPath(IoSeq *self, IoObject *locals, IoMessage *m)
991 /*#io
992 docSlot("cloneAppendPath(aSequence)",
993 "Appends argument to a copy the receiver such that there is one
994 and only one path separator between the two and returns the result.")
997 IoSeq *component = IoMessage_locals_seqArgAt_(m, locals, 0);
998 UArray *ba = UArray_clone(DATA(self));
999 UArray_appendPath_(ba, DATA(component));
1000 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
1003 IoObject *IoSeq_pathComponent(IoSeq *self, IoObject *locals, IoMessage *m)
1005 /*#io
1006 docSlot("pathComponent",
1007 "Returns a slice of the receiver before the last path separator as a symbol. ")
1010 UArray *ba = UArray_clone(DATA(self));
1011 UArray_removeLastPathComponent(ba);
1012 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
1015 IoObject *IoSeq_beforeSeq(IoSeq *self, IoObject *locals, IoMessage *m)
1017 /*#io
1018 docSlot("beforeSeq(aSequence)",
1019 "Returns the slice of the receiver (as a Symbol) before
1020 aSequence or self if aSequence is not found.")
1023 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
1024 long pos = UArray_find_(DATA(self), DATA(other));
1026 if (pos != -1)
1028 UArray *ba = UArray_slice(DATA(self), 0, pos);
1030 if (ISSYMBOL(self))
1032 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
1034 else
1036 return IoSeq_newWithUArray_copy_(IOSTATE, ba, 0);
1040 if (ISSYMBOL(self))
1042 return self;
1045 return IOCLONE(self);
1048 IoObject *IoSeq_afterSeq(IoSeq *self, IoObject *locals, IoMessage *m)
1050 /*#io
1051 docSlot("afterSeq(aSequence)",
1052 "Returns the slice of the receiver (as a Symbol)
1053 after aSequence or Nil if aSequence is not found.
1054 If aSequence is empty, the receiver (or a copy of the
1055 receiver if it is mutable) is returned.")
1058 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
1059 long pos = UArray_find_(DATA(self), DATA(other));
1061 if (pos != -1)
1063 UArray *ba = UArray_slice(DATA(self), pos + UArray_size(DATA(other)), UArray_size(DATA(self)));
1065 if (ISSYMBOL(self))
1067 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
1069 else
1071 return IoSeq_newWithUArray_copy_(IOSTATE, ba, 0);
1075 return IONIL(self);
1078 IoObject *IoSeq_asCapitalized(IoSeq *self, IoObject *locals, IoMessage *m)
1080 /*#io
1081 docSlot("asCapitalized",
1082 "Returns a copy of the receiver with the first charater made uppercase.")
1085 /* need to fix for multi-byte characters */
1087 int firstChar = UArray_firstLong(DATA(self));
1088 int upperChar = toupper(firstChar);
1090 if (ISSYMBOL(self) && (firstChar == upperChar))
1092 return self;
1094 else
1096 UArray *ba = UArray_clone(DATA(self));
1097 UArray_at_putLong_(ba, 0, upperChar);
1099 if (ISSYMBOL(self))
1101 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
1104 return IoSeq_newWithUArray_copy_(IOSTATE, ba, 0);
1108 IoObject *IoSeq_occurancesOfSeq(IoSeq *self, IoObject *locals, IoMessage *m)
1110 /*#io
1111 docSlot("occurancesOfSeq(aSeq)", "Returns count of aSeq in the receiver.")
1114 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
1115 size_t count = UArray_count_(DATA(self), DATA(other));
1116 return IONUMBER(count);
1119 IoObject *IoSeq_interpolate(IoSeq *self, IoObject *locals, IoMessage *m)
1121 /*#io
1122 docSlot("interpolate(ctx)", "Returns immutable copy of self with interpolateInPlace(ctx) passed to the copy.")
1125 IoSeq *s = IoSeq_newWithUArray_copy_(IOSTATE, IoSeq_rawUArray(self), 1);
1126 IoSeq_interpolateInPlace(s, locals, m);
1127 return IoSeq_rawAsSymbol(s);
1130 IoObject *IoSeq_distanceTo(IoSeq *self, IoObject *locals, IoMessage *m)
1132 /*#io
1133 docSlot("distanceTo(aSeq)", "Returns a number with the square root of the sum of the square of the differences of the items between the sequences.")
1136 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
1137 double d;
1139 d = UArray_distanceTo_(DATA(self), DATA(other));
1140 return IONUMBER(d);
1143 IoObject *IoSeq_greaterThan_(IoSeq *self, IoObject *locals, IoMessage *m)
1145 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
1146 return IOBOOL(self, UArray_greaterThan_(DATA(self), DATA(other)));
1149 IoObject *IoSeq_lessThan_(IoSeq *self, IoObject *locals, IoMessage *m)
1151 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
1152 return IOBOOL(self, UArray_lessThan_(DATA(self), DATA(other)));
1155 IoObject *IoSeq_greaterThanOrEqualTo_(IoSeq *self, IoObject *locals, IoMessage *m)
1157 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
1158 return IOBOOL(self, UArray_greaterThanOrEqualTo_(DATA(self), DATA(other)));
1161 IoObject *IoSeq_lessThanOrEqualTo_(IoSeq *self, IoObject *locals, IoMessage *m)
1163 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
1164 return IOBOOL(self, UArray_lessThanOrEqualTo_(DATA(self), DATA(other)));
1167 // -----------------------------------------------------------
1169 #define ASSTRUCT(type) if (!strcmp(mt, #type)) \
1171 int typeSize = sizeof(type ## _t); \
1172 IOASSERT(offset + typeSize <= size, "not enough data for struct"); \
1173 v = IONUMBER(*(type ## _t *)(data + offset)); \
1174 offset += typeSize; \
1177 IoObject *IoSeq_asStruct(IoSeq *self, IoObject *locals, IoMessage *m)
1179 IoObject *st = IoObject_new(IOSTATE);
1180 const unsigned char *data = UArray_bytes(DATA(self));
1181 size_t size = UArray_sizeInBytes(DATA(self));
1182 size_t offset = 0;
1183 List *members = IoList_rawList(IoMessage_locals_listArgAt_(m, locals, 0));
1184 int memberIndex;
1186 IOASSERT(List_size(members) % 2 == 0, "members list must be even number");
1188 for (memberIndex = 0; memberIndex < List_size(members) / 2 && offset < size; memberIndex ++)
1190 IoSeq *memberType = List_at_(members, memberIndex*2);
1191 IoSeq *memberName = List_at_(members, memberIndex*2 + 1);
1192 char *mt;
1193 IoObject *v = NULL;
1195 IOASSERT(ISSEQ(memberType), "memberTypes must be strings");
1196 IOASSERT(ISSEQ(memberName), "memberNames must be strings");
1198 mt = CSTRING(memberType);
1200 ASSTRUCT(int8);
1201 ASSTRUCT(uint8);
1202 ASSTRUCT(int16);
1203 ASSTRUCT(uint16);
1204 ASSTRUCT(int32);
1205 ASSTRUCT(uint32);
1206 ASSTRUCT(int64);
1207 ASSTRUCT(uint64);
1208 ASSTRUCT(float32);
1209 ASSTRUCT(float64);
1211 IoObject_setSlot_to_(st, memberName, v);
1214 return st;
1217 #define WITHSTRUCT(type) if (!strcmp(mt, #type)) \
1219 int typeSize = sizeof(type ## _t); \
1220 *(type ## _t *)(data + offset) = CNUMBER(memberValue); \
1221 offset += typeSize; \
1222 continue; \
1225 IoObject *IoSeq_withStruct(IoSeq *self, IoObject *locals, IoMessage *m)
1227 List *members = IoList_rawList(IoMessage_locals_listArgAt_(m, locals, 0));
1228 int memberIndex;
1229 size_t maxSize = List_size(members) * 8;
1230 IoSeq *s = IoSeq_newWithData_length_(IOSTATE, malloc(maxSize), maxSize);
1231 unsigned char *data = IoSeq_rawBytes(s);
1232 size_t offset = 0;
1234 IOASSERT(List_size(members) % 2 == 0, "members list must be even number");
1236 for (memberIndex = 0; memberIndex < List_size(members) / 2 && offset < maxSize; memberIndex ++)
1238 IoSeq *memberType = List_at_(members, memberIndex*2);
1239 IoSeq *memberValue = List_at_(members, memberIndex*2 + 1);
1240 char *mt;
1241 IoObject *v = NULL;
1243 IOASSERT(ISSEQ(memberType), "memberTypes must be strings");
1244 IOASSERT(ISNUMBER(memberValue), "memberValues must be strings");
1246 mt = CSTRING(memberType);
1248 WITHSTRUCT(int8);
1249 WITHSTRUCT(uint8);
1250 WITHSTRUCT(int16);
1251 WITHSTRUCT(uint16);
1252 WITHSTRUCT(int32);
1253 WITHSTRUCT(uint32);
1254 WITHSTRUCT(int64);
1255 WITHSTRUCT(uint64);
1256 WITHSTRUCT(float32);
1257 WITHSTRUCT(float64);
1260 IoSeq_rawSetSize_(s, offset);
1262 return s;
1265 void IoSeq_addImmutableMethods(IoSeq *self)
1267 IoMethodTable methodTable[] = {
1268 {"itemType", IoSeq_itemType},
1269 {"itemSize", IoSeq_itemSize},
1270 {"encoding", IoSeq_encoding},
1271 {"asUTF8", IoSeq_asUTF8},
1272 {"asUTF16", IoSeq_asUTF16},
1273 {"asUTF32", IoSeq_asUTF32},
1274 {"asFixedSizeType", IoSeq_asFixedSizeType},
1276 {"asBinaryNumber", IoSeq_asBinaryNumber},
1277 {"isSymbol", IoSeq_isSymbol},
1278 {"isMutable", IoSeq_isMutable},
1279 {"asSymbol", IoSeq_asSymbol},
1280 {"asString", IoSeq_asSymbol},
1281 {"asNumber", IoSeq_asNumber},
1282 {"whiteSpaceStrings", IoSeq_whiteSpaceStrings},
1283 {"print", IoSeq_print},
1284 {"linePrint", IoSeq_linePrint},
1285 {"size", IoSeq_size},
1286 {"isZero", IoSeq_isZero},
1287 {"isEmpty", IoSeq_isEmpty},
1288 {"at", IoSeq_at},
1289 {"slice", IoSeq_slice},
1290 {"between", IoSeq_between},
1291 {"betweenSeq", IoSeq_between},
1292 {"findSeqs", IoSeq_findSeqs},
1293 {"findSeq", IoSeq_findSeq},
1294 {"reverseFindSeq", IoSeq_reverseFindSeq},
1295 {"beginsWithSeq", IoSeq_beginsWithSeq},
1296 {"endsWithSeq", IoSeq_endsWithSeq},
1297 {"split", IoSeq_split},
1298 {"contains", IoSeq_contains},
1299 {"containsSeq", IoSeq_containsSeq},
1300 {"containsAnyCaseSeq", IoSeq_containsAnyCaseSeq},
1301 {"isLowercase", IoSeq_isLowercase},
1302 {"isUppercase", IoSeq_isUppercase},
1303 {"isEqualAnyCase", IoSeq_isEqualAnyCase},
1304 {"splitAt", IoSeq_splitAt},
1305 {"fromBase", IoSeq_fromBase},
1306 {"toBase", IoSeq_toBase},
1307 {"foreach", IoSeq_foreach},
1308 {"asMessage", IoSeq_asMessage},
1309 {"..", IoSeq_cloneAppendSeq},
1310 {"cloneAppendSeq", IoSeq_cloneAppendSeq},
1311 {"asMutable", IoSeq_asMutable},
1312 {"asBuffer", IoSeq_asMutable},
1314 // paths
1316 {"fileName", IoSeq_fileName},
1317 {"pathExtension", IoSeq_pathExtension},
1318 {"lastPathComponent", IoSeq_lastPathComponent},
1319 {"cloneAppendPath", IoSeq_cloneAppendPath},
1320 {"pathComponent", IoSeq_pathComponent},
1322 {"afterSeq", IoSeq_afterSeq},
1323 {"beforeSeq", IoSeq_beforeSeq},
1325 {"asCapitalized", IoSeq_asCapitalized},
1326 {"asUppercase", IoSeq_asUppercase},
1327 {"asLowercase", IoSeq_asLowercase},
1328 {"with", IoSeq_with},
1329 {"occurancesOfSeq", IoSeq_occurancesOfSeq},
1330 {"interpolate", IoSeq_interpolate},
1331 {"distanceTo", IoSeq_distanceTo},
1333 {">", IoSeq_greaterThan_},
1334 {"<", IoSeq_lessThan_},
1335 {">=", IoSeq_greaterThanOrEqualTo_},
1336 {"<=", IoSeq_lessThanOrEqualTo_},
1338 {"asStruct", IoSeq_asStruct},
1339 {"withStruct", IoSeq_withStruct},
1340 {NULL, NULL},
1343 IoObject_addMethodTable_(self, methodTable);