New doc system done for core
[io.git] / libs / iovm / source / IoList.c
blobfd788ce82eb7d765749a5f38f6306e14348b9f12
2 //metadoc List copyright Steve Dekorte 2002
3 //metadoc List license BSD revised
4 /*metadoc List description
5 A mutable array of values. The first index is 0.")
6 */
7 //metadoc List category DataStructures
9 #include "IoList.h"
10 #include "IoObject.h"
11 #include "IoState.h"
12 #include "IoCFunction.h"
13 #include "IoSeq.h"
14 #include "IoState.h"
15 #include "IoNumber.h"
16 #include "IoBlock.h"
17 #include "Sorting.h"
18 #include <math.h>
20 #define DATA(self) ((List *)(IoObject_dataPointer(self)))
22 IoTag *IoList_newTag(void *state)
24 IoTag *tag = IoTag_newWithName_("List");
25 IoTag_state_(tag, state);
26 IoTag_freeFunc_(tag, (IoTagFreeFunc *)IoList_free);
27 IoTag_cloneFunc_(tag, (IoTagCloneFunc *)IoList_rawClone);
28 IoTag_markFunc_(tag, (IoTagMarkFunc *)IoList_mark);
29 IoTag_compareFunc_(tag, (IoTagCompareFunc *)IoList_compare);
30 IoTag_writeToStreamFunc_(tag, (IoTagWriteToStreamFunc *)IoList_writeToStream_);
31 IoTag_readFromStreamFunc_(tag, (IoTagReadFromStreamFunc *)IoList_readFromStream_);
32 return tag;
35 void IoList_writeToStream_(IoList *self, BStream *stream)
37 List *list = DATA(self);
39 BStream_writeTaggedInt32_(stream, List_size(list));
41 LIST_FOREACH(list, i, v,
42 BStream_writeTaggedInt32_(stream, IoObject_pid((IoObject *)v));
46 void IoList_readFromStream_(IoList *self, BStream *stream)
48 List *list = DATA(self);
49 int i, max = BStream_readTaggedInt32(stream);
51 for (i = 0; i < max; i ++)
53 int pid = BStream_readTaggedInt32(stream);
54 IoObject *v = IoState_objectWithPid_(IOSTATE, pid);
55 List_append_(list, v);
59 IoList *IoList_proto(void *state)
61 IoMethodTable methodTable[] = {
62 {"with", IoList_with},
64 // access
66 {"indexOf", IoList_indexOf},
67 {"contains", IoList_contains},
68 {"containsIdenticalTo", IoList_containsIdenticalTo},
69 {"capacity", IoList_capacity},
70 {"size", IoList_size},
72 // mutation
74 {"setSize", IoList_setSize},
75 {"removeAll", IoList_removeAll},
76 {"appendSeq", IoList_appendSeq},
77 {"append", IoList_append},
78 {"prepend", IoList_prepend},
79 {"push", IoList_append},
81 {"appendIfAbsent", IoList_appendIfAbsent},
83 {"remove", IoList_remove},
84 {"pop", IoList_pop},
86 {"atInsert", IoList_atInsert},
87 {"at", IoList_at},
88 {"atPut", IoList_atPut},
90 {"removeAt", IoList_removeAt},
91 {"swapIndices", IoList_swapIndices},
93 {"preallocateToSize", IoList_preallocateToSize},
95 {"first", IoList_first},
96 {"last", IoList_last},
97 {"slice", IoList_slice},
98 {"sliceInPlace", IoList_sliceInPlace},
101 {"sortInPlace", IoList_sortInPlace},
102 {"sortInPlaceBy", IoList_sortInPlaceBy},
103 {"foreach", IoList_foreach},
104 {"reverse", IoList_reverse},
105 {"reverseForeach", IoList_reverseForeach},
106 {NULL, NULL},
109 IoObject *self = IoObject_new(state);
110 IoObject_tag_(self, IoList_newTag(state));
112 IoObject_setDataPointer_(self, List_new());
113 IoState_registerProtoWithFunc_((IoState *)state, self, IoList_proto);
115 IoObject_addMethodTable_(self, methodTable);
116 return self;
119 IoList *IoList_rawClone(IoList *proto)
121 IoObject *self = IoObject_rawClonePrimitive(proto);
122 IoObject_tag_(self, IoObject_tag(proto));
123 IoObject_setDataPointer_(self, List_clone(DATA(proto)));
124 return self;
127 IoList *IoList_new(void *state)
129 IoObject *proto = IoState_protoWithInitFunction_((IoState *)state, IoList_proto);
130 return IOCLONE(proto);
133 IoList *IoList_newWithList_(void *state, List *list)
135 IoList *self = IoList_new(state);
136 //printf("IoList_newWithList_ %p %p\n", (void *)self, (void *)list);
137 List_free(IoObject_dataPointer(self));
138 IoObject_setDataPointer_(self, list);
139 return self;
142 void IoList_free(IoList *self)
144 if (NULL == DATA(self))
146 printf("IoList_free(%p) already freed\n", (void *)self);
147 exit(1);
149 //printf("IoList_free(%p) List_free(%p)\n", (void *)self, (void *)DATA(self));
151 List_free(DATA(self));
152 IoObject_setDataPointer_(self, NULL);
156 void IoList_mark(IoList *self)
158 LIST_FOREACH(DATA(self), i, item, IoObject_shouldMark(item));
161 int IoList_compare(IoList *self, IoList *otherList)
163 if (!ISLIST(otherList))
165 return IoObject_defaultCompare(self, otherList);
167 else
169 size_t s1 = List_size(DATA(self));
170 size_t s2 = List_size(DATA(otherList));
171 size_t i;
173 if (s1 != s2)
175 return s1 > s2 ? 1 : -1;
178 for (i = 0; i < s1; i ++)
180 IoObject *v1 = LIST_AT_(DATA(self), i);
181 IoObject *v2 = LIST_AT_(DATA(otherList), i);
182 int c = IoObject_compare(v1, v2);
184 if (c)
186 return c;
190 return 0;
193 List *IoList_rawList(IoList *self)
195 return DATA(self);
198 IoObject *IoList_rawAt_(IoList *self, int i)
200 return List_at_(DATA(self), i);
203 void IoList_rawAt_put_(IoList *self, int i, IoObject *v)
205 List_at_put_(DATA(self), i, IOREF(v));
208 void IoList_rawAppend_(IoList *self, IoObject *v)
210 List_append_(DATA(self), IOREF(v));
213 void IoList_rawRemove_(IoList *self, IoObject *v)
215 List_remove_(DATA(self), IOREF(v));
218 void IoList_rawAddBaseList_(IoList *self, List *otherList)
220 List *list = DATA(self);
221 LIST_FOREACH(otherList, i, v, List_append_(list, IOREF((IoObject *)v)); );
224 void IoList_rawAddIoList_(IoList *self, IoList *other)
226 IoList_rawAddBaseList_(self, DATA(other));
229 size_t IoList_rawSize(IoList *self)
231 return List_size(DATA(self));
234 int IoList_rawIndexOf_(IoList *self, IoObject *v)
236 List *list = DATA(self);
238 LIST_FOREACH(list, i, item,
239 if (IoObject_compare(v, (IoObject *)item) == 0)
241 return i;
245 return -1;
248 void IoList_checkIndex(IoList *self, IoMessage *m, char allowsExtending, int index, const char *methodName)
250 int max = List_size(DATA(self));
252 if (allowsExtending)
254 max += 1;
257 if (index < 0 || index >= max)
259 IoState_error_(IOSTATE, m, "index out of bounds\n");
263 // immutable --------------------------------------------------------
265 IoObject *IoList_with(IoList *self, IoObject *locals, IoMessage *m)
267 /*doc List with(anObject, ...)
268 Returns a new List containing the arguments.
271 int n, argCount = IoMessage_argCount(m);
272 IoList *ioList = IOCLONE(self);
274 for (n = 0; n < argCount; n ++)
276 IoObject *v = IoMessage_locals_valueArgAt_(m, locals, n);
277 IoList_rawAppend_(ioList, v);
280 return ioList;
284 IoObject *IoList_indexOf(IoList *self, IoObject *locals, IoMessage *m)
286 /*doc List indexOf(anObject)
287 Returns the index of the first occurrence of anObject
288 in the receiver. Returns Nil if the receiver doesn't contain anObject.
291 int count = IoMessage_argCount(m);
293 IOASSERT(count, "remove requires at least one argument");
296 IoObject *v = IoMessage_locals_valueArgAt_(m, locals, 0);
297 int i = IoList_rawIndexOf_(self, v);
299 return i == -1 ? IONIL(self) :
300 (IoObject *)IONUMBER(IoList_rawIndexOf_(self, v));
304 IoObject *IoList_contains(IoList *self, IoObject *locals, IoMessage *m)
306 /*doc List contains(anObject)
307 Returns true if the receiver contains anObject, otherwise returns false.
310 IoObject *v = IoMessage_locals_valueArgAt_(m, locals, 0);
311 return IOBOOL(self, IoList_rawIndexOf_(self, v) != -1);
314 IoObject *IoList_containsIdenticalTo(IoList *self, IoObject *locals, IoMessage *m)
316 /*doc List containsIdenticalTo(anObject)
317 Returns true if the receiver contains a value identical to anObject, otherwise returns false.
320 IoObject *v = IoMessage_locals_valueArgAt_(m, locals, 0);
321 return IOBOOL(self, List_contains_(DATA(self), v) != 0);
324 IoObject *IoList_capacity(IoList *self, IoObject *locals, IoMessage *m)
326 /*doc List capacity
327 Returns the number of potential elements the receiver can hold before it needs to grow.
330 return IONUMBER(DATA(self)->memSize / sizeof(void *));
333 IoObject *IoList_size(IoList *self, IoObject *locals, IoMessage *m)
335 /*doc List size
336 Returns the number of items in the receiver.
339 return IONUMBER(List_size(DATA(self)));
342 IoObject *IoList_at(IoList *self, IoObject *locals, IoMessage *m)
344 /*doc List at(index)
345 Returns the value at index. Returns Nil if the index is out of bounds.
348 int index = IoMessage_locals_intArgAt_(m, locals, 0);
349 IoObject *v;
350 /*IoList_checkIndex(self, m, 0, index, "Io List at");*/
351 v = List_at_(DATA(self), index);
352 return (v) ? v : IONIL(self);
355 IoObject *IoList_first(IoList *self, IoObject *locals, IoMessage *m)
357 /*doc List first(optionalSize)
358 Returns the first item or Nil if the list is empty.
359 If optionalSize is provided, that number of the first items in the list are returned.
362 if (IoMessage_argCount(m) == 0)
364 IoObject *result = List_at_(DATA(self), 0);
366 return result ? result : ((IoState *)IOSTATE)->ioNil;
368 else
370 int end = IoMessage_locals_intArgAt_(m, locals, 0);
372 if (end <= 0)
374 return IoList_new(IOSTATE);
376 else
378 List *list = List_cloneSlice(DATA(self), 0, end - 1);
379 return IoList_newWithList_(IOSTATE, list);
384 IoObject *IoList_last(IoList *self, IoObject *locals, IoMessage *m)
386 /*doc List last(optionalSize)
387 Returns the last item or Nil if the list is empty.
388 If optionalSize is provided, that number of the last items in the list are returned.
391 if (IoMessage_argCount(m) == 0)
393 IoObject *result = List_at_(DATA(self), List_size(DATA(self))-1);
394 return result ? result : ((IoState *)IOSTATE)->ioNil;
396 else
398 size_t size = IoList_rawSize(self);
399 int start = size - IoMessage_locals_intArgAt_(m, locals, 0);
400 List *list;
402 if (start < 0)
404 start = 0;
407 list = List_cloneSlice(DATA(self), start, size);
408 return IoList_newWithList_(IOSTATE, list);
412 void IoList_sliceArguments(IoList *self, IoObject *locals, IoMessage *m, int *start, int *end)
414 int size = IoList_rawSize(self);
416 *start = IoMessage_locals_intArgAt_(m, locals, 0);
417 if (*start < 0)
419 *start += size;
420 if (*start < 0)
422 *start = 0;
426 if (IoMessage_argCount(m) == 2)
428 *end = IoMessage_locals_intArgAt_(m, locals, 1);
429 if (*end < 0)
431 *end += size;
433 (*end)--;
435 else
437 *end = size;
441 IoObject *IoList_slice(IoList *self, IoObject *locals, IoMessage *m)
443 /*doc List slice(startIndex, endIndex)
444 Returns a new string containing the subset of the
445 receiver from the startIndex to the endIndex. The endIndex argument
446 is optional. If not given, it is assumed to be the end of the string.
449 List *list;
450 int start, end;
452 IoList_sliceArguments(self, locals, m, &start, &end);
454 if (end < start)
456 return IoList_new(IOSTATE);
458 else
460 list = List_cloneSlice(DATA(self), start, end);
461 return IoList_newWithList_(IOSTATE, list);
465 IoObject *IoList_sliceInPlace(IoList *self, IoObject *locals, IoMessage *m)
467 /*doc List sliceInPlace(startIndex, endIndex)
468 Returns the receiver containing the subset of the
469 receiver from the startIndex to the endIndex. The endIndex argument
470 is optional. If not given, it is assumed to be the end of the string.
473 int start, end;
475 IoList_sliceArguments(self, locals, m, &start, &end);
477 if (end < start)
479 List_removeAll(DATA(self));
481 else
483 List_sliceInPlace(DATA(self), start, end);
485 return self;
488 IoObject *IoList_each(IoList *self, IoObject *locals, IoMessage *m)
490 IoState *state = IOSTATE;
491 IoObject *result = IONIL(self);
492 IoMessage *doMessage = IoMessage_rawArgAt_(m, 0);
493 List *list = DATA(self);
495 IoState_pushRetainPool(state);
497 LIST_SAFEFOREACH(list, i, v,
498 IoState_clearTopPool(state);
499 result = IoMessage_locals_performOn_(doMessage, locals, (IoObject *)v);
500 if (IoState_handleStatus(IOSTATE)) goto done;
503 done:
504 IoState_popRetainPoolExceptFor_(state, result);
505 return result;
509 IoObject *IoList_foreach(IoList *self, IoObject *locals, IoMessage *m)
511 /*doc List foreach(optionalIndex, value, message)
512 Loops over the list values setting the specified index and
513 value slots and executing the message. Returns the result of the last
514 execution of the message. Example:
515 <code> list(1, 2, 3) foreach(i, v, writeln(i, " = ", v))
516 list(1, 2, 3) foreach(v, writeln(v))</code>
519 IoState *state = IOSTATE;
520 IoObject *result = IONIL(self);
521 IoSymbol *slotName = NULL;
522 IoSymbol *valueName;
523 IoMessage *doMessage;
524 List *list = DATA(self);
526 if (IoMessage_argCount(m) == 1)
528 return IoList_each(self, locals, m);
531 IoMessage_foreachArgs(m, self, &slotName, &valueName, &doMessage);
533 IoState_pushRetainPool(state);
535 if (slotName)
537 LIST_SAFEFOREACH(list, i, value,
538 IoState_clearTopPool(state);
539 IoObject_setSlot_to_(locals, slotName, IONUMBER(i));
540 IoObject_setSlot_to_(locals, valueName, (IoObject *)value);
541 result = IoMessage_locals_performOn_(doMessage, locals, locals);
542 if (IoState_handleStatus(IOSTATE)) goto done;
545 else
547 LIST_SAFEFOREACH(list, i, value,
548 IoState_clearTopPool(state);
549 IoObject_setSlot_to_(locals, valueName, (IoObject *)value);
550 result = IoMessage_locals_performOn_(doMessage, locals, locals);
551 if (IoState_handleStatus(IOSTATE)) goto done;
555 done:
556 IoState_popRetainPoolExceptFor_(state, result);
557 return result;
560 IoObject *IoList_reverseForeach(IoList *self, IoObject *locals, IoMessage *m)
562 /*doc List reverseForeach(index, value, message)
563 Same as foreach, but in reverse order.
566 IoState *state = IOSTATE;
567 IoObject *result = IONIL(self);
568 IoSymbol *slotName, *valueName;
569 IoMessage *doMessage;
570 int i;
572 IoMessage_foreachArgs(m, self, &slotName, &valueName, &doMessage);
574 IoState_pushRetainPool(state);
576 for (i = List_size(DATA(self)) - 1; i >= 0; i --)
578 IoState_clearTopPool(state);
580 IoObject *value = (IoObject *)LIST_AT_(DATA(self), i);
582 if (slotName)
584 IoObject_setSlot_to_(locals, slotName, IONUMBER(i));
587 IoObject_setSlot_to_(locals, valueName, value);
588 result = IoMessage_locals_performOn_(doMessage, locals, locals);
590 if (IoState_handleStatus(IOSTATE))
592 goto done;
595 if(i > List_size(DATA(self)) - 1) { i = List_size(DATA(self)) - 1; }
597 done:
598 IoState_popRetainPoolExceptFor_(state, result);
599 return result;
602 // mutable --------------------------------------------------------
604 IoObject *IoList_appendIfAbsent(IoList *self, IoObject *locals, IoMessage *m)
606 /*doc List appendIfAbsent(anObject)
607 Adds each value not already contained by the receiver, returns self.
610 int n;
612 for (n = 0; n < IoMessage_argCount(m); n ++)
614 IoObject *v = IoMessage_locals_valueArgAt_(m, locals, n);
616 if (IoList_rawIndexOf_(self, v) == -1)
618 IoState_stackRetain_(IOSTATE, v);
619 List_append_(DATA(self), IOREF(v));
623 return self;
626 IoObject *IoList_appendSeq(IoList *self, IoObject *locals, IoMessage *m)
628 /*doc List appendSeq(aList1, aList2, ...)
629 Add the items in the lists to the receiver. Returns self.
632 int i;
634 for (i = 0; i < IoMessage_argCount(m); i ++)
636 IoObject *other = IoMessage_locals_valueArgAt_(m, locals, i);
638 IOASSERT(ISLIST(other), "requires List objects as arguments");
640 if (other == self)
642 IoState_error_(IOSTATE, m, "can't add a list to itself\n");
644 else
646 List *selfList = DATA(self);
647 List *otherList = DATA(other);
648 int i, max = List_size(otherList);
650 for (i = 0; i < max; i ++)
652 IoObject *v = List_at_(otherList, i);
653 List_append_(selfList, IOREF(v));
657 return self;
660 IoObject *IoList_append(IoList *self, IoObject *locals, IoMessage *m)
662 /*doc List append(anObject1, anObject2, ...)
663 Appends the arguments to the end of the list. Returns self.
666 /*doc List push(anObject1, anObject2, ...)
667 Same as add(anObject1, anObject2, ...).
670 int n;
672 IOASSERT(IoMessage_argCount(m), "requires at least one argument");
674 for (n = 0; n < IoMessage_argCount(m); n ++)
676 IoObject *v = IoMessage_locals_valueArgAt_(m, locals, n);
677 List_append_(DATA(self), IOREF(v));
680 return self;
683 IoObject *IoList_prepend(IoList *self, IoObject *locals, IoMessage *m)
685 /*doc List prepend(anObject1, anObject2, ...)
686 Inserts the values at the beginning of the list. Returns self.
689 int n;
691 IOASSERT(IoMessage_argCount(m), "requires at least one argument");
693 for (n = 0; n < IoMessage_argCount(m); n ++)
695 IoObject *v = IoMessage_locals_valueArgAt_(m, locals, n);
696 List_at_insert_(DATA(self), 0, IOREF(v));
699 return self;
703 IoObject *IoList_remove(IoList *self, IoObject *locals, IoMessage *m)
705 /*doc List remove(anObject, ...)
706 Removes all occurrences of the arguments from the receiver. Returns self.
709 int count = IoMessage_argCount(m);
710 int j;
712 IOASSERT(count, "requires at least one argument");
714 for (j = 0; j < count; j++)
716 IoObject *v = IoMessage_locals_valueArgAt_(m, locals, j);
718 // a quick pass to remove values with equal pointers
719 List_remove_(DATA(self), v);
721 // slow pass to remove values that match comparision test
722 for (;;)
724 int i = IoList_rawIndexOf_(self, v);
726 if (i == -1)
728 break;
731 List_removeIndex_(DATA(self), i);
735 return self;
738 IoObject *IoList_pop(IoList *self, IoObject *locals, IoMessage *m)
740 /*doc List pop
741 Returns the last item in the list and removes it
742 from the receiver. Returns nil if the receiver is empty.
745 IoObject *v = List_pop(DATA(self));
746 return (v) ? v : IONIL(self);
749 IoObject *IoList_atInsert(IoList *self, IoObject *locals, IoMessage *m)
751 /*doc List atInsert(index, anObject)
752 Inserts anObject at the index specified by index.
753 Adds anObject if the index equals the current count of the receiver.
754 Raises an exception if the index is out of bounds. Returns self.
757 int index = IoMessage_locals_intArgAt_(m, locals, 0);
758 IoObject *v = IoMessage_locals_valueArgAt_(m, locals, 1);
760 IoList_checkIndex(self, m, 1, index, "List atInsert");
761 List_at_insert_(DATA(self), index, IOREF(v));
762 return self;
765 IoObject *IoList_removeAt(IoList *self, IoObject *locals, IoMessage *m)
767 /*doc List removeAt(index)
768 Removes the item at the specified index and returns the value removed.
769 Raises an exception if the index is out of bounds.
772 int index = IoMessage_locals_intArgAt_(m, locals, 0);
773 IoObject *v = List_at_(DATA(self), index);
775 IoList_checkIndex(self, m, 0, index, "Io List atInsert");
776 List_removeIndex_(DATA(self), index);
777 return (v) ? v : IONIL(self);
780 void IoList_rawAtPut(IoList *self, int i, IoObject *v)
782 while (List_size(DATA(self)) < i) /* not efficient */
784 List_append_(DATA(self), IONIL(self));
787 List_at_put_(DATA(self), i, IOREF(v));
790 IoObject *IoList_atPut(IoList *self, IoObject *locals, IoMessage *m)
792 /*doc List atPut(index, anObject)
793 Replaces the existing value at index with anObject.
794 Raises an exception if the index is out of bounds. Returns self.
797 int index = IoMessage_locals_intArgAt_(m, locals, 0);
798 IoObject *v = IoMessage_locals_valueArgAt_(m, locals, 1);
800 IoList_checkIndex(self, m, 0, index, "Io List atPut");
801 IoList_rawAtPut(self, index, v);
802 return self;
805 IoObject *IoList_setSize(IoList *self, IoObject *locals, IoMessage *m)
807 /*doc List setSize
808 Sets the size of the receiver by either removing excess items or adding nils as needed.
811 List *list = DATA(self);
812 size_t newSize = IoMessage_locals_sizetArgAt_(m, locals, 0);
813 size_t oldSize = List_size(list);
815 if(newSize < oldSize)
817 List_setSize_(list, newSize);
819 else
821 size_t i, max = newSize - oldSize;
822 IoObject *nilObject = IONIL(self);
824 for(i = 0; i < max; i ++)
826 List_append_(list, nilObject);
830 return self;
833 IoObject *IoList_removeAll(IoList *self, IoObject *locals, IoMessage *m)
835 /*doc List empty
836 Removes all items from the receiver.
839 List_removeAll(DATA(self));
840 return self;
843 IoObject *IoList_swapIndices(IoList *self, IoObject *locals, IoMessage *m)
845 /*doc List swapIndices(index1, index2)
846 Exchanges the object at index1 with the object at index2.
847 Raises an exception if either index is out of bounds. Returns self.
850 int i = IoMessage_locals_intArgAt_(m, locals, 0);
851 int j = IoMessage_locals_intArgAt_(m, locals, 1);
853 IoList_checkIndex(self, m, 0, i, "List swapIndices");
854 IoList_checkIndex(self, m, 0, j, "List swapIndices");
855 List_swap_with_(DATA(self), i, j);
856 return self;
859 IoObject *IoList_reverse(IoList *self, IoObject *locals, IoMessage *m)
861 /*doc List reverse
862 Reverses the ordering of all the items in the receiver. Returns self.
865 List_reverse(DATA(self));
866 return self;
869 IoObject *IoList_preallocateToSize(IoList *self, IoObject *locals, IoMessage *m)
871 /*doc List preallocateToSize(aNumber)
872 Preallocates array memory to hold aNumber number of items.
875 int newSize = IoMessage_locals_intArgAt_(m, locals, 0);
876 List_preallocateToSize_(DATA(self), newSize);
877 return self;
880 // sorting -----------------------------------------------
882 typedef struct
884 IoState *state;
885 IoObject *locals;
886 IoMessage *exp;
887 List *list;
888 } MSortContext;
890 int MSortContext_compareForSort(MSortContext *self, int i, int j)
892 IoObject *a = List_at_(self->list, i);
893 IoObject *b = List_at_(self->list, j);
894 int r;
896 IoState_pushRetainPool(self->state);
898 a = IoMessage_locals_performOn_(self->exp, self->locals, a);
899 b = IoMessage_locals_performOn_(self->exp, self->locals, b);
900 r = IoObject_compare(a, b);
902 IoState_popRetainPool(self->state);
903 return r;
906 void MSortContext_swapForSort(MSortContext *self, int i, int j)
908 List_swap_with_(self->list, i, j);
911 IoObject *IoList_sortInPlace(IoList *self, IoObject *locals, IoMessage *m)
913 /*doc List sortInPlace(optionalExpression)
914 Sorts the list using the compare method on the items. Returns self.
915 If an optionalExpression is provided, the sort is done on the result of the evaluation
916 of the optionalExpression on each value.
919 if (IoMessage_argCount(m) == 0)
921 List_qsort(DATA(self), (ListSortCallback *)IoObject_sortCompare);
923 else
925 MSortContext sc;
926 MSortContext *sortContext = &sc;
927 sortContext->state = IOSTATE;
929 sortContext->list = DATA(self);
930 sortContext->locals = locals;
931 sortContext->exp = IoMessage_rawArgAt_(m, 0);
933 Sorting_context_comp_swap_size_type_(sortContext,
934 (SDSortCompareCallback *)MSortContext_compareForSort,
935 (SDSortSwapCallback *)MSortContext_swapForSort,
936 List_size(DATA(self)), SDQuickSort);
940 return self;
943 typedef struct
945 IoState *state;
946 IoObject *locals;
947 IoBlock *block;
948 IoMessage *blockMsg;
949 IoMessage *argMsg1;
950 IoMessage *argMsg2;
951 List *list;
952 } SortContext;
954 int SortContext_compareForSort(SortContext *self, int i, int j)
956 IoObject *cr;
957 IoState_pushRetainPool(self->state);
959 IoMessage_cachedResult_(self->argMsg1, LIST_AT_(self->list, i));
960 IoMessage_cachedResult_(self->argMsg2, LIST_AT_(self->list, j));
961 cr = IoBlock_activate(self->block, self->locals, self->locals, self->blockMsg, self->locals);
962 //cr = IoMessage_locals_performOn_(self->block->message, self->locals, self->locals);
964 IoState_popRetainPool(self->state);
965 return ISFALSE(cr) ? 1 : -1;
968 void SortContext_swapForSort(SortContext *self, int i, int j)
970 List_swap_with_(self->list, i, j);
973 IoObject *IoList_sortInPlaceBy(IoList *self, IoObject *locals, IoMessage *m)
975 /*doc List sortBy(aBlock)
976 Sort the list using aBlock as the compare function. Returns self.
979 SortContext sc;
980 SortContext *sortContext = &sc;
981 sortContext->state = IOSTATE;
983 sortContext->list = DATA(self);
984 sortContext->locals = locals;
985 sortContext->block = IoMessage_locals_blockArgAt_(m, locals, 0);
986 sortContext->blockMsg = IoMessage_new(IOSTATE);
987 sortContext->argMsg1 = IoMessage_new(IOSTATE);
988 sortContext->argMsg2 = IoMessage_new(IOSTATE);
990 IoMessage_addArg_(sortContext->blockMsg, sortContext->argMsg1);
991 IoMessage_addArg_(sortContext->blockMsg, sortContext->argMsg2);
993 Sorting_context_comp_swap_size_type_(sortContext,
994 (SDSortCompareCallback *)SortContext_compareForSort,
995 (SDSortSwapCallback *)SortContext_swapForSort,
996 List_size(DATA(self)), SDQuickSort);
998 return self;