Updating built in Io code to use += instead of x = x + y
[io/quag.git] / libs / iovm / source / IoSeq_immutable.c
blob09ddae96f24314706f2fe35bcc7977cb65479106
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_asOSPath(IoSeq *self, IoObject *locals, IoMessage *m)
1017 return IoSeq_newSymbolWithUArray_copy_(IOSTATE, UArray_asOSPath(IoSeq_rawUArray(self)), 0);
1020 IoObject *IoSeq_asIoPath(IoSeq *self, IoObject *locals, IoMessage *m)
1022 return IoSeq_newSymbolWithUArray_copy_(IOSTATE, UArray_asUnixPath(IoSeq_rawUArray(self)), 0);
1025 // occurances
1027 IoObject *IoSeq_beforeSeq(IoSeq *self, IoObject *locals, IoMessage *m)
1029 /*#io
1030 docSlot("beforeSeq(aSequence)",
1031 "Returns the slice of the receiver (as a Symbol) before
1032 aSequence or self if aSequence is not found.")
1035 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
1036 long pos = UArray_find_(DATA(self), DATA(other));
1038 if (pos != -1)
1040 UArray *ba = UArray_slice(DATA(self), 0, pos);
1042 if (ISSYMBOL(self))
1044 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
1046 else
1048 return IoSeq_newWithUArray_copy_(IOSTATE, ba, 0);
1052 if (ISSYMBOL(self))
1054 return self;
1057 return IOCLONE(self);
1060 IoObject *IoSeq_afterSeq(IoSeq *self, IoObject *locals, IoMessage *m)
1062 /*#io
1063 docSlot("afterSeq(aSequence)",
1064 "Returns the slice of the receiver (as a Symbol)
1065 after aSequence or Nil if aSequence is not found.
1066 If aSequence is empty, the receiver (or a copy of the
1067 receiver if it is mutable) is returned.")
1070 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
1071 long pos = UArray_find_(DATA(self), DATA(other));
1073 if (pos != -1)
1075 UArray *ba = UArray_slice(DATA(self), pos + UArray_size(DATA(other)), UArray_size(DATA(self)));
1077 if (ISSYMBOL(self))
1079 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
1081 else
1083 return IoSeq_newWithUArray_copy_(IOSTATE, ba, 0);
1087 return IONIL(self);
1090 IoObject *IoSeq_asCapitalized(IoSeq *self, IoObject *locals, IoMessage *m)
1092 /*#io
1093 docSlot("asCapitalized",
1094 "Returns a copy of the receiver with the first charater made uppercase.")
1097 /* need to fix for multi-byte characters */
1099 int firstChar = UArray_firstLong(DATA(self));
1100 int upperChar = toupper(firstChar);
1102 if (ISSYMBOL(self) && (firstChar == upperChar))
1104 return self;
1106 else
1108 UArray *ba = UArray_clone(DATA(self));
1109 UArray_at_putLong_(ba, 0, upperChar);
1111 if (ISSYMBOL(self))
1113 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
1116 return IoSeq_newWithUArray_copy_(IOSTATE, ba, 0);
1120 IoObject *IoSeq_occurancesOfSeq(IoSeq *self, IoObject *locals, IoMessage *m)
1122 /*#io
1123 docSlot("occurancesOfSeq(aSeq)", "Returns count of aSeq in the receiver.")
1126 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
1127 size_t count = UArray_count_(DATA(self), DATA(other));
1128 return IONUMBER(count);
1131 IoObject *IoSeq_interpolate(IoSeq *self, IoObject *locals, IoMessage *m)
1133 /*#io
1134 docSlot("interpolate(ctx)", "Returns immutable copy of self with interpolateInPlace(ctx) passed to the copy.")
1137 IoSeq *s = IoSeq_newWithUArray_copy_(IOSTATE, IoSeq_rawUArray(self), 1);
1138 IoSeq_interpolateInPlace(s, locals, m);
1139 return IoSeq_rawAsSymbol(s);
1142 IoObject *IoSeq_distanceTo(IoSeq *self, IoObject *locals, IoMessage *m)
1144 /*#io
1145 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.")
1148 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
1149 double d;
1151 d = UArray_distanceTo_(DATA(self), DATA(other));
1152 return IONUMBER(d);
1155 IoObject *IoSeq_greaterThan_(IoSeq *self, IoObject *locals, IoMessage *m)
1157 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
1158 return IOBOOL(self, UArray_greaterThan_(DATA(self), DATA(other)));
1161 IoObject *IoSeq_lessThan_(IoSeq *self, IoObject *locals, IoMessage *m)
1163 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
1164 return IOBOOL(self, UArray_lessThan_(DATA(self), DATA(other)));
1167 IoObject *IoSeq_greaterThanOrEqualTo_(IoSeq *self, IoObject *locals, IoMessage *m)
1169 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
1170 return IOBOOL(self, UArray_greaterThanOrEqualTo_(DATA(self), DATA(other)));
1173 IoObject *IoSeq_lessThanOrEqualTo_(IoSeq *self, IoObject *locals, IoMessage *m)
1175 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
1176 return IOBOOL(self, UArray_lessThanOrEqualTo_(DATA(self), DATA(other)));
1179 // -----------------------------------------------------------
1181 #define ASSTRUCT(type) if (!strcmp(mt, #type)) \
1183 int typeSize = sizeof(type ## _t); \
1184 IOASSERT(offset + typeSize <= size, "not enough data for struct"); \
1185 v = IONUMBER(*(type ## _t *)(data + offset)); \
1186 offset += typeSize; \
1189 IoObject *IoSeq_asStruct(IoSeq *self, IoObject *locals, IoMessage *m)
1191 IoObject *st = IoObject_new(IOSTATE);
1192 const unsigned char *data = UArray_bytes(DATA(self));
1193 size_t size = UArray_sizeInBytes(DATA(self));
1194 size_t offset = 0;
1195 List *members = IoList_rawList(IoMessage_locals_listArgAt_(m, locals, 0));
1196 int memberIndex;
1198 IOASSERT(List_size(members) % 2 == 0, "members list must be even number");
1200 for (memberIndex = 0; memberIndex < List_size(members) / 2 && offset < size; memberIndex ++)
1202 IoSeq *memberType = List_at_(members, memberIndex*2);
1203 IoSeq *memberName = List_at_(members, memberIndex*2 + 1);
1204 char *mt;
1205 IoObject *v = NULL;
1207 IOASSERT(ISSEQ(memberType), "memberTypes must be strings");
1208 IOASSERT(ISSEQ(memberName), "memberNames must be strings");
1210 mt = CSTRING(memberType);
1212 ASSTRUCT(int8);
1213 ASSTRUCT(uint8);
1214 ASSTRUCT(int16);
1215 ASSTRUCT(uint16);
1216 ASSTRUCT(int32);
1217 ASSTRUCT(uint32);
1218 ASSTRUCT(int64);
1219 ASSTRUCT(uint64);
1220 ASSTRUCT(float32);
1221 ASSTRUCT(float64);
1223 IoObject_setSlot_to_(st, memberName, v);
1226 return st;
1229 #define WITHSTRUCT(type) if (!strcmp(mt, #type)) \
1231 int typeSize = sizeof(type ## _t); \
1232 *(type ## _t *)(data + offset) = CNUMBER(memberValue); \
1233 offset += typeSize; \
1234 continue; \
1237 IoObject *IoSeq_withStruct(IoSeq *self, IoObject *locals, IoMessage *m)
1239 List *members = IoList_rawList(IoMessage_locals_listArgAt_(m, locals, 0));
1240 int memberIndex;
1241 size_t maxSize = List_size(members) * 8;
1242 IoSeq *s = IoSeq_newWithData_length_(IOSTATE, malloc(maxSize), maxSize);
1243 unsigned char *data = IoSeq_rawBytes(s);
1244 size_t offset = 0;
1246 IOASSERT(List_size(members) % 2 == 0, "members list must be even number");
1248 for (memberIndex = 0; memberIndex < List_size(members) / 2 && offset < maxSize; memberIndex ++)
1250 IoSeq *memberType = List_at_(members, memberIndex*2);
1251 IoSeq *memberValue = List_at_(members, memberIndex*2 + 1);
1252 char *mt;
1253 IoObject *v = NULL;
1255 IOASSERT(ISSEQ(memberType), "memberTypes must be strings");
1256 IOASSERT(ISNUMBER(memberValue), "memberValues must be strings");
1258 mt = CSTRING(memberType);
1260 WITHSTRUCT(int8);
1261 WITHSTRUCT(uint8);
1262 WITHSTRUCT(int16);
1263 WITHSTRUCT(uint16);
1264 WITHSTRUCT(int32);
1265 WITHSTRUCT(uint32);
1266 WITHSTRUCT(int64);
1267 WITHSTRUCT(uint64);
1268 WITHSTRUCT(float32);
1269 WITHSTRUCT(float64);
1272 IoSeq_rawSetSize_(s, offset);
1274 return s;
1277 void IoSeq_addImmutableMethods(IoSeq *self)
1279 IoMethodTable methodTable[] = {
1280 {"itemType", IoSeq_itemType},
1281 {"itemSize", IoSeq_itemSize},
1282 {"encoding", IoSeq_encoding},
1283 {"asUTF8", IoSeq_asUTF8},
1284 {"asUTF16", IoSeq_asUTF16},
1285 {"asUTF32", IoSeq_asUTF32},
1286 {"asFixedSizeType", IoSeq_asFixedSizeType},
1288 {"asBinaryNumber", IoSeq_asBinaryNumber},
1289 {"isSymbol", IoSeq_isSymbol},
1290 {"isMutable", IoSeq_isMutable},
1291 {"asSymbol", IoSeq_asSymbol},
1292 {"asString", IoSeq_asSymbol},
1293 {"asNumber", IoSeq_asNumber},
1294 {"whiteSpaceStrings", IoSeq_whiteSpaceStrings},
1295 {"print", IoSeq_print},
1296 {"linePrint", IoSeq_linePrint},
1297 {"size", IoSeq_size},
1298 {"isZero", IoSeq_isZero},
1299 {"isEmpty", IoSeq_isEmpty},
1300 {"at", IoSeq_at},
1301 {"slice", IoSeq_slice},
1302 {"between", IoSeq_between},
1303 {"betweenSeq", IoSeq_between},
1304 {"findSeqs", IoSeq_findSeqs},
1305 {"findSeq", IoSeq_findSeq},
1306 {"reverseFindSeq", IoSeq_reverseFindSeq},
1307 {"beginsWithSeq", IoSeq_beginsWithSeq},
1308 {"endsWithSeq", IoSeq_endsWithSeq},
1309 {"split", IoSeq_split},
1310 {"contains", IoSeq_contains},
1311 {"containsSeq", IoSeq_containsSeq},
1312 {"containsAnyCaseSeq", IoSeq_containsAnyCaseSeq},
1313 {"isLowercase", IoSeq_isLowercase},
1314 {"isUppercase", IoSeq_isUppercase},
1315 {"isEqualAnyCase", IoSeq_isEqualAnyCase},
1316 {"splitAt", IoSeq_splitAt},
1317 {"fromBase", IoSeq_fromBase},
1318 {"toBase", IoSeq_toBase},
1319 {"foreach", IoSeq_foreach},
1320 {"asMessage", IoSeq_asMessage},
1321 {"..", IoSeq_cloneAppendSeq},
1322 {"cloneAppendSeq", IoSeq_cloneAppendSeq},
1323 {"asMutable", IoSeq_asMutable},
1324 {"asBuffer", IoSeq_asMutable},
1326 // paths
1328 {"fileName", IoSeq_fileName},
1329 {"pathExtension", IoSeq_pathExtension},
1330 {"lastPathComponent", IoSeq_lastPathComponent},
1331 {"cloneAppendPath", IoSeq_cloneAppendPath},
1332 {"pathComponent", IoSeq_pathComponent},
1333 {"asOSPath", IoSeq_asOSPath},
1334 {"asIoPath", IoSeq_asIoPath},
1336 {"afterSeq", IoSeq_afterSeq},
1337 {"beforeSeq", IoSeq_beforeSeq},
1339 {"asCapitalized", IoSeq_asCapitalized},
1340 {"asUppercase", IoSeq_asUppercase},
1341 {"asLowercase", IoSeq_asLowercase},
1342 {"with", IoSeq_with},
1343 {"occurancesOfSeq", IoSeq_occurancesOfSeq},
1344 {"interpolate", IoSeq_interpolate},
1345 {"distanceTo", IoSeq_distanceTo},
1347 {">", IoSeq_greaterThan_},
1348 {"<", IoSeq_lessThan_},
1349 {">=", IoSeq_greaterThanOrEqualTo_},
1350 {"<=", IoSeq_lessThanOrEqualTo_},
1352 {"asStruct", IoSeq_asStruct},
1353 {"withStruct", IoSeq_withStruct},
1354 {NULL, NULL},
1357 IoObject_addMethodTable_(self, methodTable);