diff --git a/.vs/deemon-v141.vcxproj b/.vs/deemon-v141.vcxproj index f23c3cd45..64a0653d3 100644 --- a/.vs/deemon-v141.vcxproj +++ b/.vs/deemon-v141.vcxproj @@ -267,6 +267,7 @@ + diff --git a/.vs/deemon-v141.vcxproj.filters b/.vs/deemon-v141.vcxproj.filters index d7cf3a849..3d58fd9e6 100644 --- a/.vs/deemon-v141.vcxproj.filters +++ b/.vs/deemon-v141.vcxproj.filters @@ -774,6 +774,9 @@ src\objects\seq + + src\objects\seq + src\objects\seq diff --git a/.vs/deemon-v142.vcxproj b/.vs/deemon-v142.vcxproj index 376680759..abbb99a7c 100644 --- a/.vs/deemon-v142.vcxproj +++ b/.vs/deemon-v142.vcxproj @@ -267,6 +267,7 @@ + diff --git a/.vs/deemon-v142.vcxproj.filters b/.vs/deemon-v142.vcxproj.filters index d7cf3a849..3d58fd9e6 100644 --- a/.vs/deemon-v142.vcxproj.filters +++ b/.vs/deemon-v142.vcxproj.filters @@ -774,6 +774,9 @@ src\objects\seq + + src\objects\seq + src\objects\seq diff --git a/include/deemon/list.h b/include/deemon/list.h index 3f7d118fe..83f16e3d7 100644 --- a/include/deemon/list.h +++ b/include/deemon/list.h @@ -141,13 +141,14 @@ DeeList_Pop(DeeObject *__restrict self, Dee_ssize_t index); DFUNDEF NONNULL((1)) bool DCALL DeeList_Clear(DeeObject *__restrict self); -/* Sort the given list ascendingly, or according to `key' */ -DFUNDEF WUNUSED NONNULL((1)) int DCALL -DeeList_Sort(DeeObject *self, DeeObject *key); +/* Sort the given list ascendingly, or according to `key' + * To use default sorting, pass `Dee_None' for `key' */ +DFUNDEF WUNUSED NONNULL((1, 4)) int DCALL +DeeList_Sort(DeeObject *self, size_t start, size_t end, DeeObject *key); /* Reverse the order of the elements of `self' */ DFUNDEF NONNULL((1)) void DCALL -DeeList_Reverse(DeeObject *__restrict self); +DeeList_Reverse(DeeObject *__restrict self, size_t start, size_t end); /* Remove all items matching `!!should(item)' * @return: * : The number of removed items. diff --git a/include/deemon/tuple.h b/include/deemon/tuple.h index 313aefc66..a8a8d18ee 100644 --- a/include/deemon/tuple.h +++ b/include/deemon/tuple.h @@ -99,6 +99,7 @@ DDATDEF DeeObject DeeTuple_Empty; #define Dee_return_empty_tuple Dee_return_reference_(Dee_EmptyTuple) DDATDEF DeeTypeObject DeeTuple_Type; +DDATDEF DeeTypeObject DeeNullableTuple_Type; /* Same as "DeeTuple_Type", but items are allowed to be NULL (meaning unbound) */ #define DeeTuple_Check(x) DeeObject_InstanceOfExact(x, &DeeTuple_Type) /* `Tuple' is final */ #define DeeTuple_CheckExact(x) DeeObject_InstanceOfExact(x, &DeeTuple_Type) @@ -129,7 +130,7 @@ DeeTuple_FreeUninitialized(DREF DeeTupleObject *__restrict self); /* Create a new tuple object from a sequence or iterator. */ DFUNDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeTuple_FromSequence(DeeObject *__restrict self); -DFUNDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeTuple_FromIterator(DeeObject *__restrict self); +DFUNDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeTuple_FromIterator(DeeObject *__restrict self); /* TODO: Deprecated */ /* Return a new tuple object containing the types of each object of the given tuple. */ DFUNDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeTuple_Types(DeeObject *__restrict self); diff --git a/src/deemon/linker-scripts/link-deemon-gcc-i386-cygwin.def b/src/deemon/linker-scripts/link-deemon-gcc-i386-cygwin.def index a27e40976..4db232e05 100644 --- a/src/deemon/linker-scripts/link-deemon-gcc-i386-cygwin.def +++ b/src/deemon/linker-scripts/link-deemon-gcc-i386-cygwin.def @@ -468,8 +468,8 @@ EXPORTS _DeeList_Pop@8=DeeList_Pop@8 _DeeList_RemoveIf@20=DeeList_RemoveIf@20 _DeeList_Resize@12=DeeList_Resize@12 - _DeeList_Reverse@4=DeeList_Reverse@4 - _DeeList_Sort@8=DeeList_Sort@8 + _DeeList_Reverse@12=DeeList_Reverse@12 + _DeeList_Sort@16=DeeList_Sort@16 _DeeMapFile_Fini@4=DeeMapFile_Fini@4 _DeeMapFile_InitFile@32=DeeMapFile_InitFile@32 _DeeMapFile_InitSysFd@32=DeeMapFile_InitSysFd@32 diff --git a/src/deemon/linker-scripts/link-deemon-msvc-i386-win32.def b/src/deemon/linker-scripts/link-deemon-msvc-i386-win32.def index 54d216c48..892bf8926 100644 --- a/src/deemon/linker-scripts/link-deemon-msvc-i386-win32.def +++ b/src/deemon/linker-scripts/link-deemon-msvc-i386-win32.def @@ -468,8 +468,8 @@ EXPORTS DeeList_Pop@8=_DeeList_Pop@8 DeeList_RemoveIf@20=_DeeList_RemoveIf@20 DeeList_Resize@12=_DeeList_Resize@12 - DeeList_Reverse@4=_DeeList_Reverse@4 - DeeList_Sort@8=_DeeList_Sort@8 + DeeList_Reverse@12=_DeeList_Reverse@12 + DeeList_Sort@16=_DeeList_Sort@16 DeeMapFile_Fini@4=_DeeMapFile_Fini@4 DeeMapFile_InitFile@32=_DeeMapFile_InitFile@32 DeeMapFile_InitSysFd@32=_DeeMapFile_InitSysFd@32 diff --git a/src/deemon/objects/list.c b/src/deemon/objects/list.c index 44430fd11..c7aa87ca4 100644 --- a/src/deemon/objects/list.c +++ b/src/deemon/objects/list.c @@ -2874,12 +2874,16 @@ list_shrink(List *me, size_t argc, DeeObject *const *argv) { /* Reverse the order of the elements of `self' */ PUBLIC NONNULL((1)) void DCALL -DeeList_Reverse(DeeObject *__restrict self) { +DeeList_Reverse(DeeObject *__restrict self, size_t start, size_t end) { List *me = (List *)self; DeeObject **lo, **hi; DeeList_LockWrite(me); - lo = DeeList_ELEM(me); - hi = lo + DeeList_SIZE(me); + if (end > me->l_list.ol_elemc) + end = me->l_list.ol_elemc; + if unlikely(start > end) + start = end; + lo = DeeList_ELEM(me) + start; + hi = DeeList_ELEM(me) + end; while (lo < hi) { DeeObject *temp; temp = *lo; @@ -2890,10 +2894,13 @@ DeeList_Reverse(DeeObject *__restrict self) { } PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL -list_reverse(List *me, size_t argc, DeeObject *const *argv) { - if (DeeArg_Unpack(argc, argv, ":reverse")) +list_reverse(List *me, size_t argc, DeeObject *const *argv, DeeObject *kw) { + size_t start = 0, end = (size_t)-1; + if (DeeArg_UnpackKw(argc, argv, kw, kwlist__start_end, + "|" UNPuSIZ UNPuSIZ ":reverse", + &start, &end)) goto err; - DeeList_Reverse((DeeObject *)me); + DeeList_Reverse((DeeObject *)me, start, end); return_none; err: return NULL; @@ -2901,31 +2908,50 @@ list_reverse(List *me, size_t argc, DeeObject *const *argv) { -/* Sort the given list ascendingly, or according to `key' */ -PUBLIC WUNUSED NONNULL((1)) int DCALL -DeeList_Sort(DeeObject *self, DeeObject *key) { +/* Sort the given list ascendingly, or according to `key' + * To use default sorting, pass `Dee_None' for `key' */ +PUBLIC WUNUSED NONNULL((1, 4)) int DCALL +DeeList_Sort(DeeObject *self, size_t start, size_t end, DeeObject *key) { List *me = (List *)self; DeeObject **oldv, **newv; - size_t oldc, objc; - objc = DeeList_SIZE_ATOMIC(me); + size_t oldc, objc, list_objc; + size_t used_start = start; + size_t used_end = end; + list_objc = DeeList_SIZE_ATOMIC(me); + if (used_end > list_objc) + used_end = list_objc; + if unlikely(used_start > used_end) + used_start = used_end; + objc = used_end - used_start; oldv = (DeeObject **)Dee_Mallocc(objc, sizeof(DeeObject *)); if unlikely(!oldv) goto err; again: DeeList_LockRead(me); - if unlikely(me->l_list.ol_elemc > objc) { - DeeObject **new_objv; - objc = me->l_list.ol_elemc; - DeeList_LockEndRead(me); - new_objv = (DeeObject **)Dee_Reallocc(oldv, objc, sizeof(DeeObject *)); - if unlikely(!new_objv) - goto err_oldv; - oldv = new_objv; - goto again; + if unlikely(me->l_list.ol_elemc != list_objc) { + size_t new_used_start = start; + size_t new_used_end = end; + list_objc = me->l_list.ol_elemc; + if (new_used_end > list_objc) + new_used_end = list_objc; + if unlikely(new_used_start > new_used_end) + new_used_start = new_used_end; + if (new_used_start != used_start || new_used_end != used_end) { + DeeObject **new_objv; + DeeList_LockEndRead(me); + new_objv = (DeeObject **)Dee_Reallocc(oldv, list_objc, sizeof(DeeObject *)); + if unlikely(!new_objv) + goto err_oldv; + oldv = new_objv; + used_start = new_used_start; + used_end = new_used_end; + oldc = used_end - used_start; + goto again; + } } /* Read all the old elements from the list. */ - Dee_Movrefv(oldv, me->l_list.ol_elemv, objc); + Dee_Movrefv(oldv, me->l_list.ol_elemv + used_start, objc); DeeList_LockEndRead(me); /* Allocate the new list */ @@ -2933,18 +2959,38 @@ DeeList_Sort(DeeObject *self, DeeObject *key) { if unlikely(!newv) goto err_oldv_elem; /* Do the actual sorting. */ - if unlikely(DeeSeq_MergeSort(newv, oldv, objc, key)) + if unlikely(!DeeNone_Check(key) + ? DeeSeq_SortVectorWithKey(objc, newv, oldv, key) + : DeeSeq_SortVector(objc, newv, oldv)) goto err_newv; - Dee_Free(oldv); - DeeList_LockWrite(me); - oldv = me->l_list.ol_elemv; - oldc = me->l_list.ol_elemc; - me->l_list.ol_elemc = objc; - me->l_list.ol_elemv = newv; - _DeeList_SetAlloc(me, objc); - DeeList_LockEndWrite(me); - Dee_Decrefv(oldv, oldc); - Dee_Free(oldv); + if likely(objc == list_objc) { + /* Likely case: sort the whole list (replace the entire vector) */ + Dee_Free(oldv); + DeeList_LockWrite(me); + oldv = me->l_list.ol_elemv; + oldc = me->l_list.ol_elemc; + me->l_list.ol_elemc = objc; + me->l_list.ol_elemv = newv; + _DeeList_SetAlloc(me, objc); + DeeList_LockEndWrite(me); + Dee_Decrefv(oldv, oldc); + Dee_Free(oldv); + } else { + /* Special case: only a sub-range of the list was sorted; must override that sub-range. */ + DeeList_LockWrite(me); + if unlikely(me->l_list.ol_elemc < (used_start + objc)) { + DeeList_LockEndWrite(me); + Dee_Decrefv(newv, objc); + Dee_Free(newv); + goto again; + } + memcpyc(oldv, me->l_list.ol_elemv + used_start, objc, sizeof(DREF DeeObject *)); + memcpyc(me->l_list.ol_elemv + used_start, newv, objc, sizeof(DREF DeeObject *)); + DeeList_LockEndWrite(me); + Dee_Decrefv(oldv, objc); + Dee_Free(oldv); + Dee_Free(newv); + } return 0; err_newv: Dee_Free(newv); @@ -2956,44 +3002,62 @@ DeeList_Sort(DeeObject *self, DeeObject *key) { return -1; } -PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL -DeeList_Sorted(DeeObject *self, DeeObject *key) { - List *me = (List *)self; +PRIVATE WUNUSED NONNULL((1, 4)) DREF DeeTupleObject *DCALL +DeeList_Sorted(List *me, size_t start, size_t end, DeeObject *key) { + DREF DeeTupleObject *result; DeeObject **oldv; - size_t objc; - DeeTupleObject *result; - objc = DeeList_SIZE_ATOMIC(me); + size_t oldc, objc, list_objc; + size_t used_start = start; + size_t used_end = end; + list_objc = DeeList_SIZE_ATOMIC(me); + if (used_end > list_objc) + used_end = list_objc; + if unlikely(used_start > used_end) + used_start = used_end; + objc = used_end - used_start; oldv = (DeeObject **)Dee_Mallocc(objc, sizeof(DeeObject *)); if unlikely(!oldv) goto err; again: DeeList_LockRead(me); - if unlikely(DeeList_SIZE(me) > objc) { - DeeObject **new_objv; - objc = DeeList_SIZE(me); - DeeList_LockEndRead(me); - new_objv = (DeeObject **)Dee_Reallocc(oldv, objc, sizeof(DeeObject *)); - if unlikely(!new_objv) - goto err_oldv; - oldv = new_objv; - goto again; + if unlikely(me->l_list.ol_elemc != list_objc) { + size_t new_used_start = start; + size_t new_used_end = end; + list_objc = me->l_list.ol_elemc; + if (new_used_end > list_objc) + new_used_end = list_objc; + if unlikely(new_used_start > new_used_end) + new_used_start = new_used_end; + if (new_used_start != used_start || new_used_end != used_end) { + DeeObject **new_objv; + DeeList_LockEndRead(me); + new_objv = (DeeObject **)Dee_Reallocc(oldv, list_objc, sizeof(DeeObject *)); + if unlikely(!new_objv) + goto err_oldv; + oldv = new_objv; + used_start = new_used_start; + used_end = new_used_end; + oldc = used_end - used_start; + goto again; + } } /* Read all the old elements from the list. */ - Dee_Movrefv(oldv, DeeList_ELEM(me), objc); + Dee_Movrefv(oldv, me->l_list.ol_elemv + used_start, objc); DeeList_LockEndRead(me); - /* Allocate the new list */ + /* Allocate the new tuple */ result = DeeTuple_NewUninitialized(objc); if unlikely(!result) goto err_oldv_elem; /* Do the actual sorting. */ - if (DeeSeq_MergeSort(DeeTuple_ELEM(result), oldv, objc, key)) - goto err_result; + if unlikely(key ? DeeSeq_SortVectorWithKey(objc, result->t_elem, oldv, key) + : DeeSeq_SortVector(objc, result->t_elem, oldv)) + goto err_oldv_elem_result; Dee_Free(oldv); - return (DeeObject *)result; -err_result: + return result; +err_oldv_elem_result: DeeTuple_FreeUninitialized(result); err_oldv_elem: Dee_Decrefv(oldv, objc); @@ -3007,27 +3071,29 @@ DeeList_Sorted(DeeObject *self, DeeObject *key) { PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL list_sort(List *me, size_t argc, DeeObject *const *argv, DeeObject *kw) { - DeeObject *key = NULL; - if (DeeArg_UnpackKw(argc, argv, kw, kwlist__key, "|o:sort", &key)) + size_t start = 0, end = (size_t)-1; + DeeObject *key = Dee_None; + if (DeeArg_UnpackKw(argc, argv, kw, kwlist__start_end_key, + "|" UNPuSIZ UNPuSIZ "o:sort", + &start, &end, &key)) goto err; - if (DeeNone_Check(key)) - key = NULL; - if (DeeList_Sort((DeeObject *)me, key)) + if unlikely(DeeList_Sort((DeeObject *)me, start, end, key)) goto err; return_none; err: return NULL; } -PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL +PRIVATE WUNUSED NONNULL((1)) DREF DeeTupleObject *DCALL list_sorted(List *me, size_t argc, DeeObject *const *argv, DeeObject *kw) { - DeeObject *key = NULL; - if (DeeArg_UnpackKw(argc, argv, kw, kwlist__key, "|o:sorted", &key)) + size_t start = 0, end = (size_t)-1; + DeeObject *key = Dee_None; + if (DeeArg_UnpackKw(argc, argv, kw, kwlist__start_end_key, + "|" UNPuSIZ UNPuSIZ "o:sorted", + &start, &end, &key)) goto err; - if (DeeNone_Check(key)) - key = NULL; - return DeeList_Sorted((DeeObject *)me, key); + return DeeList_Sorted(me, start, end, key); err: return NULL; } @@ -3139,16 +3205,14 @@ PRIVATE struct type_method tpconst list_methods[] = { "Same as ${this.pop(-1)}"), /* List ordering functions. */ - TYPE_METHOD_F("reverse", &list_reverse, METHOD_FNOREFESCAPE, - "()\n" - "Reverse the order of all the elements of @this List"), - TYPE_KWMETHOD_F("sort", &list_sort, METHOD_FNOREFESCAPE, - "()\n" - "(key:?DCallable)\n" + TYPE_KWMETHOD_F(STR_reverse, &list_reverse, METHOD_FNOREFESCAPE, + "(start=!0,end=!-1)\n" + "Reverse the order of all the elements of @this List"), + TYPE_KWMETHOD_F(STR_sort, &list_sort, METHOD_FNOREFESCAPE, + "(start=!0,end=!-1,key:?DCallable=!N)\n" "Sort the elements of @this List in ascending order, or in accordance to @key"), - TYPE_KWMETHOD_F("sorted", &list_sorted, METHOD_FNOREFESCAPE, - "->?S?O\n" - "(key:?DCallable)->?S?O\n" + TYPE_KWMETHOD_F(STR_sorted, &list_sorted, METHOD_FNOREFESCAPE, + "(start=!0,end=!-1,key:?DCallable=!N)->?S?O\n" "Return a sequence that contains all elements from @this sequence, " /**/ "but sorted in ascending order, or in accordance to @key\n" "The type of sequence returned is implementation-defined"), diff --git a/src/deemon/objects/seq.c b/src/deemon/objects/seq.c index e44a35e2f..13d572270 100644 --- a/src/deemon/objects/seq.c +++ b/src/deemon/objects/seq.c @@ -4041,12 +4041,14 @@ seq_rindex(DeeObject *self, size_t argc, DeeObject *const *argv, DeeObject *kw) PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL seq_reversed(DeeObject *self, size_t argc, DeeObject *const *argv, DeeObject *kw) { DREF DeeObject *result; - (void)kw; - if (DeeArg_Unpack(argc, argv, ":reversed")) + size_t start = 0, end = (size_t)-1; + if (DeeArg_UnpackKw(argc, argv, kw, kwlist__start_end, + "|" UNPuSIZ UNPuSIZ ":reverse", + &start, &end)) goto err; result = DeeList_FromSequence(self); if likely(result) - DeeList_Reverse(result); + DeeList_Reverse(result, start, end); return result; err: return NULL; @@ -4064,7 +4066,7 @@ seq_sorted(DeeObject *self, size_t argc, result = DeeList_FromSequence(self); if unlikely(!result) goto err; - if unlikely(DeeList_Sort(result, key)) + if unlikely(DeeList_Sort(result, 0, (size_t)-1, key)) Dee_Clear(result); return result; err: @@ -4408,12 +4410,20 @@ seq_resize(DeeObject *self, size_t argc, PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL seq_reverse(DeeObject *self, size_t argc, DeeObject *const *argv, DeeObject *kw) { + DREF DeeObject *reversed; (void)kw; if (DeeArg_Unpack(argc, argv, ":reverse")) goto err; - if (DeeSeq_Reverse(self)) + reversed = DeeList_FromSequence(self); + if unlikely(!reversed) goto err; + DeeList_Reverse(reversed, 0, (size_t)-1); + if unlikely(DeeObject_Assign(self, reversed)) + goto err_reversed; + Dee_Decref(reversed); return_none; +err_reversed: + Dee_Decref(reversed); err: return NULL; } @@ -4421,14 +4431,21 @@ seq_reverse(DeeObject *self, size_t argc, DeeObject *const *argv, DeeObject *kw) PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL seq_sort(DeeObject *self, size_t argc, DeeObject *const *argv, DeeObject *kw) { - DeeObject *key = NULL; + DREF DeeObject *sorted; + DeeObject *key = Dee_None; if (DeeArg_UnpackKw(argc, argv, kw, kwlist__key, "|o:sort", &key)) goto err; - if (DeeNone_Check(key)) - key = NULL; - if (DeeSeq_Sort(self, key)) + sorted = DeeList_FromSequence(self); + if unlikely(!sorted) goto err; + if unlikely(DeeList_Sort(sorted, 0, (size_t)-1, key)) + goto err_sorted; + if unlikely(DeeObject_Assign(self, sorted)) + goto err_sorted; + Dee_Decref(sorted); return_none; +err_sorted: + Dee_Decref(sorted); err: return NULL; } diff --git a/src/deemon/objects/seq/default-api-mutable-require-impl.c.inl b/src/deemon/objects/seq/default-api-mutable-require-impl.c.inl index 469f0f42f..db694f6bc 100644 --- a/src/deemon/objects/seq/default-api-mutable-require-impl.c.inl +++ b/src/deemon/objects/seq/default-api-mutable-require-impl.c.inl @@ -274,7 +274,7 @@ DECL_BEGIN #define LOCAL_DeeSeq_DefaultFooWithCallFooDataFunction DeeSeq_DefaultReversedWithCallReversedDataFunction #define LOCAL_DeeSeq_DefaultFooWithCallFooDataMethod DeeSeq_DefaultReversedWithCallReversedDataMethod #define LOCAL_DeeSeq_DefaultFooWithCallFooDataKwMethod DeeSeq_DefaultReversedWithCallReversedDataKwMethod -#define LOCAL_DeeSeq_DefaultFooWithError DeeSeq_DefaultReversedWithProxyCopyDefault +#define LOCAL_DeeSeq_DefaultFooWithError DeeSeq_DefaultReversedWithCopyForeachDefault #elif defined(DEFINE_DeeType_SeqCache_RequireSort) #define LOCAL_CANONICAL_NAME sort #define LOCAL_generic_seq_foo generic_seq_sort @@ -304,7 +304,7 @@ DECL_BEGIN #define LOCAL_DeeSeq_DefaultFooWithCallFooDataFunction DeeSeq_DefaultSortedWithCallSortedDataFunction #define LOCAL_DeeSeq_DefaultFooWithCallFooDataMethod DeeSeq_DefaultSortedWithCallSortedDataMethod #define LOCAL_DeeSeq_DefaultFooWithCallFooDataKwMethod DeeSeq_DefaultSortedWithCallSortedDataKwMethod -#define LOCAL_DeeSeq_DefaultFooWithError DeeSeq_DefaultSortedWithEnumerateDefaultAndCopy +#define LOCAL_DeeSeq_DefaultFooWithError DeeSeq_DefaultSortedWithCopyForeachDefault #elif defined(DEFINE_DeeType_SeqCache_RequireSortedWithKey) #define LOCAL_CANONICAL_NAME sorted #define LOCAL_generic_seq_foo generic_seq_sorted @@ -314,7 +314,7 @@ DECL_BEGIN #define LOCAL_DeeSeq_DefaultFooWithCallFooDataFunction DeeSeq_DefaultSortedWithKeyWithCallSortedDataFunction #define LOCAL_DeeSeq_DefaultFooWithCallFooDataMethod DeeSeq_DefaultSortedWithKeyWithCallSortedDataMethod #define LOCAL_DeeSeq_DefaultFooWithCallFooDataKwMethod DeeSeq_DefaultSortedWithKeyWithCallSortedDataKwMethod -#define LOCAL_DeeSeq_DefaultFooWithError DeeSeq_DefaultSortedWithKeyWithEnumerateDefaultAndCopy +#define LOCAL_DeeSeq_DefaultFooWithError DeeSeq_DefaultSortedWithKeyWithCopyForeachDefault #else /* DEFINE_DeeType_SeqCache_Require... */ #error "Invalid configuration" #endif /* !DEFINE_DeeType_SeqCache_Require... */ @@ -656,7 +656,7 @@ LOCAL_DeeType_SeqCache_RequireFoo_private_uncached(DeeTypeObject *orig_type, Dee return &DeeSeq_DefaultReversedWithProxySizeAndGetItemIndex; } if (DeeType_HasPrivateOperator(self, OPERATOR_ITER)) - return &DeeSeq_DefaultReversedWithProxyCopyDefault; /* non-Default would also be OK */ + return &DeeSeq_DefaultReversedWithCopyForeachDefault; /* non-Default would also be OK */ #elif defined(DEFINE_DeeType_SeqCache_RequireSort) if (DeeType_HasPrivateOperator(self, OPERATOR_SETRANGE)) return &DeeSeq_DefaultSortWithTSCSortedAndSetRangeIndex; @@ -674,11 +674,25 @@ LOCAL_DeeType_SeqCache_RequireFoo_private_uncached(DeeTypeObject *orig_type, Dee DeeType_HasOperator(orig_type, OPERATOR_SIZE)) return &DeeSeq_DefaultSortWithKeyWithSizeAndGetItemIndexAndSetItemIndex; #elif defined(DEFINE_DeeType_SeqCache_RequireSorted) + if (DeeType_GetSeqClass(self) == Dee_SEQCLASS_SEQ && + DeeType_HasPrivateOperator(self, OPERATOR_GETITEM) && + DeeType_HasOperator(orig_type, OPERATOR_SIZE)) { + if (orig_type->tp_seq->tp_getitem_index_fast) + return &DeeSeq_DefaultSortedWithCopySizeAndGetItemIndexFast; + return &DeeSeq_DefaultSortedWithCopySizeAndTryGetItemIndex; + } if (DeeType_HasPrivateOperator(self, OPERATOR_ITER)) - return &DeeSeq_DefaultSortedWithEnumerateDefaultAndCopy; /* non-Default would also be OK */ + return &DeeSeq_DefaultSortedWithCopyForeachDefault; /* non-Default would also be OK */ #elif defined(DEFINE_DeeType_SeqCache_RequireSortedWithKey) + if (DeeType_GetSeqClass(self) == Dee_SEQCLASS_SEQ && + DeeType_HasPrivateOperator(self, OPERATOR_GETITEM) && + DeeType_HasOperator(orig_type, OPERATOR_SIZE)) { + if (orig_type->tp_seq->tp_getitem_index_fast) + return &DeeSeq_DefaultSortedWithKeyWithCopySizeAndGetItemIndexFast; + return &DeeSeq_DefaultSortedWithKeyWithCopySizeAndTryGetItemIndex; + } if (DeeType_HasPrivateOperator(self, OPERATOR_ITER)) - return &DeeSeq_DefaultSortedWithKeyWithEnumerateDefaultAndCopy; /* non-Default would also be OK */ + return &DeeSeq_DefaultSortedWithKeyWithCopyForeachDefault; /* non-Default would also be OK */ #endif /* ... */ return NULL; } diff --git a/src/deemon/objects/seq/default-api-mutable.c b/src/deemon/objects/seq/default-api-mutable.c index ecd9b7c69..8e301885f 100644 --- a/src/deemon/objects/seq/default-api-mutable.c +++ b/src/deemon/objects/seq/default-api-mutable.c @@ -45,6 +45,7 @@ /**/ #include "default-reversed.h" #include "repeat.h" +#include "sort.h" /**/ #include "../../runtime/kwlist.h" @@ -1685,7 +1686,7 @@ DeeSeq_DefaultReversedWithProxySizeAndGetItemIndexFast(DeeObject *self, size_t s goto err; if (end > selfsize) end = selfsize; - if (start > end) + if unlikely(start > end) start = end; result = DeeObject_MALLOC(DefaultReversed_WithGetItemIndex); if unlikely(!result) @@ -1710,7 +1711,7 @@ DeeSeq_DefaultReversedWithProxySizeAndGetItemIndex(DeeObject *self, size_t start goto err; if (end > selfsize) end = selfsize; - if (start > end) + if unlikely(start > end) start = end; result = DeeObject_MALLOC(DefaultReversed_WithGetItemIndex); if unlikely(!result) @@ -1735,7 +1736,7 @@ DeeSeq_DefaultReversedWithProxySizeAndTryGetItemIndex(DeeObject *self, size_t st goto err; if (end > selfsize) end = selfsize; - if (start > end) + if unlikely(start > end) start = end; result = DeeObject_MALLOC(DefaultReversed_WithGetItemIndex); if unlikely(!result) @@ -1751,16 +1752,95 @@ DeeSeq_DefaultReversedWithProxySizeAndTryGetItemIndex(DeeObject *self, size_t st return NULL; } -INTERN WUNUSED NONNULL((1)) DREF DeeObject *DCALL -DeeSeq_DefaultReversedWithProxyCopyDefault(DeeObject *self, size_t start, size_t end) { - /* TODO */ - (void)self; - (void)start; - (void)end; - DeeError_NOTIMPLEMENTED(); +struct foreach_subrange_as_tuple_data { + DREF DeeTupleObject *fesrat_result; /* [1..1] The tuple being constructed. */ + size_t fesrat_used; /* Used # of elements of `fesrat_result' */ + size_t fesrat_maxsize; /* Max value for `fesrat_used' */ + size_t fesrat_start; /* # of elements that still need to be skipped. */ +}; + +PRIVATE WUNUSED NONNULL((1, 2)) Dee_ssize_t DCALL +foreach_subrange_as_tuple_cb(void *arg, DeeObject *elem) { + struct foreach_subrange_as_tuple_data *data; + data = (struct foreach_subrange_as_tuple_data *)arg; + if (data->fesrat_start) { + --data->fesrat_start; /* Skip leading. */ + return 0; + } + if (data->fesrat_used >= DeeTuple_SIZE(data->fesrat_result)) { + DREF DeeTupleObject *new_tuple; + size_t new_size = DeeTuple_SIZE(data->fesrat_result) * 2; + if (new_size < 16) + new_size = 16; + new_tuple = DeeTuple_TryResizeUninitialized(data->fesrat_result, new_size); + if unlikely(!new_tuple) { + new_size = data->fesrat_used + 1; + new_tuple = DeeTuple_ResizeUninitialized(data->fesrat_result, new_size); + if unlikely(!new_tuple) + goto err; + } + data->fesrat_result = new_tuple; + } + Dee_Incref(elem); + data->fesrat_result->t_elem[data->fesrat_used++] = elem; + if (data->fesrat_used >= data->fesrat_maxsize) + return -2; /* Stop enumeration */ + return 0; +err: + return -1; +} + + +PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL +DeeSeq_GetForeachSubRangeAsTuple(DeeObject *self, size_t start, size_t end) { + size_t fast_size; + Dee_ssize_t foreach_status; + struct foreach_subrange_as_tuple_data data; + if unlikely(start >= end) + return_empty_tuple; + fast_size = (*Dee_TYPE(self)->tp_seq->tp_size_fast)(self); + if (fast_size != (size_t)-1) { + data.fesrat_result = DeeTuple_NewUninitialized(fast_size); + if unlikely(!data.fesrat_result) + goto err; + } else { + Dee_Incref(Dee_EmptyTuple); + data.fesrat_result = (DREF DeeTupleObject *)Dee_EmptyTuple; + } + data.fesrat_used = 0; + data.fesrat_maxsize = end - start; + data.fesrat_start = start; + foreach_status = (*Dee_TYPE(self)->tp_seq->tp_foreach)(self, &foreach_subrange_as_tuple_cb, &data); + ASSERT(foreach_status == 0 || foreach_status == -1); + if unlikely(foreach_status < 0) + goto err_r; + data.fesrat_result = DeeTuple_TruncateUninitialized(data.fesrat_result, data.fesrat_used); + return (DREF DeeObject *)data.fesrat_result; +err_r: + Dee_Decrefv(data.fesrat_result->t_elem, data.fesrat_used); + DeeTuple_FreeUninitialized(data.fesrat_result); +err: return NULL; } +INTERN WUNUSED NONNULL((1)) DREF DeeObject *DCALL +DeeSeq_DefaultReversedWithCopyForeachDefault(DeeObject *self, size_t start, size_t end) { + DREF DeeObject *result; + result = DeeSeq_GetForeachSubRangeAsTuple(self, start, end); + if likely(result) { + DREF DeeObject **lo, **hi; + lo = DeeTuple_ELEM(result); + hi = lo + DeeTuple_SIZE(result); + while (lo < hi) { + DeeObject *temp; + temp = *lo; + *lo++ = *--hi; + *hi = temp; + } + } + return result; +} + /************************************************************************/ /* sort() */ @@ -1832,13 +1912,80 @@ DeeSeq_DefaultSortWithKeyWithError(DeeObject *self, size_t start, size_t end, De /************************************************************************/ /* sorted() */ /************************************************************************/ +INTERN WUNUSED NONNULL((1, 4)) DREF DeeObject *DCALL +DeeSeq_DefaultSortedWithCopySizeAndGetItemIndexFast(DeeObject *self, size_t start, size_t end) { + size_t selfsize; + DREF DeeTupleObject *result; + struct type_seq *seq = Dee_TYPE(self)->tp_seq; + selfsize = (*seq->tp_size)(self); + if unlikely(selfsize == (size_t)-1) + goto err; + if (end > selfsize) + end = selfsize; + if unlikely(start > end) + start = end; + result = DeeTuple_NewUninitialized(end - start); + if unlikely(!result) + goto err; + if unlikely(DeeSeq_SortGetItemIndexFast(DeeTuple_SIZE(result), DeeTuple_ELEM(result), + self, start, seq->tp_getitem_index_fast)) + goto err_r; + if unlikely(DeeTuple_GET(result, 0) == NULL) { + /* Must trim unbound items (which were sorted to the start of the tuple) */ + + } + return (DREF DeeObject *)result; +err_r: + DeeTuple_FreeUninitialized(result); +err: + return NULL; +} + +INTERN WUNUSED NONNULL((1, 4)) DREF DeeObject *DCALL +DeeSeq_DefaultSortedWithCopySizeAndTryGetItemIndex(DeeObject *self, size_t start, size_t end) { + size_t selfsize; + DREF DeeTupleObject *result; + struct type_seq *seq = Dee_TYPE(self)->tp_seq; + selfsize = (*seq->tp_size)(self); + if unlikely(selfsize == (size_t)-1) + goto err; + if (end > selfsize) + end = selfsize; + if unlikely(start > end) + start = end; + result = DeeTuple_NewUninitialized(end - start); + if unlikely(!result) + goto err; + if unlikely(DeeSeq_SortTryGetItemIndex(DeeTuple_SIZE(result), DeeTuple_ELEM(result), + self, start, seq->tp_trygetitem_index)) + goto err_r; + return (DREF DeeObject *)result; +err_r: + DeeTuple_FreeUninitialized(result); +err: + return NULL; +} + INTERN WUNUSED NONNULL((1)) DREF DeeObject *DCALL -DeeSeq_DefaultSortedWithEnumerateDefaultAndCopy(DeeObject *self, size_t start, size_t end) { - /* TODO */ - (void)self; - (void)start; - (void)end; - DeeError_NOTIMPLEMENTED(); +DeeSeq_DefaultSortedWithCopyForeachDefault(DeeObject *self, size_t start, size_t end) { + DREF DeeTupleObject *base, *result; + base = (DREF DeeTupleObject *)DeeSeq_GetForeachSubRangeAsTuple(self, start, end); + if unlikely(!base) + goto err; + result = DeeTuple_NewUninitialized(DeeTuple_SIZE(base)); + if unlikely(!result) + goto err_base; + if unlikely(DeeSeq_SortVector(DeeTuple_SIZE(result), + DeeTuple_ELEM(result), + DeeTuple_ELEM(base))) + goto err_base_r; + DeeTuple_FreeUninitialized(base); + return (DREF DeeObject *)result; +err_base_r: + DeeTuple_FreeUninitialized(result); +err_base: + Dee_Decref(base); +err: return NULL; } @@ -1847,13 +1994,76 @@ DeeSeq_DefaultSortedWithEnumerateDefaultAndCopy(DeeObject *self, size_t start, s /* sorted() (with key) */ /************************************************************************/ INTERN WUNUSED NONNULL((1, 4)) DREF DeeObject *DCALL -DeeSeq_DefaultSortedWithKeyWithEnumerateDefaultAndCopy(DeeObject *self, size_t start, size_t end, DeeObject *key) { - /* TODO */ - (void)self; - (void)start; - (void)end; - (void)key; - DeeError_NOTIMPLEMENTED(); +DeeSeq_DefaultSortedWithKeyWithCopySizeAndGetItemIndexFast(DeeObject *self, size_t start, size_t end, DeeObject *key) { + size_t selfsize; + DREF DeeTupleObject *result; + struct type_seq *seq = Dee_TYPE(self)->tp_seq; + selfsize = (*seq->tp_size)(self); + if unlikely(selfsize == (size_t)-1) + goto err; + if (end > selfsize) + end = selfsize; + if unlikely(start > end) + start = end; + result = DeeTuple_NewUninitialized(end - start); + if unlikely(!result) + goto err; + if unlikely(DeeSeq_SortGetItemIndexFastWithKey(DeeTuple_SIZE(result), DeeTuple_ELEM(result), + self, start, seq->tp_getitem_index_fast, key)) + goto err_r; + return (DREF DeeObject *)result; +err_r: + DeeTuple_FreeUninitialized(result); +err: + return NULL; +} + +INTERN WUNUSED NONNULL((1, 4)) DREF DeeObject *DCALL +DeeSeq_DefaultSortedWithKeyWithCopySizeAndTryGetItemIndex(DeeObject *self, size_t start, size_t end, DeeObject *key) { + size_t selfsize; + DREF DeeTupleObject *result; + struct type_seq *seq = Dee_TYPE(self)->tp_seq; + selfsize = (*seq->tp_size)(self); + if unlikely(selfsize == (size_t)-1) + goto err; + if (end > selfsize) + end = selfsize; + if unlikely(start > end) + start = end; + result = DeeTuple_NewUninitialized(end - start); + if unlikely(!result) + goto err; + if unlikely(DeeSeq_SortTryGetItemIndexWithKey(DeeTuple_SIZE(result), DeeTuple_ELEM(result), + self, start, seq->tp_trygetitem_index, key)) + goto err_r; + return (DREF DeeObject *)result; +err_r: + DeeTuple_FreeUninitialized(result); +err: + return NULL; +} + +INTERN WUNUSED NONNULL((1, 4)) DREF DeeObject *DCALL +DeeSeq_DefaultSortedWithKeyWithCopyForeachDefault(DeeObject *self, size_t start, size_t end, DeeObject *key) { + DREF DeeObject *base; + DREF DeeTupleObject *result; + base = DeeSeq_GetForeachSubRangeAsTuple(self, start, end); + if unlikely(!base) + goto err; + result = DeeTuple_NewUninitialized(DeeTuple_SIZE(base)); + if unlikely(!result) + goto err_base; + if unlikely(DeeSeq_SortVectorWithKey(DeeTuple_SIZE(result), + DeeTuple_ELEM(result), + DeeTuple_ELEM(base), + key)) + goto err_base_r; + return (DREF DeeObject *)result; +err_base_r: + DeeTuple_FreeUninitialized(result); +err_base: + Dee_Decref(base); +err: return NULL; } diff --git a/src/deemon/objects/seq/default-api.h b/src/deemon/objects/seq/default-api.h index 6f7db2e33..000daf0c4 100644 --- a/src/deemon/objects/seq/default-api.h +++ b/src/deemon/objects/seq/default-api.h @@ -521,7 +521,7 @@ INTDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeSeq_DefaultReversedWithCall INTDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeSeq_DefaultReversedWithProxySizeAndGetItemIndexFast(DeeObject *self, size_t start, size_t end); INTDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeSeq_DefaultReversedWithProxySizeAndGetItemIndex(DeeObject *self, size_t start, size_t end); INTDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeSeq_DefaultReversedWithProxySizeAndTryGetItemIndex(DeeObject *self, size_t start, size_t end); -INTDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeSeq_DefaultReversedWithProxyCopyDefault(DeeObject *self, size_t start, size_t end); +INTDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeSeq_DefaultReversedWithCopyForeachDefault(DeeObject *self, size_t start, size_t end); INTDEF WUNUSED NONNULL((1)) int DCALL DeeSeq_DefaultSortWithCallAttrSort(DeeObject *self, size_t start, size_t end); INTDEF WUNUSED NONNULL((1)) int DCALL DeeSeq_DefaultSortWithCallSortDataFunction(DeeObject *self, size_t start, size_t end); @@ -543,13 +543,17 @@ INTDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeSeq_DefaultSortedWithCallAt INTDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeSeq_DefaultSortedWithCallSortedDataFunction(DeeObject *self, size_t start, size_t end); INTDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeSeq_DefaultSortedWithCallSortedDataMethod(DeeObject *self, size_t start, size_t end); INTDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeSeq_DefaultSortedWithCallSortedDataKwMethod(DeeObject *self, size_t start, size_t end); -INTDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeSeq_DefaultSortedWithProxyCopyDefault(DeeObject *self, size_t start, size_t end); +INTDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeSeq_DefaultSortedWithCopySizeAndGetItemIndexFast(DeeObject *self, size_t start, size_t end); +INTDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeSeq_DefaultSortedWithCopySizeAndTryGetItemIndex(DeeObject *self, size_t start, size_t end); +INTDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeSeq_DefaultSortedWithCopyForeachDefault(DeeObject *self, size_t start, size_t end); INTDEF WUNUSED NONNULL((1, 4)) DREF DeeObject *DCALL DeeSeq_DefaultSortedWithKeyWithCallAttrSorted(DeeObject *self, size_t start, size_t end, DeeObject *key); INTDEF WUNUSED NONNULL((1, 4)) DREF DeeObject *DCALL DeeSeq_DefaultSortedWithKeyWithCallSortedDataFunction(DeeObject *self, size_t start, size_t end, DeeObject *key); INTDEF WUNUSED NONNULL((1, 4)) DREF DeeObject *DCALL DeeSeq_DefaultSortedWithKeyWithCallSortedDataMethod(DeeObject *self, size_t start, size_t end, DeeObject *key); INTDEF WUNUSED NONNULL((1, 4)) DREF DeeObject *DCALL DeeSeq_DefaultSortedWithKeyWithCallSortedDataKwMethod(DeeObject *self, size_t start, size_t end, DeeObject *key); -INTDEF WUNUSED NONNULL((1, 4)) DREF DeeObject *DCALL DeeSeq_DefaultSortedWithKeyWithProxyCopyDefault(DeeObject *self, size_t start, size_t end, DeeObject *key); +INTDEF WUNUSED NONNULL((1, 4)) DREF DeeObject *DCALL DeeSeq_DefaultSortedWithKeyWithCopySizeAndGetItemIndexFast(DeeObject *self, size_t start, size_t end, DeeObject *key); +INTDEF WUNUSED NONNULL((1, 4)) DREF DeeObject *DCALL DeeSeq_DefaultSortedWithKeyWithCopySizeAndTryGetItemIndex(DeeObject *self, size_t start, size_t end, DeeObject *key); +INTDEF WUNUSED NONNULL((1, 4)) DREF DeeObject *DCALL DeeSeq_DefaultSortedWithKeyWithCopyForeachDefault(DeeObject *self, size_t start, size_t end, DeeObject *key); diff --git a/src/deemon/objects/seq/sort-impl.c.inl b/src/deemon/objects/seq/sort-impl.c.inl new file mode 100644 index 000000000..afbccf247 --- /dev/null +++ b/src/deemon/objects/seq/sort-impl.c.inl @@ -0,0 +1,593 @@ +/* Copyright (c) 2018-2024 Griefer@Work * + * * + * This software is provided 'as-is', without any express or implied * + * warranty. In no event will the authors be held liable for any damages * + * arising from the use of this software. * + * * + * Permission is granted to anyone to use this software for any purpose, * + * including commercial applications, and to alter it and redistribute it * + * freely, subject to the following restrictions: * + * * + * 1. The origin of this software must not be misrepresented; you must not * + * claim that you wrote the original software. If you use this software * + * in a product, an acknowledgement (see the following) in the product * + * documentation is required: * + * Portions Copyright (c) 2018-2024 Griefer@Work * + * 2. Altered source versions must be plainly marked as such, and must not be * + * misrepresented as being the original software. * + * 3. This notice may not be removed or altered from any source distribution. * + */ +#ifdef __INTELLISENSE__ +#include "sort.c" +//#define DEFINE_DeeSeq_SortVector +#define DEFINE_DeeSeq_SortVectorWithKey +//#define DEFINE_DeeSeq_SortGetItemIndexFast +//#define DEFINE_DeeSeq_SortGetItemIndexFastWithKey +//#define DEFINE_DeeSeq_SortTryGetItemIndex +//#define DEFINE_DeeSeq_SortTryGetItemIndexWithKey +#endif /* __INTELLISENSE__ */ + +#if (defined(DEFINE_DeeSeq_SortVector) + \ + defined(DEFINE_DeeSeq_SortVectorWithKey) + \ + defined(DEFINE_DeeSeq_SortGetItemIndexFast) + \ + defined(DEFINE_DeeSeq_SortGetItemIndexFastWithKey) + \ + defined(DEFINE_DeeSeq_SortTryGetItemIndex) + \ + defined(DEFINE_DeeSeq_SortTryGetItemIndexWithKey)) != 1 +#error "Must #define exactly one of these macros" +#endif /* DEFINE_DeeSeq_Sort... */ + +DECL_BEGIN + +#ifdef DEFINE_DeeSeq_SortVector +#define LOCAL_DeeSeq_Sort DeeSeq_SortVector +#define LOCAL_HAS_VECTOR +#elif defined(DEFINE_DeeSeq_SortVectorWithKey) +#define LOCAL_DeeSeq_Sort DeeSeq_SortVectorWithKey +#define LOCAL_HAS_VECTOR +#define LOCAL_HAS_KEY +#elif defined(DEFINE_DeeSeq_SortGetItemIndexFast) +#define LOCAL_DeeSeq_Sort DeeSeq_SortGetItemIndexFast +#define LOCAL_HAS_GETITEM +#define LOCAL_HAS_GETITEM_FAST +#elif defined(DEFINE_DeeSeq_SortGetItemIndexFastWithKey) +#define LOCAL_DeeSeq_Sort DeeSeq_SortGetItemIndexFastWithKey +#define LOCAL_HAS_GETITEM +#define LOCAL_HAS_GETITEM_FAST +#define LOCAL_HAS_KEY +#elif defined(DEFINE_DeeSeq_SortTryGetItemIndex) +#define LOCAL_DeeSeq_Sort DeeSeq_SortTryGetItemIndex +#define LOCAL_HAS_GETITEM +#elif defined(DEFINE_DeeSeq_SortTryGetItemIndexWithKey) +#define LOCAL_DeeSeq_Sort DeeSeq_SortTryGetItemIndexWithKey +#define LOCAL_HAS_GETITEM +#define LOCAL_HAS_KEY +#else /* DEFINE_DeeSeq_Sort... */ +#error "Invalid configuration" +#endif /* !DEFINE_DeeSeq_Sort... */ + +#define F(x) PP_CAT3(LOCAL_DeeSeq_Sort, _impl__, x) + +#define LOCAL_mergesort_impl F(mergesort_impl) +#define LOCAL_mergesort_impl_with_key_cache F(mergesort_impl_with_key_cache) +#define LOCAL_insertsort_impl F(insertsort_impl) + +#ifdef LOCAL_HAS_KEY +#define LOCAL__PARAM_KEY , DeeObject *key +#define LOCAL__ARG_KEY , key +#define LOCAL_DeeObject_CmpLoAsBool(lhs, rhs) \ + DeeObject_CmpLoAsBoolWithKey(lhs, rhs, key) +#ifndef DeeObject_CmpLoAsBoolWithKey_DEFINED +#define DeeObject_CmpLoAsBoolWithKey_DEFINED +PRIVATE WUNUSED NONNULL((1, 2, 3)) int DCALL +DeeObject_CmpLoAsBoolWithKey(DeeObject *lhs, DeeObject *rhs, DeeObject *key) { + int result; + lhs = DeeObject_Call(key, 1, (DeeObject **)&lhs); + if unlikely(!lhs) + goto err; + rhs = DeeObject_Call(key, 1, (DeeObject **)&rhs); + if unlikely(!rhs) + goto err_lhs; + result = DeeObject_CmpLoAsBool(lhs, rhs); + Dee_Decref(rhs); + Dee_Decref(lhs); + return result; +err_lhs: + Dee_Decref(lhs); +err: + return -1; +} +#endif /* !DeeObject_CmpLoAsBoolWithKey_DEFINED */ +#else /* LOCAL_HAS_KEY */ +#define LOCAL__PARAM_KEY /* nothing */ +#define LOCAL__ARG_KEY /* nothing */ +#define LOCAL_DeeObject_CmpLoAsBool(lhs, rhs) \ + DeeObject_CmpLoAsBool(lhs, rhs) +#endif /* !LOCAL_HAS_KEY */ + + +#ifdef LOCAL_HAS_GETITEM_FAST +#define LOCAL_PARAM_SRC DeeObject *src, size_t src_start, DREF DeeObject *(DCALL *src_getitem_index_fast)(DeeObject *__restrict self, size_t index) +#define LOCAL_ARG_SRC(skip) src, src_start + (skip), src_getitem_index_fast +#define LOCAL_GETITEM(i) (*src_getitem_index_fast)(src, src_start + (i)) +#define LOCAL_GETITEM_UNBOUND NULL +#define LOCAL_GETITEM_ISREF +#elif defined(LOCAL_HAS_GETITEM) +#define LOCAL_PARAM_SRC DeeObject *src, size_t src_start, DREF DeeObject *(DCALL *src_trygetitem_index)(DeeObject *__restrict self, size_t index) +#define LOCAL_ARG_SRC(skip) src, src_start + (skip), src_trygetitem_index +#define LOCAL_GETITEM(i) (*src_trygetitem_index)(src, src_start + (i)) +#define LOCAL_GETITEM_UNBOUND ITER_DONE +#define LOCAL_GETITEM_ERROR NULL +#define LOCAL_GETITEM_ISREF +#elif defined(LOCAL_HAS_VECTOR) +#define LOCAL_PARAM_SRC /*inherit(on_success)*/ DREF DeeObject *const *__restrict src +#define LOCAL_ARG_SRC(skip) src + (skip) +#define LOCAL_GETITEM(i) src[i] +#else /* ... */ +#error "Invalid configuration" +#endif /* !... */ + + +#ifdef LOCAL_GETITEM_ISREF +#define LOCAL_IF_GETITEM_ISREF(...) __VA_ARGS__ +#else /* LOCAL_GETITEM_ISREF */ +#define LOCAL_IF_GETITEM_ISREF(...) /* nothing */ +#endif /* !LOCAL_GETITEM_ISREF */ + +#ifdef LOCAL_GETITEM_UNBOUND +#define LOCAL_DecrefIfNotUnbound(x) \ + do { \ + if ((x) != LOCAL_GETITEM_UNBOUND) \ + Dee_Decref(x); \ + } __WHILE0 +#define LOCAL_DecrefvIfNotUnbound(v, s) \ + do { \ + size_t _i; \ + for (_i = 0; _i < (s); ++_i) { \ + DeeObject *_o = (v)[_i]; \ + if (_o != LOCAL_GETITEM_UNBOUND) \ + Dee_Decref(_o); \ + } \ + } __WHILE0 +#else /* LOCAL_GETITEM_UNBOUND */ +#define LOCAL_DecrefIfNotUnbound(x) Dee_Decref(x) +#define LOCAL_DecrefvIfNotUnbound(v, s) Dee_Decrefv(v, s) +#endif /* !LOCAL_GETITEM_UNBOUND */ + + +PRIVATE WUNUSED ATTR_OUTS(2, 1) int DCALL +LOCAL_mergesort_impl(size_t objc, DREF DeeObject **__restrict dst, + DeeObject **__restrict scratch, /* Scratch buffer area */ + LOCAL_PARAM_SRC LOCAL__PARAM_KEY) { + int error; + switch (objc) { + + case 1: { + DREF DeeObject *src0; + src0 = LOCAL_GETITEM(0); +#ifdef LOCAL_GETITEM_ERROR + if unlikely(src0 == LOCAL_GETITEM_ERROR) + goto err; +#endif /* LOCAL_GETITEM_ERROR */ + dst[0] = src0; + } break; + + case 2: { /* Optimization for sorting 2 objects. */ + int src0_lo_src1; + DREF DeeObject *src0, *src1; + src0 = LOCAL_GETITEM(0); +#ifdef LOCAL_GETITEM_ERROR + if unlikely(src0 == LOCAL_GETITEM_ERROR) + goto err; +#endif /* LOCAL_GETITEM_ERROR */ + src1 = LOCAL_GETITEM(1); +#ifdef LOCAL_GETITEM_ERROR + if unlikely(src1 == LOCAL_GETITEM_ERROR) { + LOCAL_IF_GETITEM_ISREF(LOCAL_DecrefIfNotUnbound(src0)); + goto err; + } +#endif /* LOCAL_GETITEM_ERROR */ +#ifdef LOCAL_GETITEM_UNBOUND + if (src0 == LOCAL_GETITEM_UNBOUND) { + src0_lo_src1 = src1 == LOCAL_GETITEM_UNBOUND ? 0 : 1; + } else if (src1 == LOCAL_GETITEM_UNBOUND) { + src0_lo_src1 = 0; + } else +#endif /* LOCAL_GETITEM_UNBOUND */ + { + src0_lo_src1 = LOCAL_DeeObject_CmpLoAsBool(src0, src1); + } + if (src0_lo_src1 <= 0) { + if unlikely(src0_lo_src1 < 0) + goto err; + dst[0] = src1; /* Inherit reference */ + dst[1] = src0; /* Inherit reference */ + } else { + dst[0] = src0; /* Inherit reference */ + dst[1] = src1; /* Inherit reference */ + } + } break; + + default: { + size_t s1, s2; + DREF DeeObject **iter1; + DREF DeeObject **iter2; + s1 = objc / 2; + s2 = objc - s1; + error = LOCAL_mergesort_impl(s1, scratch, dst, LOCAL_ARG_SRC(0) LOCAL__ARG_KEY); + if unlikely(error < 0) + goto err; + error = LOCAL_mergesort_impl(s2, scratch + s1, dst + s1, LOCAL_ARG_SRC(s1) LOCAL__ARG_KEY); + if unlikely(error < 0) { + LOCAL_IF_GETITEM_ISREF(LOCAL_DecrefvIfNotUnbound(scratch, s1)); + goto err; + } + iter1 = scratch; + iter2 = scratch + s1; + while (s1 && s2) { + DREF DeeObject *iter1_value = *iter1; + DREF DeeObject *iter2_value = *iter2; +#ifdef LOCAL_GETITEM_UNBOUND + if (iter1_value == LOCAL_GETITEM_UNBOUND) { + error = iter2_value == LOCAL_GETITEM_UNBOUND ? 0 : 1; + } else if (iter2_value == LOCAL_GETITEM_UNBOUND) { + error = 0; + } else +#endif /* LOCAL_GETITEM_UNBOUND */ + { + error = LOCAL_DeeObject_CmpLoAsBool(iter1_value, iter2_value); + } + if (error <= 0) { + if unlikely(error < 0) { + LOCAL_IF_GETITEM_ISREF(LOCAL_DecrefvIfNotUnbound(scratch, objc)); + goto err; + } + *dst = iter2_value; + ++iter2; + --s2; + } else { + *dst = iter1_value; + ++iter1; + --s1; + } + ++dst; + } + if (s1) { + ASSERT(!s2); + memcpyc(dst, iter1, s1, sizeof(DREF DeeObject *)); + } else if (s2) { + memcpyc(dst, iter2, s2, sizeof(DREF DeeObject *)); + } + } break; + + } + return 0; +err: + return -1; +} + +#ifdef LOCAL_HAS_KEY +PRIVATE WUNUSED ATTR_OUTS(2, 1) ATTR_OUTS(3, 1) int DCALL +LOCAL_mergesort_impl_with_key_cache(size_t objc, + DREF DeeObject **__restrict dst, + DREF DeeObject **__restrict dst_keyed, + DeeObject **__restrict scratch, /* Scratch buffer area */ + DeeObject **__restrict scratch_keyed, /* Scratch buffer area */ + LOCAL_PARAM_SRC LOCAL__PARAM_KEY) { + int error; + switch (objc) { + + case 1: { + DREF DeeObject *src0; + src0 = LOCAL_GETITEM(0); +#ifdef LOCAL_GETITEM_ERROR + if unlikely(src0 == LOCAL_GETITEM_ERROR) + goto err; +#endif /* LOCAL_GETITEM_ERROR */ + dst[0] = src0; +#ifdef LOCAL_GETITEM_UNBOUND + if (src0 == LOCAL_GETITEM_UNBOUND) { + dst_keyed[0] = LOCAL_GETITEM_UNBOUND; + } else +#endif /* LOCAL_GETITEM_UNBOUND */ + { + dst_keyed[0] = DeeObject_Call(key, 1, &dst[0]); + if unlikely(!dst_keyed[0]) { + LOCAL_IF_GETITEM_ISREF(LOCAL_DecrefIfNotUnbound(dst[0])); + goto err; + } + } + } break; + + case 2: { /* Optimization for sorting 2 objects. */ + int src0_lo_src1; + DREF DeeObject *src0, *src1; + DREF DeeObject *src0_keyed, *src1_keyed; + src0 = LOCAL_GETITEM(0); +#ifdef LOCAL_GETITEM_ERROR + if unlikely(src0 == LOCAL_GETITEM_ERROR) + goto err; +#endif /* LOCAL_GETITEM_ERROR */ + src1 = LOCAL_GETITEM(1); +#ifdef LOCAL_GETITEM_ERROR + if unlikely(src1 == LOCAL_GETITEM_ERROR) + goto err_src0; +#endif /* LOCAL_GETITEM_ERROR */ +#ifdef LOCAL_GETITEM_UNBOUND + if (src0 == LOCAL_GETITEM_UNBOUND) { + src0_keyed = LOCAL_GETITEM_UNBOUND; + if (src1 == LOCAL_GETITEM_UNBOUND) { + src0_lo_src1 = 0; + src1_keyed = LOCAL_GETITEM_UNBOUND; + } else { + src0_lo_src1 = 1; + src1_keyed = DeeObject_Call(key, 1, &src1); + if unlikely(!src1_keyed) + goto err_src0_src1; + } + } else if (src1 == LOCAL_GETITEM_UNBOUND) { + src0_lo_src1 = 0; + src0_keyed = DeeObject_Call(key, 1, &src0); + if unlikely(!src0_keyed) + goto err_src0_src1; + src1_keyed = LOCAL_GETITEM_UNBOUND; + } else +#endif /* LOCAL_GETITEM_UNBOUND */ + { + src0_keyed = DeeObject_Call(key, 1, &src0); + if unlikely(!src0_keyed) + goto err_src0_src1; + src1_keyed = DeeObject_Call(key, 1, &src1); + if unlikely(!src1_keyed) { + Dee_Decref(src0_keyed); +err_src0_src1: + LOCAL_IF_GETITEM_ISREF(LOCAL_DecrefIfNotUnbound(src1)); +#ifdef LOCAL_GETITEM_ERROR +err_src0: +#endif /* LOCAL_GETITEM_ERROR */ + LOCAL_IF_GETITEM_ISREF(LOCAL_DecrefIfNotUnbound(src0)); + goto err; + } + src0_lo_src1 = DeeObject_CmpLoAsBool(src0_keyed, src1_keyed); + } + if (src0_lo_src1 <= 0) { + if unlikely(src0_lo_src1 < 0) + goto err; + dst[0] = src1; /* Inherit reference */ + dst[1] = src0; /* Inherit reference */ + dst_keyed[0] = src1_keyed; /* Inherit reference */ + dst_keyed[1] = src0_keyed; /* Inherit reference */ + } else { + dst[0] = src0; /* Inherit reference */ + dst[1] = src1; /* Inherit reference */ + dst_keyed[0] = src0_keyed; /* Inherit reference */ + dst_keyed[1] = src1_keyed; /* Inherit reference */ + } + } break; + + default: { + size_t s1, s2; + DREF DeeObject **iter1, **iter1_keyed; + DREF DeeObject **iter2, **iter2_keyed; + s1 = objc / 2; + s2 = objc - s1; + error = LOCAL_mergesort_impl_with_key_cache(s1, + scratch, scratch_keyed, + dst, dst_keyed, + LOCAL_ARG_SRC(0) LOCAL__ARG_KEY); + if unlikely(error < 0) + goto err; + error = LOCAL_mergesort_impl_with_key_cache(s2, + scratch + s1, scratch_keyed + s1, + dst + s1, dst_keyed + s1, + LOCAL_ARG_SRC(s1) LOCAL__ARG_KEY); + if unlikely(error < 0) { + LOCAL_IF_GETITEM_ISREF(LOCAL_DecrefvIfNotUnbound(scratch, s1)); + LOCAL_DecrefvIfNotUnbound(scratch_keyed, s1); + goto err; + } + iter1 = scratch; + iter1_keyed = scratch_keyed; + iter2 = scratch + s1; + iter2_keyed = scratch_keyed + s1; + while (s1 && s2) { +#ifdef LOCAL_GETITEM_UNBOUND + if (*iter1_keyed == LOCAL_GETITEM_UNBOUND) { + error = *iter2_keyed == LOCAL_GETITEM_UNBOUND ? 0 : 1; + } else if (*iter2_keyed == LOCAL_GETITEM_UNBOUND) { + error = 0; + } else +#endif /* LOCAL_GETITEM_UNBOUND */ + { + error = DeeObject_CmpLoAsBool(*iter1_keyed, *iter2_keyed); + } + if (error <= 0) { + if unlikely(error < 0) { + LOCAL_IF_GETITEM_ISREF(LOCAL_DecrefvIfNotUnbound(scratch, objc)); + LOCAL_DecrefvIfNotUnbound(scratch_keyed, objc); + goto err; + } + *dst++ = *iter2++; + *dst_keyed++ = *iter2_keyed++; + --s2; + } else { + *dst++ = *iter1++; + *dst_keyed++ = *iter1_keyed++; + --s1; + } + } + if (s1) { + ASSERT(!s2); + memcpyc(dst, iter1, s1, sizeof(DREF DeeObject *)); + memcpyc(dst_keyed, iter1_keyed, s1, sizeof(DREF DeeObject *)); + } else if (s2) { + memcpyc(dst, iter2, s2, sizeof(DREF DeeObject *)); + memcpyc(dst_keyed, iter2_keyed, s2, sizeof(DREF DeeObject *)); + } + } break; + + } + return 0; +err: + return -1; +} +#endif /* LOCAL_HAS_KEY */ + + +PRIVATE WUNUSED ATTR_OUTS(1, 2) int DCALL +LOCAL_insertsort_impl(DREF DeeObject **__restrict dst, size_t objc, + LOCAL_PARAM_SRC LOCAL__PARAM_KEY) { + int temp; + size_t i, j; + for (i = 0; i < objc; ++i) { + DREF DeeObject *ob = LOCAL_GETITEM(i); +#ifdef LOCAL_GETITEM_ERROR + if unlikely(ob == LOCAL_GETITEM_ERROR) + goto err_dst_i; +#endif /* LOCAL_GETITEM_ERROR */ + j = 0; +#ifdef LOCAL_GETITEM_UNBOUND + if (ob != LOCAL_GETITEM_UNBOUND) +#endif /* LOCAL_GETITEM_UNBOUND */ + { +#ifdef LOCAL_HAS_KEY + DREF DeeObject *keyed_ob = DeeObject_Call(key, 1, &ob); + if unlikely(!keyed_ob) { + LOCAL_IF_GETITEM_ISREF(Dee_Decref(ob)); + goto err_dst_i; + } +#endif /* LOCAL_HAS_KEY */ + for (; j < i; ++j) { + /* Check if we need to insert the object in this location. */ +#ifdef LOCAL_HAS_KEY + DREF DeeObject *keyed_dst_j; + keyed_dst_j = DeeObject_Call(key, 1, &dst[j]); + if unlikely(!keyed_dst_j) { +err_dst_i_keyed_ob: + Dee_Decref(keyed_ob); + goto err_dst_i; + } + temp = DeeObject_CmpLoAsBool(ob, keyed_dst_j); + Dee_Decref(keyed_dst_j); + if unlikely(temp < 0) + goto err_dst_i_keyed_ob; +#else /* LOCAL_HAS_KEY */ + temp = DeeObject_CmpLoAsBool(ob, dst[j]); + if unlikely(temp < 0) + goto err_dst_i; +#endif /* !LOCAL_HAS_KEY */ + if (temp > 0) + break; + } + } + memmoveupc(&dst[j + 1], &dst[j], i - j, sizeof(DREF DeeObject *)); + dst[j] = ob; + } + return 0; +err_dst_i: + LOCAL_IF_GETITEM_ISREF(LOCAL_DecrefvIfNotUnbound(dst, i)); + return -1; +} + +INTERN WUNUSED ATTR_OUTS(2, 1) int DCALL +LOCAL_DeeSeq_Sort(size_t objc, DREF DeeObject **__restrict dst, + LOCAL_PARAM_SRC LOCAL__PARAM_KEY) { + int result = 0; + switch (objc) { + + case 0: + break; + + case 1: { + DREF DeeObject *src0; + src0 = LOCAL_GETITEM(0); +#ifdef LOCAL_GETITEM_ERROR + if unlikely(src0 == LOCAL_GETITEM_ERROR) + goto err; +#endif /* LOCAL_GETITEM_ERROR */ + dst[0] = src0; + } break; + + case 2: { /* Optimization for sorting 2 objects. */ + int src0_lo_src1; + DREF DeeObject *src0, *src1; + src0 = LOCAL_GETITEM(0); +#ifdef LOCAL_GETITEM_ERROR + if unlikely(src0 == LOCAL_GETITEM_ERROR) + goto err; +#endif /* LOCAL_GETITEM_ERROR */ + src1 = LOCAL_GETITEM(1); +#ifdef LOCAL_GETITEM_ERROR + if unlikely(src1 == LOCAL_GETITEM_ERROR) { + LOCAL_IF_GETITEM_ISREF(LOCAL_DecrefIfNotUnbound(src0)); + goto err; + } +#endif /* LOCAL_GETITEM_ERROR */ + src0_lo_src1 = LOCAL_DeeObject_CmpLoAsBool(src0, src1); + if (src0_lo_src1 <= 0) { + if unlikely(src0_lo_src1 < 0) + goto err; + dst[0] = src1; /* Inherit reference */ + dst[1] = src0; /* Inherit reference */ + } else { + dst[0] = src0; /* Inherit reference */ + dst[1] = src1; /* Inherit reference */ + } + } break; + + default: { + DREF DeeObject **scratch; +#ifdef LOCAL_HAS_KEY + scratch = (DeeObject **)Dee_TryMallocc(objc * 3, sizeof(DeeObject *)); + if likely(scratch) { + result = LOCAL_mergesort_impl_with_key_cache(objc, dst, scratch, scratch + objc, scratch + objc * 2, + LOCAL_ARG_SRC(0) LOCAL__ARG_KEY); + if likely(result == 0) /* Drop references still held on cached keys */ + LOCAL_DecrefvIfNotUnbound(scratch, objc); + Dee_Free(scratch); + } else +#endif /* LOCAL_HAS_KEY */ + { + scratch = (DeeObject **)Dee_TryMallocc(objc, sizeof(DeeObject *)); + if likely(scratch) { + result = LOCAL_mergesort_impl(objc, dst, scratch, LOCAL_ARG_SRC(0) LOCAL__ARG_KEY); + Dee_Free(scratch); + } else { + result = LOCAL_insertsort_impl(dst, objc, LOCAL_ARG_SRC(0) LOCAL__ARG_KEY); + } + } + } break; + } + return result; +err: + return -1; +} + +#undef LOCAL_DecrefIfNotUnbound +#undef LOCAL_DecrefvIfNotUnbound +#undef LOCAL_IF_GETITEM_ISREF +#undef LOCAL__PARAM_KEY +#undef LOCAL__ARG_KEY +#undef LOCAL_DeeObject_CmpLoAsBool +#undef LOCAL_PARAM_SRC +#undef LOCAL_ARG_SRC +#undef LOCAL_GETITEM +#undef LOCAL_GETITEM_UNBOUND +#undef LOCAL_GETITEM_ERROR +#undef LOCAL_GETITEM_ISREF +#undef LOCAL_mergesort_impl +#undef LOCAL_insertsort_impl +#undef F +#undef LOCAL_DeeSeq_Sort +#undef LOCAL_HAS_VECTOR +#undef LOCAL_HAS_KEY +#undef LOCAL_HAS_GETITEM +#undef LOCAL_HAS_GETITEM_FAST + +DECL_END + +#undef DEFINE_DeeSeq_SortVector +#undef DEFINE_DeeSeq_SortVectorWithKey +#undef DEFINE_DeeSeq_SortGetItemIndexFast +#undef DEFINE_DeeSeq_SortGetItemIndexFastWithKey +#undef DEFINE_DeeSeq_SortTryGetItemIndex +#undef DEFINE_DeeSeq_SortTryGetItemIndexWithKey diff --git a/src/deemon/objects/seq/sort.c b/src/deemon/objects/seq/sort.c index 6955d3ade..9dcdc5129 100644 --- a/src/deemon/objects/seq/sort.c +++ b/src/deemon/objects/seq/sort.c @@ -23,344 +23,25 @@ #include #include #include -#include #include -#include -#include - -DECL_BEGIN - -PRIVATE WUNUSED ATTR_OUTS(1, 4) ATTR_INS(3, 4) int DCALL -mergesort_impl(DREF DeeObject **__restrict dst, - DeeObject **__restrict temp, - DREF DeeObject *const *__restrict src, - size_t objc) { - int error; - switch (objc) { - - case 0: - break; - - case 1: - dst[0] = src[0]; - break; - - case 2: - error = DeeObject_CmpLoAsBool(src[0], src[1]); - if unlikely(error < 0 && - !DeeError_Catch(&DeeError_TypeError) && - !DeeError_Catch(&DeeError_NotImplemented)) - goto err; - if (error <= 0) { - dst[0] = src[1]; - dst[1] = src[0]; - } else { - dst[0] = src[0]; - dst[1] = src[1]; - } - break; - - default: { - size_t s1, s2; - DeeObject **iter1; - DeeObject **iter2; - s1 = objc / 2; - s2 = objc - s1; - error = mergesort_impl(temp, dst, src, s1); - if unlikely(error < 0) - goto err; - error = mergesort_impl(temp + s1, dst + s1, src + s1, s2); - if unlikely(error < 0) - goto err; - iter1 = temp; - iter2 = temp + s1; - while (s1 && s2) { - error = DeeObject_CmpLoAsBool(*iter1, *iter2); - if unlikely(error < 0) { - if (!DeeError_Catch(&DeeError_TypeError) && - !DeeError_Catch(&DeeError_NotImplemented)) - goto err; - } - if (error <= 0) { - *dst++ = *iter2++; - --s2; - } else { - *dst++ = *iter1++; - --s1; - } - } - if (s1) { - ASSERT(!s2); - memcpyc(dst, iter1, s1, - sizeof(DREF DeeObject *)); - } else if (s2) { - memcpyc(dst, iter2, s2, - sizeof(DREF DeeObject *)); - } - } break; - - } - return 0; -err: - return -1; -} - - -PRIVATE WUNUSED NONNULL((1, 2, 3)) int DCALL -compare_lo(DeeObject *lhs, DeeObject *rhs, DeeObject *key) { - int result; - lhs = DeeObject_Call(key, 1, (DeeObject **)&lhs); - if unlikely(!lhs) - goto err; - rhs = DeeObject_Call(key, 1, (DeeObject **)&rhs); - if unlikely(!rhs) - goto err_lhs; - result = DeeObject_CmpLoAsBool(lhs, rhs); - Dee_Decref(rhs); - Dee_Decref(lhs); - return result; -err_lhs: - Dee_Decref(lhs); -err: - return -1; -} - -PRIVATE WUNUSED ATTR_OUTS(1, 4) ATTR_INS(3, 4) NONNULL((5)) int DCALL -mergesort_impl_p(DREF DeeObject **__restrict dst, - DeeObject **__restrict temp, - DREF DeeObject *const *__restrict src, - size_t objc, - DeeObject *key) { - int error; - switch (objc) { - - case 0: - break; - - case 1: - dst[0] = src[0]; - break; - - case 2: - error = compare_lo(src[0], src[1], key); - if (error <= 0) { - if unlikely(error < 0 && - !DeeError_Catch(&DeeError_TypeError) && - !DeeError_Catch(&DeeError_NotImplemented)) - goto err; - dst[0] = src[1]; - dst[1] = src[0]; - } else { - dst[0] = src[0]; - dst[1] = src[1]; - } - break; - - default: { - size_t s1, s2; - DeeObject *const *iter1; - DeeObject *const *iter2; - s1 = objc / 2; - s2 = objc - s1; - error = mergesort_impl_p(temp, dst, src, s1, key); - if unlikely(error < 0) - goto err; - error = mergesort_impl_p(temp + s1, dst + s1, src + s1, s2, key); - if unlikely(error < 0) - goto err; - iter1 = temp; - iter2 = temp + s1; - while (s1 && s2) { - error = compare_lo(*iter1, *iter2, key); - if (error <= 0) { - if unlikely(error < 0 && - !DeeError_Catch(&DeeError_TypeError) && - !DeeError_Catch(&DeeError_NotImplemented)) - goto err; - *dst++ = *iter2++; - --s2; - } else { - *dst++ = *iter1++; - --s1; - } - } - if (s1) { - ASSERT(!s2); - memcpyc(dst, iter1, s1, - sizeof(DREF DeeObject *)); - } else if (s2) { - memcpyc(dst, iter2, s2, - sizeof(DREF DeeObject *)); - } - } break; - - } - return 0; -err: - return -1; -} - - - -PRIVATE WUNUSED ATTR_OUTS(1, 3) ATTR_INS(2, 3) int DCALL -insertsort_impl(DREF DeeObject **__restrict dst, - DREF DeeObject *const *__restrict src, - size_t objc) { - int temp; - size_t i, j; - for (i = 0; i < objc; ++i) { - DeeObject *ob = src[i]; - for (j = 0; j < i; ++j) { - /* Check if we need to insert the object in this location. */ - temp = DeeObject_CmpLoAsBool(ob, dst[j]); - if unlikely(temp < 0 && - !DeeError_Catch(&DeeError_TypeError) && - !DeeError_Catch(&DeeError_NotImplemented)) - goto err; - if (temp > 0) - break; - } - memmoveupc(&dst[j + 1], &dst[j], - i - j, sizeof(DREF DeeObject *)); - dst[j] = ob; - } - return 0; -err: - return -1; -} - -PRIVATE WUNUSED ATTR_OUTS(1, 3) ATTR_INS(2, 3) NONNULL((4)) int DCALL -insertsort_impl_p(DREF DeeObject **__restrict dst, - DREF DeeObject *const *__restrict src, - size_t objc, DeeObject *key) { - int temp; - size_t i, j; - for (i = 0; i < objc; ++i) { - DeeObject *src_ob = src[i]; - for (j = 0; j < i; ++j) { - /* Check if we need to insert the object in this location. */ - temp = compare_lo(src_ob, dst[j], key); - if unlikely(temp < 0 && - !DeeError_Catch(&DeeError_TypeError) && - !DeeError_Catch(&DeeError_NotImplemented)) - goto err; - if (temp > 0) - break; - } - memmoveupc(&dst[j + 1], &dst[j], - i - j, sizeof(DREF DeeObject *)); - dst[j] = src_ob; - } - return 0; -err: - return -1; -} - - - -INTERN WUNUSED ATTR_OUTS(1, 3) ATTR_INS(2, 3) int DCALL -DeeSeq_MergeSort(DREF DeeObject **__restrict dst, - DREF DeeObject *const *__restrict src, - size_t objc, DeeObject *key) { - int result = 0; - ASSERT(dst != src); - switch (objc) { - - case 0: - break; - - case 1: - dst[0] = src[0]; - break; - - case 2: { - int temp; - /* Optimization for sorting 2 objects. */ - temp = key - ? compare_lo(src[0], src[1], key) - : DeeObject_CmpLoAsBool(src[0], src[1]); - if (temp <= 0) { - if unlikely(temp < 0 && - !DeeError_Catch(&DeeError_TypeError) && - !DeeError_Catch(&DeeError_NotImplemented)) - goto err; - dst[0] = src[1]; - dst[1] = src[0]; - } else { - dst[0] = src[0]; - dst[1] = src[1]; - } - } break; - - default: { - DeeObject **temp; - /* Default case: Do an actual merge-sort. */ - temp = (DeeObject **)Dee_TryMallocc(objc, sizeof(DeeObject *)); - if unlikely(!temp) { - /* Use a fallback sorting function */ - result = key - ? insertsort_impl_p(dst, src, objc, key) - : insertsort_impl(dst, src, objc); - } else { - result = key - ? mergesort_impl_p(dst, temp, src, objc, key) - : mergesort_impl(dst, temp, src, objc); - Dee_Free(temp); - } - } break; - } - return result; -err: - return -1; -} - - - -INTERN WUNUSED ATTR_OUTS(1, 3) ATTR_INS(2, 3) int DCALL -DeeSeq_InsertionSort(DREF DeeObject **__restrict dst, - DREF DeeObject *const *__restrict src, - size_t objc, DeeObject *key) { - int result = 0; - ASSERT(dst != src); - switch (objc) { - - case 0: - break; - - case 1: - dst[0] = src[0]; - break; - - case 2: { - int temp; - /* Optimization for sorting 2 objects. */ - temp = key - ? compare_lo(src[0], src[1], key) - : DeeObject_CmpLoAsBool(src[0], src[1]); - if unlikely(temp < 0 && - !DeeError_Catch(&DeeError_TypeError) && - !DeeError_Catch(&DeeError_NotImplemented)) - goto err; - if (temp <= 0) { - dst[0] = src[0]; - dst[1] = src[1]; - } else { - dst[0] = src[1]; - dst[1] = src[0]; - } - } break; - - default: - result = key - ? insertsort_impl_p(dst, src, objc, key) - : insertsort_impl(dst, src, objc); - break; - } - return result; -err: - return -1; -} - -DECL_END +#include /* memcpyc */ +/**/ + +#include "sort.h" + +#ifndef __INTELLISENSE__ +#define DEFINE_DeeSeq_SortVector +#include "sort-impl.c.inl" +#define DEFINE_DeeSeq_SortVectorWithKey +#include "sort-impl.c.inl" +#define DEFINE_DeeSeq_SortGetItemIndexFast +#include "sort-impl.c.inl" +#define DEFINE_DeeSeq_SortGetItemIndexFastWithKey +#include "sort-impl.c.inl" +#define DEFINE_DeeSeq_SortTryGetItemIndex +#include "sort-impl.c.inl" +#define DEFINE_DeeSeq_SortTryGetItemIndexWithKey +#include "sort-impl.c.inl" +#endif /* !__INTELLISENSE__ */ #endif /* !GUARD_DEEMON_OBJECTS_SEQ_SORT_C */ diff --git a/src/deemon/objects/seq/sort.h b/src/deemon/objects/seq/sort.h index d51431dc3..dc9d888db 100644 --- a/src/deemon/objects/seq/sort.h +++ b/src/deemon/objects/seq/sort.h @@ -25,15 +25,13 @@ DECL_BEGIN -/* Vector-sorting functions. */ -INTDEF WUNUSED ATTR_OUTS(1, 3) ATTR_INS(2, 3) int DCALL -DeeSeq_MergeSort(DREF DeeObject **__restrict dst, - DREF DeeObject *const *__restrict src, - size_t objc, DeeObject *key); -INTDEF WUNUSED ATTR_OUTS(1, 3) ATTR_INS(2, 3) int DCALL -DeeSeq_InsertionSort(DREF DeeObject **__restrict dst, - DREF DeeObject *const *__restrict src, - size_t objc, DeeObject *key); +/* Generic sorting functions */ +INTDEF WUNUSED ATTR_OUTS(2, 1) ATTR_INS(3, 1) int DCALL DeeSeq_SortVector(size_t objc, DREF DeeObject **__restrict dst, /*inherit(on_success)*/ DREF DeeObject *const *__restrict src); /* source elements are never unbound */ +INTDEF WUNUSED ATTR_OUTS(2, 1) ATTR_INS(3, 1) NONNULL((4)) int DCALL DeeSeq_SortVectorWithKey(size_t objc, DREF DeeObject **__restrict dst, /*inherit(on_success)*/ DREF DeeObject *const *__restrict src, DeeObject *key); /* source elements are never unbound */ +INTDEF WUNUSED ATTR_OUTS(2, 1) NONNULL((3, 5)) int DCALL DeeSeq_SortGetItemIndexFast(size_t objc, DREF DeeObject **__restrict dst, DeeObject *src, size_t src_start, DREF DeeObject *(DCALL *src_getitem_index_fast)(DeeObject *__restrict self, size_t index)); +INTDEF WUNUSED ATTR_OUTS(2, 1) NONNULL((3, 5, 6)) int DCALL DeeSeq_SortGetItemIndexFastWithKey(size_t objc, DREF DeeObject **__restrict dst, DeeObject *src, size_t src_start, DREF DeeObject *(DCALL *src_getitem_index_fast)(DeeObject *__restrict self, size_t index), DeeObject *key); +INTDEF WUNUSED ATTR_OUTS(2, 1) NONNULL((3, 5)) int DCALL DeeSeq_SortTryGetItemIndex(size_t objc, DREF DeeObject **__restrict dst, DeeObject *src, size_t src_start, DREF DeeObject *(DCALL *src_trygetitem_index)(DeeObject *__restrict self, size_t index)); +INTDEF WUNUSED ATTR_OUTS(2, 1) NONNULL((3, 5, 6)) int DCALL DeeSeq_SortTryGetItemIndexWithKey(size_t objc, DREF DeeObject **__restrict dst, DeeObject *src, size_t src_start, DREF DeeObject *(DCALL *src_trygetitem_index)(DeeObject *__restrict self, size_t index), DeeObject *key); DECL_END diff --git a/src/deemon/objects/seq_functions.h b/src/deemon/objects/seq_functions.h index d23482feb..5019505b1 100644 --- a/src/deemon/objects/seq_functions.h +++ b/src/deemon/objects/seq_functions.h @@ -81,8 +81,6 @@ INTDEF WUNUSED NONNULL((1, 4)) int DCALL DeeSeq_RRemove(DeeObject *self, size_t INTDEF WUNUSED NONNULL((1, 4)) size_t DCALL DeeSeq_RemoveAll(DeeObject *self, size_t start, size_t end, DeeObject *elem, DeeObject *key); INTDEF WUNUSED NONNULL((1, 4)) size_t DCALL DeeSeq_RemoveIf(DeeObject *self, size_t start, size_t end, DeeObject *should); INTDEF WUNUSED NONNULL((1, 4)) size_t DCALL DeeSeq_Fill(DeeObject *self, size_t start, size_t end, DeeObject *value); -INTDEF WUNUSED NONNULL((1)) int DCALL DeeSeq_Reverse(DeeObject *__restrict self); -INTDEF WUNUSED NONNULL((1)) int DCALL DeeSeq_Sort(DeeObject *self, DeeObject *key); /* Determine if a given sequence is mutable or resizable. * @return: 1: The sequence is mutable or resizable. diff --git a/src/deemon/objects/seq_mutable.c b/src/deemon/objects/seq_mutable.c index 36a728db4..80794c466 100644 --- a/src/deemon/objects/seq_mutable.c +++ b/src/deemon/objects/seq_mutable.c @@ -4275,41 +4275,6 @@ DeeSeq_Fill(DeeObject *self, size_t start, size_t end, return (size_t)-1; } -INTERN WUNUSED NONNULL((1)) int DCALL -DeeSeq_Reverse(DeeObject *__restrict self) { - int result; - DREF DeeObject *reversed; - reversed = DeeList_FromSequence(self); - if unlikely(!reversed) - goto err; - DeeList_Reverse(reversed); - result = DeeObject_Assign(self, reversed); - Dee_Decref(reversed); - return result; -err: - return -1; -} - -INTERN WUNUSED NONNULL((1)) int DCALL -DeeSeq_Sort(DeeObject *self, DeeObject *key) { - int result; - DREF DeeObject *sorted; - sorted = DeeList_FromSequence(self); - if unlikely(!sorted) - goto err; - if unlikely(DeeList_Sort(sorted, key)) - goto err_sorted; - result = DeeObject_Assign(self, sorted); - Dee_Decref(sorted); - return result; -err_sorted: - Dee_Decref(sorted); -err: - return -1; -} - - - PRIVATE DeeStringObject *tpconst mutable_sequence_attributes[] = { &str_remove, &str_rremove, diff --git a/src/deemon/objects/tuple.c b/src/deemon/objects/tuple.c index ebc94bc82..683454c73 100644 --- a/src/deemon/objects/tuple.c +++ b/src/deemon/objects/tuple.c @@ -43,6 +43,11 @@ #include +/**/ +#include "seq/sort.h" + +/**/ +#include "../runtime/kwlist.h" #include "../runtime/runtime_error.h" #include "../runtime/strings.h" @@ -1402,10 +1407,10 @@ tuple_deepcopy(Tuple *__restrict self) { PRIVATE WUNUSED DREF Tuple *DCALL tuple_init(size_t argc, DeeObject *const *argv) { - DeeObject *seq; - if (DeeArg_Unpack(argc, argv, "o:Tuple", &seq)) + DeeObject *items; + if (DeeArg_Unpack(argc, argv, "o:Tuple", &items)) goto err; - return (DREF Tuple *)DeeTuple_FromSequence(seq); + return (DREF Tuple *)DeeTuple_FromSequence(items); err: return NULL; } @@ -1471,7 +1476,7 @@ tuple_getitem(Tuple *self, DeeObject *index) { INTERN WUNUSED NONNULL((1)) DREF DeeObject *DCALL tuple_getrange_index(Tuple *__restrict self, - dssize_t begin, dssize_t end) { + Dee_ssize_t begin, Dee_ssize_t end) { size_t range_size; struct Dee_seq_range range; DeeSeqRange_Clamp(&range, begin, end, self->t_size); @@ -1483,7 +1488,7 @@ tuple_getrange_index(Tuple *__restrict self, INTERN WUNUSED NONNULL((1)) DREF DeeObject *DCALL tuple_getrange_index_n(Tuple *__restrict self, - dssize_t begin) { + Dee_ssize_t begin) { #ifdef __OPTIMIZE_SIZE__ return tuple_getrange_index(self, begin, SSIZE_MAX); #else /* __OPTIMIZE_SIZE__ */ @@ -1500,7 +1505,7 @@ PRIVATE WUNUSED NONNULL((1, 2, 3)) DREF DeeObject *DCALL tuple_getrange(Tuple *__restrict self, DeeObject *__restrict begin, DeeObject *__restrict end) { - dssize_t i_begin, i_end; + Dee_ssize_t i_begin, i_end; if (DeeObject_AsSSize(begin, &i_begin)) goto err; if (DeeNone_Check(end)) @@ -1536,6 +1541,13 @@ tuple_getitem_index_fast(Tuple *__restrict self, size_t index) { return_reference(self->t_elem[index]); } +PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL +tuple_trygetitem_index(Tuple *__restrict self, size_t index) { + if unlikely(index >= self->t_size) + return ITER_DONE; + return_reference(self->t_elem[index]); +} + PRIVATE WUNUSED NONNULL((1, 4)) size_t DCALL tuple_nsi_find(Tuple *__restrict self, size_t start, size_t end, DeeObject *__restrict keyed_search_item, @@ -1678,7 +1690,7 @@ PRIVATE struct type_seq tuple_seq = { /* .tp_delrange_index_n = */ NULL, /* .tp_setrange_index_n = */ NULL, /* .tp_trygetitem = */ NULL, - /* .tp_trygetitem_index = */ NULL, + /* .tp_trygetitem_index = */ (DREF DeeObject *(DCALL *)(DeeObject *, size_t))&tuple_trygetitem_index, /* .tp_trygetitem_string_hash = */ NULL, /* .tp_getitem_string_hash = */ NULL, /* .tp_delitem_string_hash = */ NULL, @@ -1735,11 +1747,11 @@ tuple_visit(Tuple *__restrict self, dvisit_t proc, void *arg) { /* Print all elements of the given tuple without any separators in-between * elements. This is equivalent to `Tuple.operator str' and is related to * the change introduced for handling `print("foo", "bar");'-like statements */ -INTERN WUNUSED NONNULL((1, 2)) dssize_t DCALL +INTERN WUNUSED NONNULL((1, 2)) Dee_ssize_t DCALL tuple_print(Tuple *__restrict self, Dee_formatprinter_t printer, void *arg) { size_t i; - dssize_t temp, result = 0; + Dee_ssize_t temp, result = 0; for (i = 0; i < DeeTuple_SIZE(self); ++i) { DeeObject *elem; elem = DeeTuple_GET(self, i); @@ -1788,7 +1800,7 @@ tuple_str(Tuple *__restrict self) { return NULL; } -INTERN WUNUSED NONNULL((1, 2)) dssize_t DCALL +PRIVATE WUNUSED NONNULL((1, 2)) Dee_ssize_t DCALL tuple_printrepr(Tuple *__restrict self, Dee_formatprinter_t printer, void *arg) { Dee_ssize_t temp, result; @@ -1890,10 +1902,44 @@ tuple_last(Tuple *__restrict self) { return NULL; } +INTDEF WUNUSED NONNULL((1)) DREF Tuple *DCALL +tuple_sorted(Tuple *self, size_t argc, DeeObject *const *argv, DeeObject *kw) { + DREF Tuple *result; + size_t start = 0, end = (size_t)-1; + DeeObject *key = Dee_None; + if (DeeArg_UnpackKw(argc, argv, kw, kwlist__start_end_key, + "|" UNPuSIZ UNPuSIZ "o:sorted", + &start, &end, &key)) + goto err; + if (end > self->t_size) + end = self->t_size; + if unlikely(start > end) + start = end; + result = DeeTuple_NewUninitialized(end - start); + if unlikely(!result) + goto err; + if unlikely(!DeeNone_Check(key) + ? DeeSeq_SortVectorWithKey(result->t_size, result->t_elem, self->t_elem + start, key) + : DeeSeq_SortVector(result->t_size, result->t_elem, self->t_elem + start)) + goto err_r; + Dee_Increfv(result->t_elem, result->t_size); + return result; +err_r: + DeeTuple_FreeUninitialized(result); +err: + return NULL; +} + + +PRIVATE struct type_method tpconst tuple_methods[] = { + TYPE_KWMETHOD(STR_sorted, &tuple_sorted, "(start=!0,end=!-1,key=!n)->?."), + TYPE_METHOD_END +}; PRIVATE struct type_getset tpconst tuple_getsets[] = { TYPE_GETTER_F_NODOC(STR_first, &tuple_first, METHOD_FNOREFESCAPE), TYPE_GETTER_F_NODOC(STR_last, &tuple_last, METHOD_FNOREFESCAPE), +#define nullable_tuple_getsets (tuple_getsets + 2) TYPE_GETTER(STR_frozen, &DeeObject_NewRef, "->?."), TYPE_GETTER_F("__sizeof__", &tuple_sizeof, METHOD_FNOREFESCAPE, "->?Dint"), TYPE_GETSET_END @@ -2207,8 +2253,8 @@ PUBLIC DeeTypeObject DeeTuple_Type = { /* .tp_str = */ (DREF DeeObject *(DCALL *)(DeeObject *__restrict))&tuple_str, /* .tp_repr = */ (DREF DeeObject *(DCALL *)(DeeObject *__restrict))&tuple_repr, /* .tp_bool = */ (int (DCALL *)(DeeObject *__restrict))&tuple_bool, - /* .tp_print = */ (dssize_t (DCALL *)(DeeObject *__restrict, dformatprinter, void *))&tuple_print, - /* .tp_printrepr = */ (dssize_t (DCALL *)(DeeObject *__restrict, dformatprinter, void *))&tuple_printrepr + /* .tp_print = */ (Dee_ssize_t (DCALL *)(DeeObject *__restrict, dformatprinter, void *))&tuple_print, + /* .tp_printrepr = */ (Dee_ssize_t (DCALL *)(DeeObject *__restrict, dformatprinter, void *))&tuple_printrepr }, /* .tp_call = */ NULL, /* .tp_visit = */ (void (DCALL *)(DeeObject *__restrict, dvisit_t, void *))&tuple_visit, @@ -2220,7 +2266,7 @@ PUBLIC DeeTypeObject DeeTuple_Type = { /* .tp_attr = */ NULL, /* .tp_with = */ NULL, /* .tp_buffer = */ NULL, - /* .tp_methods = */ NULL, + /* .tp_methods = */ tuple_methods, /* .tp_getsets = */ tuple_getsets, /* .tp_members = */ NULL, /* .tp_class_methods = */ tuple_class_methods, @@ -2242,6 +2288,296 @@ PUBLIC struct empty_tuple_object DeeTuple_Empty = { 0 }; + + + +PRIVATE struct empty_tuple_object DeeNullableTuple_Empty = { + OBJECT_HEAD_INIT(&DeeNullableTuple_Type), + 0 +}; + + +LOCAL ATTR_RETNONNULL WUNUSED NONNULL((1)) DREF DeeTupleObject *DCALL +make_nullable(DREF DeeTupleObject *__restrict self) { + if unlikely(self == (DREF DeeTupleObject *)Dee_EmptyTuple) { + Dee_DecrefNokill(Dee_EmptyTuple); + Dee_Incref(&DeeNullableTuple_Empty); + return (DREF DeeTupleObject *)&DeeNullableTuple_Empty; + } + Dee_DecrefNokill(&DeeTuple_Type); + Dee_Incref(&DeeNullableTuple_Type); + self->ob_type = &DeeNullableTuple_Type; + return self; +} + +PRIVATE WUNUSED NONNULL((1)) DREF Tuple *DCALL +nullable_tuple_unpack(DeeObject *UNUSED(self), size_t argc, DeeObject *const *argv) { + DREF Tuple *result; + size_t num_items; + DeeObject *init; + if (DeeArg_Unpack(argc, argv, UNPuSIZ "o:unpack", &num_items, &init)) + goto err; + result = DeeTuple_NewUninitialized(num_items); + if unlikely(!result) + goto done; + if unlikely(DeeObject_UnpackWithUnbound(init, num_items, DeeTuple_ELEM(result))) { + DeeTuple_FreeUninitialized(result); +err: + result = NULL; + } else { + result = make_nullable(result); + } +done: + return result; +} + + +PRIVATE WUNUSED DREF Tuple *DCALL nullable_tuple_ctor(void) { + return_reference_((DREF Tuple *)&DeeNullableTuple_Empty); +} + +INTERN WUNUSED NONNULL((1)) DREF Tuple *DCALL +nullable_tuple_deepcopy(Tuple *__restrict self) { + DREF Tuple *result; + size_t i, size = DeeTuple_SIZE(self); + result = DeeTuple_NewUninitialized(size); + if unlikely(!result) + goto err; + for (i = 0; i < size; ++i) { + DREF DeeObject *temp; + temp = DeeTuple_GET(self, i); + if (temp) { + temp = DeeObject_DeepCopy(DeeTuple_GET(self, i)); + if unlikely(!temp) + goto err_r; + } + DeeTuple_SET(result, i, temp); /* Inherit reference. */ + } + return make_nullable(result); +err_r: + Dee_XDecrefv_likely(DeeTuple_ELEM(result), i); + DeeTuple_FreeUninitialized(result); +err: + return NULL; +} + +PRIVATE WUNUSED DREF Tuple *DCALL +nullable_tuple_init(size_t argc, DeeObject *const *argv) { + DREF Tuple *result; + DeeObject *items; + if (DeeArg_Unpack(argc, argv, "o:NullableTuple", &items)) + goto err; + result = (DREF Tuple *)DeeTuple_FromSequence(items); + if likely(result) + result = make_nullable(result); + return result; +err: + return NULL; +} + +PRIVATE NONNULL((1)) void DCALL +nullable_tuple_fini(Tuple *__restrict self) { + Dee_XDecrefv(DeeTuple_ELEM(self), + DeeTuple_SIZE(self)); +} + +PRIVATE NONNULL((1, 2)) void DCALL +nullable_tuple_visit(Tuple *__restrict self, dvisit_t proc, void *arg) { + Dee_XVisitv(DeeTuple_ELEM(self), + DeeTuple_SIZE(self)); +} + +PRIVATE WUNUSED NONNULL((1, 2)) DREF DeeObject *DCALL +nullable_tuple_contains(Tuple *self, DeeObject *item) { + int error; + size_t i, mylen; + mylen = DeeTuple_SIZE(self); + for (i = 0; i < mylen; ++i) { + DeeObject *ob; + ob = DeeTuple_GET(self, i); + if (!ob) + continue; + error = DeeObject_TryCompareEq(item, ob); + if unlikely(error == Dee_COMPARE_ERR) + goto err; + if (error == 0) + return_true; + } + return_false; +err: + return NULL; +} + +#define nullable_tuple_enumerate_index \ + tuple_enumerate_index /* Actually works the same! */ + +PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL +nullable_tuple_getitem_index(Tuple *__restrict self, size_t index) { + if unlikely(index >= self->t_size) + goto err_bounds; + if (!self->t_elem[index]) + goto err_unbound; + return_reference(self->t_elem[index]); +err_unbound: + err_unbound_index((DeeObject *)self, index); + return NULL; +err_bounds: + err_index_out_of_bounds((DeeObject *)self, index, self->t_size); + return NULL; +} + +PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL +nullable_tuple_getitem_index_fast(Tuple *__restrict self, size_t index) { + DREF DeeObject *result; + ASSERT(index < self->t_size); + result = self->t_elem[index]; + Dee_XIncref(result); + return result; +} + +PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL +nullable_tuple_trygetitem_index(Tuple *__restrict self, size_t index) { + if unlikely(index >= self->t_size) + return ITER_DONE; + if (!self->t_elem[index]) + return ITER_DONE; + return_reference(self->t_elem[index]); +} + + +PRIVATE struct type_seq nullable_tuple_seq = { + /* .tp_iter = */ NULL, + /* .tp_sizeob = */ (DREF DeeObject *(DCALL *)(DeeObject *__restrict))&tuple_sizeob, + /* .tp_contains = */ (DREF DeeObject *(DCALL *)(DeeObject *, DeeObject *))&nullable_tuple_contains, + /* .tp_getitem = */ NULL, + /* .tp_delitem = */ NULL, + /* .tp_setitem = */ NULL, + /* .tp_getrange = */ NULL, + /* .tp_delrange = */ NULL, + /* .tp_setrange = */ NULL, + /* .tp_nsi = */ NULL, + /* .tp_foreach = */ NULL, + /* .tp_foreach_pair = */ NULL, + /* .tp_enumerate = */ NULL, + /* .tp_enumerate_index = */ (Dee_ssize_t (DCALL *)(DeeObject *__restrict, Dee_enumerate_index_t, void *, size_t, size_t))&nullable_tuple_enumerate_index, + /* .tp_bounditem = */ NULL, + /* .tp_hasitem = */ NULL, + /* .tp_size = */ (size_t (DCALL *)(DeeObject *__restrict))&tuple_size, + /* .tp_size_fast = */ (size_t (DCALL *)(DeeObject *__restrict))&tuple_size, + /* .tp_getitem_index = */ (DREF DeeObject *(DCALL *)(DeeObject *, size_t))&nullable_tuple_getitem_index, + /* .tp_getitem_index_fast = */ (DREF DeeObject *(DCALL *)(DeeObject *, size_t))&nullable_tuple_getitem_index_fast, + /* .tp_delitem_index = */ NULL, + /* .tp_setitem_index = */ NULL, + /* .tp_bounditem_index = */ NULL, + /* .tp_hasitem_index = */ NULL, + /* .tp_getrange_index = */ NULL, + /* .tp_delrange_index = */ NULL, + /* .tp_setrange_index = */ NULL, + /* .tp_getrange_index_n = */ NULL, + /* .tp_delrange_index_n = */ NULL, + /* .tp_setrange_index_n = */ NULL, + /* .tp_trygetitem = */ NULL, + /* .tp_trygetitem_index = */ (DREF DeeObject *(DCALL *)(DeeObject *, size_t))&nullable_tuple_trygetitem_index, + /* .tp_trygetitem_string_hash = */ NULL, + /* .tp_getitem_string_hash = */ NULL, + /* .tp_delitem_string_hash = */ NULL, + /* .tp_setitem_string_hash = */ NULL, + /* .tp_bounditem_string_hash = */ NULL, + /* .tp_hasitem_string_hash = */ NULL, + /* .tp_trygetitem_string_len_hash = */ NULL, + /* .tp_getitem_string_len_hash = */ NULL, + /* .tp_delitem_string_len_hash = */ NULL, + /* .tp_setitem_string_len_hash = */ NULL, + /* .tp_bounditem_string_len_hash = */ NULL, + /* .tp_hasitem_string_len_hash = */ NULL, +}; + +PRIVATE struct type_method tpconst nullable_tuple_class_methods[] = { + TYPE_METHOD("unpack", &nullable_tuple_unpack, + "(num:?Dint,seq:?S?O)->?.\n" + "#tUnpackError{The given @seq doesn't contain exactly @num elements}" + "Unpack the given sequence @seq into a Tuple consisting of @num elements.\n" + "Same as ?Aunpack?DTuple, except that unbound items are not silently skipped"), + TYPE_METHOD_END +}; + +PRIVATE struct type_member tpconst nullable_tuple_class_members[] = { + TYPE_MEMBER_CONST("Frozen", &DeeNullableTuple_Type), + TYPE_MEMBER_END +}; + +PRIVATE struct type_operator const nullable_tuple_operators[] = { + TYPE_OPERATOR_FLAGS(OPERATOR_0000_CONSTRUCTOR, METHOD_FCONSTCALL | METHOD_FCONSTCALL_IF_ARGSELEM_CONSTCAST), + TYPE_OPERATOR_FLAGS(OPERATOR_0001_COPY, METHOD_FCONSTCALL | METHOD_FNOTHROW), + TYPE_OPERATOR_FLAGS(OPERATOR_0002_DEEPCOPY, METHOD_FCONSTCALL | METHOD_FCONSTCALL_IF_THISELEM_CONSTDEEP | METHOD_FNOREFESCAPE), + TYPE_OPERATOR_FLAGS(OPERATOR_0008_BOOL, METHOD_FCONSTCALL | METHOD_FNOTHROW | METHOD_FNOREFESCAPE), + TYPE_OPERATOR_FLAGS(OPERATOR_0030_SIZE, METHOD_FCONSTCALL | METHOD_FNOREFESCAPE), + TYPE_OPERATOR_FLAGS(OPERATOR_0031_CONTAINS, METHOD_FCONSTCALL | METHOD_FCONSTCALL_IF_SEQ_CONSTCONTAINS | METHOD_FNOREFESCAPE), + TYPE_OPERATOR_FLAGS(OPERATOR_0032_GETITEM, METHOD_FCONSTCALL | METHOD_FCONSTCALL_IF_ARGS_CONSTCAST | METHOD_FNOREFESCAPE), + TYPE_OPERATOR_FLAGS(OPERATOR_0035_GETRANGE, METHOD_FCONSTCALL | METHOD_FCONSTCALL_IF_ARGS_CONSTCAST), +}; + +PUBLIC DeeTypeObject DeeNullableTuple_Type = { + OBJECT_HEAD_INIT(&DeeType_Type), + /* .tp_name = */ "NullableTuple", + /* .tp_doc = */ DOC("Same as ?DTuple, but able to represent unbound elements\n" + "\n" + + "()\n" + "Construct an empty ?.\n" + "\n" + + "(items:?S?O)\n" + "Construct a new ?. that is pre-initializes with the elements from @items"), + /* .tp_flags = */ TP_FNORMAL | TP_FVARIABLE | TP_FFINAL, + /* .tp_weakrefs = */ 0, + /* .tp_features = */ TF_NONE, + /* .tp_base = */ &DeeSeq_Type, + /* .tp_init = */ { + { + /* .tp_var = */ { + /* .tp_ctor = */ (dfunptr_t)&nullable_tuple_ctor, + /* .tp_copy_ctor = */ (dfunptr_t)&DeeObject_NewRef, + /* .tp_deep_ctor = */ (dfunptr_t)&nullable_tuple_deepcopy, + /* .tp_any_ctor = */ (dfunptr_t)&nullable_tuple_init, +#if CONFIG_TUPLE_CACHE_MAXCOUNT != 0 + /* .tp_free = */ (dfunptr_t)&tuple_tp_free +#else /* CONFIG_TUPLE_CACHE_MAXCOUNT != 0 */ + /* .tp_free = */ (dfunptr_t)NULL +#endif /* CONFIG_TUPLE_CACHE_MAXCOUNT == 0 */ + } + }, + /* .tp_dtor = */ (void (DCALL *)(DeeObject *__restrict))&nullable_tuple_fini, + /* .tp_assign = */ NULL, + /* .tp_move_assign = */ NULL + }, + /* .tp_cast = */ { + /* .tp_str = */ NULL, + /* .tp_repr = */ NULL, + /* .tp_bool = */ (int (DCALL *)(DeeObject *__restrict))&tuple_bool + }, + /* .tp_call = */ NULL, + /* .tp_visit = */ (void (DCALL *)(DeeObject *__restrict, dvisit_t, void *))&nullable_tuple_visit, + /* .tp_gc = */ NULL, + /* .tp_math = */ NULL, + /* .tp_cmp = */ NULL, + /* .tp_seq = */ &nullable_tuple_seq, + /* .tp_iter_next = */ NULL, + /* .tp_attr = */ NULL, + /* .tp_with = */ NULL, + /* .tp_buffer = */ NULL, + /* .tp_methods = */ NULL, + /* .tp_getsets = */ nullable_tuple_getsets, + /* .tp_members = */ NULL, + /* .tp_class_methods = */ nullable_tuple_class_methods, + /* .tp_class_getsets = */ NULL, + /* .tp_class_members = */ tuple_class_members, + /* .tp_call_kw = */ NULL, + /* .tp_mro = */ NULL, + /* .tp_operators = */ nullable_tuple_operators, + /* .tp_operators_size= */ COMPILER_LENOF(nullable_tuple_operators) +}; + DECL_END #endif /* !GUARD_DEEMON_OBJECTS_TUPLE_C */ diff --git a/src/deemon/objects/unicode/codec.h b/src/deemon/objects/unicode/codec.h index 37caeba59..d3366cd55 100644 --- a/src/deemon/objects/unicode/codec.h +++ b/src/deemon/objects/unicode/codec.h @@ -79,7 +79,7 @@ local codecs = List { ("backslash-escape\0", "CODEC_C_ESCAPE"), ("c-escape\0", "CODEC_C_ESCAPE"), }; -codecs.sort([](x) -> x[0]); +codecs.sort(key: x -> x[0]); local inset = "\t"; diff --git a/src/deemon/runtime/operator.c b/src/deemon/runtime/operator.c index 1bfa76f43..44a1cf53b 100644 --- a/src/deemon/runtime/operator.c +++ b/src/deemon/runtime/operator.c @@ -14481,9 +14481,9 @@ DeeSeqType_SubstituteDefaultOperators(DeeTypeObject *self, seq_featureset_t feat seq->tp_enumerate = &DeeSeq_DefaultEnumerateWithSizeAndGetItemIndex; } else if (seq_featureset_test(features, FEAT_tp_sizeob) && seq_featureset_test(features, FEAT_tp_getitem) && seqclass == Dee_SEQCLASS_SEQ) { seq->tp_enumerate = &DeeSeq_DefaultEnumerateWithSizeObAndGetItem; - } else if (seq_featureset_test(features, FEAT_tp_foreach) && seqclass == Dee_SEQCLASS_SEQ) { + } else if (seq_featureset_test(features, FEAT_tp_foreach) && (seqclass == Dee_SEQCLASS_SEQ || seqclass == Dee_SEQCLASS_SET)) { seq->tp_enumerate = &DeeSeq_DefaultEnumerateWithCounterAndForeach; - } else if (seq_featureset_test(features, FEAT_tp_iter) && seqclass == Dee_SEQCLASS_SEQ) { + } else if (seq_featureset_test(features, FEAT_tp_iter) && (seqclass == Dee_SEQCLASS_SEQ || seqclass == Dee_SEQCLASS_SET)) { seq->tp_enumerate = &DeeSeq_DefaultEnumerateWithCounterAndIter; } else if (seq_featureset_test(features, FEAT_tp_iter) && seqclass == Dee_SEQCLASS_MAP) { seq->tp_enumerate = &DeeMap_DefaultEnumerateWithIter; diff --git a/src/dex/rt/librt.c b/src/dex/rt/librt.c index d6a735590..46bdae23d 100644 --- a/src/dex/rt/librt.c +++ b/src/dex/rt/librt.c @@ -2184,7 +2184,6 @@ PRIVATE struct dex_symbol symbols[] = { { NULL, NULL, MODSYM_FNORMAL }, { NULL, (DeeObject *)&librt_argv_set, MODSYM_FNORMAL }, - /* Internal types used to drive sequence proxies */ { "SeqCombinations", (DeeObject *)&librt_get_SeqCombinations, MODSYM_FREADONLY | MODSYM_FPROPERTY | MODSYM_FCONSTEXPR }, /* SeqCombinations_Type */ { "SeqCombinationsIterator", (DeeObject *)&librt_get_SeqCombinationsIterator, MODSYM_FREADONLY | MODSYM_FPROPERTY | MODSYM_FCONSTEXPR }, /* SeqCombinationsIterator_Type */ @@ -2234,7 +2233,31 @@ PRIVATE struct dex_symbol symbols[] = { { "SeqEachCallAttrIterator", (DeeObject *)&librt_get_SeqEachCallAttrIterator, MODSYM_FREADONLY | MODSYM_FPROPERTY | MODSYM_FCONSTEXPR }, /* SeqEachCallAttrIterator_Type */ { "SeqEachCallAttrKw", (DeeObject *)&librt_get_SeqEachCallAttrKw, MODSYM_FREADONLY | MODSYM_FPROPERTY | MODSYM_FCONSTEXPR }, /* SeqEachCallAttrKw_Type */ { "SeqEachCallAttrKwIterator", (DeeObject *)&librt_get_SeqEachCallAttrKwIterator, MODSYM_FREADONLY | MODSYM_FPROPERTY | MODSYM_FCONSTEXPR }, /* SeqEachCallAttrKwIterator_Type */ - /* TODO: SeqRemoveIfAllWrapper_Type */ +#ifdef CONFIG_EXPERIMENTAL_NEW_SEQUENCE_OPERATORS + /* TODO: IterWithGetItemIndex = DefaultIterator_WithGetItemIndex_Type */ + /* TODO: IterWithSizeAndGetItemIndex = DefaultIterator_WithSizeAndGetItemIndex_Type */ + /* TODO: IterWithSizeAndGetItemIndexFast = DefaultIterator_WithSizeAndGetItemIndexFast_Type */ + /* TODO: IterWithGetItem = DefaultIterator_WithGetItem_Type */ + /* TODO: IterWithTGetItem = DefaultIterator_WithTGetItem_Type */ + /* TODO: IterWithSizeAndGetItem = DefaultIterator_WithSizeAndGetItem_Type */ + /* TODO: IterWithTSizeAndGetItem = DefaultIterator_WithTSizeAndGetItem_Type */ + /* TODO: IterWithNextAndLimit = DefaultIterator_WithNextAndLimit_Type */ + /* TODO: SeqWithSizeAndGetItemIndex = DefaultSequence_WithSizeAndGetItemIndex_Type */ + /* TODO: SeqWithSizeAndGetItemIndexFast = DefaultSequence_WithSizeAndGetItemIndexFast_Type */ + /* TODO: SeqWithSizeAndGetItem = DefaultSequence_WithSizeAndGetItem_Type */ + /* TODO: SeqWithTSizeAndGetItem = DefaultSequence_WithTSizeAndGetItem_Type */ + /* TODO: SeqWithIter = DefaultSequence_WithIter_Type */ + /* TODO: SeqWithTIter = DefaultSequence_WithTIter_Type */ + /* TODO: SeqReversedWithGetItemIndex = DefaultReversed_WithGetItemIndex_Type */ + /* TODO: SeqReversedWithGetItemIndexFast = DefaultReversed_WithGetItemIndexFast_Type */ + /* TODO: SeqReversedWithTryGetItemIndex = DefaultReversed_WithTryGetItemIndex_Type */ + /* TODO: SeqRemoveWithRemoveIfPredicate = SeqRemoveWithRemoveIfPredicate_Type */ + /* TODO: SeqRemoveWithRemoveIfPredicateWithKey = SeqRemoveWithRemoveIfPredicateWithKey_Type */ + /* TODO: SeqRemoveIfWithRemoveAllItem = SeqRemoveIfWithRemoveAllItem_Type */ + /* TODO: SeqRemoveIfWithRemoveAllItem_DummyInstance = SeqRemoveIfWithRemoveAllItem_DummyInstance */ + /* TODO: SeqRemoveIfWithRemoveAllKey = SeqRemoveIfWithRemoveAllKey_Type */ +#endif /* CONFIG_EXPERIMENTAL_NEW_SEQUENCE_OPERATORS */ + { "NullableTuple", (DeeObject *)&DeeNullableTuple_Type, MODSYM_FREADONLY }, /* Internal types used to drive set proxies */ { "SetUnion", (DeeObject *)&librt_get_SetUnion, MODSYM_FREADONLY | MODSYM_FPROPERTY | MODSYM_FCONSTEXPR }, /* SetUnion_Type */ @@ -2589,31 +2612,6 @@ PRIVATE struct dex_symbol symbols[] = { { "FrameSymbolsByName", (DeeObject *)&librt_get_FrameSymbolsByName, MODSYM_FREADONLY | MODSYM_FPROPERTY | MODSYM_FCONSTEXPR }, /* FrameSymbolsByName_Type */ { "FrameSymbolsByNameIterator", (DeeObject *)&librt_get_FrameSymbolsByNameIterator, MODSYM_FREADONLY | MODSYM_FPROPERTY | MODSYM_FCONSTEXPR }, /* FrameSymbolsByName_Type */ -#ifdef CONFIG_EXPERIMENTAL_NEW_SEQUENCE_OPERATORS - /* TODO: IterWithGetItemIndex = DefaultIterator_WithGetItemIndex_Type */ - /* TODO: IterWithSizeAndGetItemIndex = DefaultIterator_WithSizeAndGetItemIndex_Type */ - /* TODO: IterWithSizeAndGetItemIndexFast = DefaultIterator_WithSizeAndGetItemIndexFast_Type */ - /* TODO: IterWithGetItem = DefaultIterator_WithGetItem_Type */ - /* TODO: IterWithTGetItem = DefaultIterator_WithTGetItem_Type */ - /* TODO: IterWithSizeAndGetItem = DefaultIterator_WithSizeAndGetItem_Type */ - /* TODO: IterWithTSizeAndGetItem = DefaultIterator_WithTSizeAndGetItem_Type */ - /* TODO: IterWithNextAndLimit = DefaultIterator_WithNextAndLimit_Type */ - /* TODO: SeqWithSizeAndGetItemIndex = DefaultSequence_WithSizeAndGetItemIndex_Type */ - /* TODO: SeqWithSizeAndGetItemIndexFast = DefaultSequence_WithSizeAndGetItemIndexFast_Type */ - /* TODO: SeqWithSizeAndGetItem = DefaultSequence_WithSizeAndGetItem_Type */ - /* TODO: SeqWithTSizeAndGetItem = DefaultSequence_WithTSizeAndGetItem_Type */ - /* TODO: SeqWithIter = DefaultSequence_WithIter_Type */ - /* TODO: SeqWithTIter = DefaultSequence_WithTIter_Type */ - /* TODO: SeqReversedWithGetItemIndex = DefaultReversed_WithGetItemIndex_Type */ - /* TODO: SeqReversedWithGetItemIndexFast = DefaultReversed_WithGetItemIndexFast_Type */ - /* TODO: SeqReversedWithTryGetItemIndex = DefaultReversed_WithTryGetItemIndex_Type */ - /* TODO: SeqRemoveWithRemoveIfPredicate = SeqRemoveWithRemoveIfPredicate_Type */ - /* TODO: SeqRemoveWithRemoveIfPredicateWithKey = SeqRemoveWithRemoveIfPredicateWithKey_Type */ - /* TODO: SeqRemoveIfWithRemoveAllItem = SeqRemoveIfWithRemoveAllItem_Type */ - /* TODO: SeqRemoveIfWithRemoveAllItem_DummyInstance = SeqRemoveIfWithRemoveAllItem_DummyInstance */ - /* TODO: SeqRemoveIfWithRemoveAllKey = SeqRemoveIfWithRemoveAllKey_Type */ -#endif /* CONFIG_EXPERIMENTAL_NEW_SEQUENCE_OPERATORS */ - { NULL } };