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". """)
10 #define _GNU_SOURCE // for NAN macro
13 #include "IoCFunction.h"
16 #include "IoMessage.h"
20 #include <math.h> // for NAN macro
33 #define DATA(self) ((UArray *)IoObject_dataPointer(self))
36 IoObject
*IoSeq_rawAsSymbol(IoSeq
*self
)
43 return IoState_symbolWithUArray_copy_(IOSTATE
, DATA(self
), 1);
46 IoObject
*IoSeq_with(IoSeq
*self
, IoObject
*locals
, IoMessage
*m
)
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
));
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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);
136 IoObject
*IoSeq_asBinaryNumber(IoSeq
*self
, IoObject
*locals
, IoMessage
*m
)
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);
149 if (!ISNIL(byteCount
))
151 bc
= IoNumber_asInt(byteCount
);
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
);
163 IoObject
*IoSeq_asSymbol(IoSeq
*self
, IoObject
*locals
, IoMessage
*m
)
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
)
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
)
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
)
199 "Prints the receiver as a string. Returns self.")
202 IoState_justPrintba_(IOSTATE
, DATA(self
));
206 IoObject
*IoSeq_linePrint(IoSeq
*self
, IoObject
*locals
, IoMessage
*m
)
210 "Prints the Sequence and a newline character.")
213 IoState_justPrintba_(IOSTATE
, DATA(self
));
214 IoState_justPrintln_(IOSTATE
);
218 IoObject
*IoSeq_isEmpty(IoSeq
*self
, IoObject
*locals
, IoMessage
*m
)
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
)
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
)
239 docSlot("size", """Returns the length in bytes of the receiver. For example,
246 return IONUMBER(UArray_size(DATA(self
)));
249 IoObject
*IoSeq_at(IoSeq
*self
, IoObject
*locals
, IoMessage
*m
)
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
));
269 return IONUMBER(UArray_longAt_(a
, i
));
273 IoObject
*IoSeq_slice(IoSeq
*self
, IoObject
*locals
, IoMessage
*m
)
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
));
286 if (IoMessage_argCount(m
) > 1)
288 last
= IoMessage_locals_longArgAt_(m
, locals
, 1);
291 ba
= UArray_slice(DATA(self
), fromIndex
, last
);
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
)
304 docSlot("between(aSequence, anotherSequence)",
305 "Returns a new Sequence containing the bytes between the
306 occurance of aSequence and anotherSequence in the receiver.")
311 IoSeq
*fromSeq
, *toSeq
;
313 fromSeq
= (IoSeq
*)IoMessage_locals_valueArgAt_(m
, locals
, 0);
317 start
= UArray_find_from_(DATA(self
), DATA(fromSeq
), 0) + IoSeq_rawSize(fromSeq
);
324 else if (ISNIL(fromSeq
))
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);
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
));
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);
358 // find ----------------------------------------------------------
360 IoObject
*IoSeq_findSeqs(IoSeq
*self
, IoObject
*locals
, IoMessage
*m
)
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
);
370 long firstIndex
= -1;
373 if (IoMessage_argCount(m
) > 1)
375 f
= IoMessage_locals_longArgAt_(m
, locals
, 1);
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)
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
));
408 IoObject
*IoSeq_findSeq(IoSeq
*self
, IoObject
*locals
, IoMessage
*m
)
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);
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
)
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
));
446 if (IoMessage_argCount(m
) > 1)
448 from
= IoMessage_locals_intArgAt_(m
, locals
, 1);
451 index
= UArray_rFind_from_(DATA(self
), DATA(other
), from
);
458 return IONUMBER((double)index
);
461 IoObject
*IoSeq_beginsWithSeq(IoSeq
*self
, IoObject
*locals
, IoMessage
*m
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
));
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
);
583 IoList
*IoSeq_whiteSpaceStrings(IoSeq
*self
, IoObject
*locals
, IoMessage
*m
)
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"));
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
))
619 IoState_error_(IOSTATE
, m
,
620 "requires Sequences as arguments, not %ss",
621 IoObject_name((IoSeq
*)s
));
624 List_append_(list
, DATA(((IoSeq
*)s
)));
630 IoObject
*IoSeq_splitToFunction(IoSeq
*self
,
633 IoSplitFunction
*func
)
635 IoList
*output
= IoList_new(IOSTATE
);
636 List
*others
= IoSeq_byteArrayListForSeqList(self
, locals
, m
, IoSeq_stringListForArgs(self
, locals
, m
));
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
);
665 IoObject
*IoSeq_split(IoSeq
*self
, IoObject
*locals
, IoMessage
*m
)
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.
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")
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
);
701 /* --- base -------------------------------------------------------------- */
703 IoObject
*IoSeq_fromBase(IoSeq
*self
, IoObject
*locals
, IoMessage
*m
)
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
);
716 r
= strtoul(s
, &tail
, base
);
721 IoState_error_(IOSTATE
, m
, "conversion from base %i not supported", base
);
723 else if (errno
== ERANGE
)
726 IoState_error_(IOSTATE
, m
, "resulting value \"%s\" was out of range", s
);
728 else if (*s
== 0 || *tail
!= 0 || errno
!= 0)
731 IoState_error_(IOSTATE
, m
, "conversion of \"%s\" to base %i failed", s
, base
);
737 IoObject
*IoSeq_toBase(IoSeq
*self
, IoObject
*locals
, IoMessage
*m
)
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. */
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);
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
)));
794 result
= IoMessage_locals_performOn_(doMessage
, locals
, IONUMBER(UArray_longAt_(DATA(self
), i
)));
797 if (IoState_handleStatus(IOSTATE
))
804 IoState_popRetainPoolExceptFor_(state
, result
);
809 IoObject
*IoSeq_foreach(IoSeq
*self
, IoObject
*locals
, IoMessage
*m
)
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:
816 aSequence foreach(i, v, writeln("value at index ", i, " is ", v))
817 aSequence foreach(v, writeln("value ", v))
821 IoObject
*result
= IONIL(self
);
822 IoMessage
*doMessage
;
824 IoSymbol
*indexSlotName
;
825 IoSymbol
*characterSlotName
;
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
);
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
)));
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
))
863 IoState_popRetainPoolExceptFor_(IOSTATE
, result
);
867 IoObject
*IoSeq_asMessage(IoSeq
*self
, IoObject
*locals
, IoMessage
*m
)
870 docSlot("asMessage(optionalLabel)",
871 "Returns the compiled message object for the string.")
876 if (IoMessage_argCount(m
) >= 1)
877 label
= IoMessage_locals_symbolArgAt_(m
, locals
, 0);
879 label
= IOSYMBOL("[asMessage]");
881 return IoMessage_newFromText_labelSymbol_(IOSTATE
, CSTRING(self
), label
);
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);
895 other
= IoNumber_justAsString((IoNumber
*)other
, (IoObject
*)locals
, m
);
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)
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
)
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
)
931 docSlot("asUppercase",
932 "Returns a symbol containing the reveiver made uppercase. ")
935 UArray
*ba
= UArray_clone(DATA(self
));
937 return IoState_symbolWithUArray_copy_(IOSTATE
, ba
, 0);
940 IoObject
*IoSeq_asLowercase(IoSeq
*self
, IoObject
*locals
, IoMessage
*m
)
943 docSlot("asLowercase",
944 "Returns a symbol containing the reveiver made Lowercase. ")
947 UArray
*ba
= UArray_clone(DATA(self
));
949 return IoState_symbolWithUArray_copy_(IOSTATE
, ba
, 0);
952 /* --- path ------------------------------------------------ */
955 IoObject
*IoSeq_lastPathComponent(IoSeq
*self
, IoObject
*locals
, IoMessage
*m
)
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
)
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
)
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
)
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
)
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
)
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
));
1028 UArray
*ba
= UArray_slice(DATA(self
), 0, pos
);
1032 return IoState_symbolWithUArray_copy_(IOSTATE
, ba
, 0);
1036 return IoSeq_newWithUArray_copy_(IOSTATE
, ba
, 0);
1045 return IOCLONE(self
);
1048 IoObject
*IoSeq_afterSeq(IoSeq
*self
, IoObject
*locals
, IoMessage
*m
)
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
));
1063 UArray
*ba
= UArray_slice(DATA(self
), pos
+ UArray_size(DATA(other
)), UArray_size(DATA(self
)));
1067 return IoState_symbolWithUArray_copy_(IOSTATE
, ba
, 0);
1071 return IoSeq_newWithUArray_copy_(IOSTATE
, ba
, 0);
1078 IoObject
*IoSeq_asCapitalized(IoSeq
*self
, IoObject
*locals
, IoMessage
*m
)
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
))
1096 UArray
*ba
= UArray_clone(DATA(self
));
1097 UArray_at_putLong_(ba
, 0, upperChar
);
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
)
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
)
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
)
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);
1139 d
= UArray_distanceTo_(DATA(self
), DATA(other
));
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
));
1183 List
*members
= IoList_rawList(IoMessage_locals_listArgAt_(m
, locals
, 0));
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);
1195 IOASSERT(ISSEQ(memberType
), "memberTypes must be strings");
1196 IOASSERT(ISSEQ(memberName
), "memberNames must be strings");
1198 mt
= CSTRING(memberType
);
1211 IoObject_setSlot_to_(st
, memberName
, v
);
1217 #define WITHSTRUCT(type) if (!strcmp(mt, #type)) \
1219 int typeSize = sizeof(type ## _t); \
1220 *(type ## _t *)(data + offset) = CNUMBER(memberValue); \
1221 offset += typeSize; \
1225 IoObject
*IoSeq_withStruct(IoSeq
*self
, IoObject
*locals
, IoMessage
*m
)
1227 List
*members
= IoList_rawList(IoMessage_locals_listArgAt_(m
, locals
, 0));
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
);
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);
1243 IOASSERT(ISSEQ(memberType
), "memberTypes must be strings");
1244 IOASSERT(ISNUMBER(memberValue
), "memberValues must be strings");
1246 mt
= CSTRING(memberType
);
1256 WITHSTRUCT(float32
);
1257 WITHSTRUCT(float64
);
1260 IoSeq_rawSetSize_(s
, offset
);
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
},
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
},
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
},
1343 IoObject_addMethodTable_(self
, methodTable
);