diff --git a/.vs/deemon-v141.sln b/.vs/deemon-v141.sln index 576988fd9..07eed794e 100644 --- a/.vs/deemon-v141.sln +++ b/.vs/deemon-v141.sln @@ -396,6 +396,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{2360741E-F ..\util\test\deemon-property.dee = ..\util\test\deemon-property.dee ..\util\test\deemon-sequence-bsearch.dee = ..\util\test\deemon-sequence-bsearch.dee ..\util\test\deemon-sequence-cached.dee = ..\util\test\deemon-sequence-cached.dee + ..\util\test\deemon-sequence-combinations.dee = ..\util\test\deemon-sequence-combinations.dee ..\util\test\deemon-sequence-compare.dee = ..\util\test\deemon-sequence-compare.dee ..\util\test\deemon-sequence-each-contains.dee = ..\util\test\deemon-sequence-each-contains.dee ..\util\test\deemon-sequence-each.dee = ..\util\test\deemon-sequence-each.dee diff --git a/.vs/deemon-v142.sln b/.vs/deemon-v142.sln index 7fa4dda53..7d255553c 100644 --- a/.vs/deemon-v142.sln +++ b/.vs/deemon-v142.sln @@ -396,6 +396,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{2360741E-F ..\util\test\deemon-property.dee = ..\util\test\deemon-property.dee ..\util\test\deemon-sequence-bsearch.dee = ..\util\test\deemon-sequence-bsearch.dee ..\util\test\deemon-sequence-cached.dee = ..\util\test\deemon-sequence-cached.dee + ..\util\test\deemon-sequence-combinations.dee = ..\util\test\deemon-sequence-combinations.dee ..\util\test\deemon-sequence-compare.dee = ..\util\test\deemon-sequence-compare.dee ..\util\test\deemon-sequence-each-contains.dee = ..\util\test\deemon-sequence-each-contains.dee ..\util\test\deemon-sequence-each.dee = ..\util\test\deemon-sequence-each.dee diff --git a/include/deemon/object.h b/include/deemon/object.h index 76dac143d..3d6a068d8 100644 --- a/include/deemon/object.h +++ b/include/deemon/object.h @@ -605,8 +605,9 @@ DFUNDEF NONNULL((1)) void (DCALL Dee_weakref_support_fini)(struct Dee_weakref_li /* Initialize the given weak reference to NULL. */ -#define Dee_weakref_initempty(self) \ - (void)((self)->wr_obj = NULL, (self)->wr_del = NULL) +#define Dee_weakref_initempty(self) \ + (void)((self)->wr_pself = NULL, (self)->wr_next = NULL, \ + (self)->wr_obj = NULL, (self)->wr_del = NULL) /* Weak reference functionality. * @assume(ob != NULL); @@ -4549,8 +4550,14 @@ DFUNDEF WUNUSED NONNULL((1, 2)) int (DCALL DeeObject_AssertTypeExact)(DeeObject /* Throw a TypeError stating that an instance of `required_type' was required, when `self' was given. */ DFUNDEF ATTR_COLD NONNULL((1, 2)) int (DCALL DeeObject_TypeAssertFailed)(DeeObject *self, DeeTypeObject *required_type); DFUNDEF ATTR_COLD NONNULL((1, 2, 3)) int (DCALL DeeObject_TypeAssertFailed2)(DeeObject *self, DeeTypeObject *required_type1, DeeTypeObject *required_type2); +DFUNDEF ATTR_COLD NONNULL((1, 2, 3, 4)) int (DCALL DeeObject_TypeAssertFailed3)(DeeObject *self, DeeTypeObject *required_type1, DeeTypeObject *required_type2, DeeTypeObject *required_type3); #ifndef Dee_ASSUMED_VALUE_IS_NOOP -#define DeeObject_TypeAssertFailed(self, required_type) Dee_ASSUMED_VALUE(DeeObject_TypeAssertFailed(self, required_type), -1) +#define DeeObject_TypeAssertFailed(self, required_type) \ + Dee_ASSUMED_VALUE(DeeObject_TypeAssertFailed(self, required_type), -1) +#define DeeObject_TypeAssertFailed2(self, required_type1, required_type2) \ + Dee_ASSUMED_VALUE(DeeObject_TypeAssertFailed2(self, required_type1, required_type2), -1) +#define DeeObject_TypeAssertFailed3(self, required_type1, required_type2, required_type3) \ + Dee_ASSUMED_VALUE(DeeObject_TypeAssertFailed3(self, required_type1, required_type2, required_type3), -1) #endif /* !Dee_ASSUMED_VALUE_IS_NOOP */ #define DeeObject_AssertTypeOrNone(self, required_type) (DeeNone_Check(self) ? 0 : DeeObject_AssertType(self, required_type)) #define DeeObject_AssertTypeExactOrNone(self, required_type) (DeeNone_CheckExact(self) ? 0 : DeeObject_AssertTypeExact(self, required_type)) diff --git a/src/deemon/objects/dict.c b/src/deemon/objects/dict.c index 8d92e4a0f..c80d38fa5 100644 --- a/src/deemon/objects/dict.c +++ b/src/deemon/objects/dict.c @@ -341,7 +341,10 @@ PRIVATE struct type_member tpconst dict_iterator_members[] = { INTERN DeeTypeObject DictIterator_Type = { OBJECT_HEAD_INIT(&DeeType_Type), /* .tp_name = */ "_DictIterator", - /* .tp_doc = */ DOC("next->?T2?O?O"), + /* .tp_doc = */ DOC("()\n" + "(dict:?DDict)\n" + "\n" + "next->?T2?O?O"), /* .tp_flags = */ TP_FNORMAL, /* .tp_weakrefs = */ 0, /* .tp_features = */ TF_NONE, diff --git a/src/deemon/objects/int.c b/src/deemon/objects/int.c index eb75a5b06..60e1a2e28 100644 --- a/src/deemon/objects/int.c +++ b/src/deemon/objects/int.c @@ -3739,19 +3739,19 @@ PRIVATE struct type_math int_math = { /* .tp_or = */ (DeeObject *(DCALL *)(DeeObject *, DeeObject *))&int_or, /* .tp_xor = */ (DeeObject *(DCALL *)(DeeObject *, DeeObject *))&int_xor, /* .tp_pow = */ (DeeObject *(DCALL *)(DeeObject *, DeeObject *))&int_pow, - /* .tp_inc = */ (int (DCALL *)(DeeObject **__restrict))&int_inc, - /* .tp_dec = */ (int (DCALL *)(DeeObject **__restrict))&int_dec, - /* .tp_inplace_add = */ NULL, - /* .tp_inplace_sub = */ NULL, - /* .tp_inplace_mul = */ NULL, - /* .tp_inplace_div = */ NULL, - /* .tp_inplace_mod = */ NULL, - /* .tp_inplace_shl = */ NULL, - /* .tp_inplace_shr = */ NULL, - /* .tp_inplace_and = */ NULL, - /* .tp_inplace_or = */ NULL, - /* .tp_inplace_xor = */ NULL, - /* .tp_inplace_pow = */ NULL + /* .tp_inc = */ (int (DCALL *)(DREF DeeObject **__restrict))&int_inc, + /* .tp_dec = */ (int (DCALL *)(DREF DeeObject **__restrict))&int_dec, + /* .tp_inplace_add = */ NULL, /* TODO: Same as regular, allow optimizations for !DeeObject_IsShared() */ + /* .tp_inplace_sub = */ NULL, /* TODO: Same as regular, allow optimizations for !DeeObject_IsShared() */ + /* .tp_inplace_mul = */ NULL, /* TODO: Same as regular, allow optimizations for !DeeObject_IsShared() */ + /* .tp_inplace_div = */ NULL, /* TODO: Same as regular, allow optimizations for !DeeObject_IsShared() */ + /* .tp_inplace_mod = */ NULL, /* TODO: Same as regular, allow optimizations for !DeeObject_IsShared() */ + /* .tp_inplace_shl = */ NULL, /* TODO: Same as regular, allow optimizations for !DeeObject_IsShared() */ + /* .tp_inplace_shr = */ NULL, /* TODO: Same as regular, allow optimizations for !DeeObject_IsShared() */ + /* .tp_inplace_and = */ NULL, /* TODO: Same as regular, allow optimizations for !DeeObject_IsShared() */ + /* .tp_inplace_or = */ NULL, /* TODO: Same as regular, allow optimizations for !DeeObject_IsShared() */ + /* .tp_inplace_xor = */ NULL, /* TODO: Same as regular, allow optimizations for !DeeObject_IsShared() */ + /* .tp_inplace_pow = */ NULL /* TODO: Same as regular, allow optimizations for !DeeObject_IsShared() */ }; diff --git a/src/deemon/objects/seq.c b/src/deemon/objects/seq.c index 7991ca046..d83bad867 100644 --- a/src/deemon/objects/seq.c +++ b/src/deemon/objects/seq.c @@ -64,13 +64,11 @@ #include "seq/simpleproxy.h" #include "seq/svec.h" #include "seq/unique-iterator.h" -#include "seq_functions.h" #undef SSIZE_MAX #include #define SSIZE_MAX __SSIZE_MAX__ - /* Provide aliases for certain Set operators in Sequence */ #undef CONFIG_HAVE_SET_OPERATORS_IN_SEQ #define CONFIG_HAVE_SET_OPERATORS_IN_SEQ @@ -501,41 +499,61 @@ seq_distribute(DeeObject *self, size_t argc, DeeObject *const *argv) { } PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL -seq_combinations(DeeObject *self, size_t argc, DeeObject *const *argv) { +seq_combinations(DeeObject *self, size_t argc, DeeObject *const *argv, DeeObject *kw) { size_t r; - if (DeeArg_Unpack(argc, argv, UNPuSIZ ":combinations", &r)) + bool cached = true; + if (DeeArg_UnpackKw(argc, argv, kw, kwlist__r_cached, UNPuSIZ "|b:combinations", &r, &cached)) goto err; + if (cached) { + self = DeeSeq_InvokeCached(self); + if unlikely(!self) + goto err; + } else { + Dee_Incref(self); + } return DeeSeq_Combinations(self, r); err: return NULL; } PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL -seq_repeatcombinations(DeeObject *self, size_t argc, DeeObject *const *argv) { +seq_repeatcombinations(DeeObject *self, size_t argc, DeeObject *const *argv, DeeObject *kw) { size_t r; - if (DeeArg_Unpack(argc, argv, UNPuSIZ ":repeatcombinations", &r)) + bool cached = true; + if (DeeArg_UnpackKw(argc, argv, kw, kwlist__r_cached, UNPuSIZ "|b:repeatcombinations", &r, &cached)) goto err; + if (cached) { + self = DeeSeq_InvokeCached(self); + if unlikely(!self) + goto err; + } else { + Dee_Incref(self); + } return DeeSeq_RepeatCombinations(self, r); err: return NULL; } PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL -seq_permutations(DeeObject *self, size_t argc, DeeObject *const *argv) { - size_t r; - DeeObject *arg = Dee_None; - if (DeeArg_Unpack(argc, argv, "|o:permutations", &arg)) - goto err; - if (DeeNone_Check(arg)) - return DeeSeq_Permutations(self); - if (DeeObject_AsSize(arg, &r)) +seq_permutations(DeeObject *self, size_t argc, DeeObject *const *argv, DeeObject *kw) { + size_t r = (size_t)-1; + bool cached = true; + if (DeeArg_UnpackKw(argc, argv, kw, kwlist__r_cached, "|" UNPuSIZ "b:permutations", &r, &cached)) goto err; + if (cached) { + self = DeeSeq_InvokeCached(self); + if unlikely(!self) + goto err; + } else { + Dee_Incref(self); + } return DeeSeq_Permutations2(self, r); err: return NULL; } + PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL seq_index(DeeObject *self, size_t argc, DeeObject *const *argv, DeeObject *kw) { DeeObject *item, *key = Dee_None; @@ -1420,61 +1438,64 @@ INTERN_TPCONST struct type_method tpconst seq_methods[] = { /**/ "making its length a little bit shorter than the other buckets\n" "This is similar to #segments, however rather than having the caller specify the " /**/ "size of the a bucket, the number of buckets is specified instead."), - TYPE_METHOD("combinations", - &seq_combinations, - "(r:?Dint)->?S?DSequence\n" - "#tIntegerOverflow{@r is negative, or too large}" - "Returns a Sequence of r-long sequences representing all possible (ordered) " - /**/ "combinations of elements retrieved from @this\n" - "${" - /**/ "/* { (\"A\", \"B\"), (\"A\", \"C\"), (\"A\", \"D\"),\n" - /**/ " * (\"B\", \"C\"), (\"B\", \"D\"), (\"C\", \"D\") } */\n" - /**/ "print repr \"ABCD\".combinations(2);" - "}\n" - "Notice that a combination such as $\"BA\" is not produced, as only possible " - /**/ "combinations with their original element order still in tact may be returned\n" - "When @this Sequence implements ?#{op:getitem} and ?#{op:size}, those will be invoked " - /**/ "as items are retrieved by index. Otherwise, all elements from @this Sequence " - /**/ "are loaded at once when #combinations is called first.\n" - "When @r is greater than ${##this}, an empty Sequence is returned (${{}})\n" - "Hint: The python equivalent of this function is " - /**/ "#A{itertools.combinations|https://docs.python.org/3/library/itertools.html##itertools.combinations}"), - TYPE_METHOD("repeatcombinations", - &seq_repeatcombinations, - "(r:?Dint)->?S?DSequence\n" - "#tIntegerOverflow{@r is negative, or too large}" - "Same as #combinations, however elements of @this Sequence may be repeated (though element order is still enforced)\n" - "${" - /**/ "/* { (\"A\", \"A\"), (\"A\", \"B\"), (\"A\", \"C\"),\n" - /**/ " * (\"B\", \"B\"), (\"B\", \"C\"), (\"C\", \"C\") } */\n" - /**/ "print repr \"ABC\".repeatcombinations(2);" - "}\n" - "When @this Sequence implements ?#{op:getitem} and ?#{op:size}, those will be invoked " - /**/ "as items are retrieved by index. Otherwise, all elements from @this Sequence " - /**/ "are loaded at once when #repeatcombinations is called first.\n" - "When @r is $0, a Sequence containing a single, empty Sequence is returned (${{{}}})\n" - "When ${##this} is zero, an empty Sequence is returned (${{}})\n" - "Hint: The python equivalent of this function is " - /**/ "#A{itertools.combinations_with_replacement|https://docs.python.org/3/library/itertools.html##itertools.combinations_with_replacement}"), - TYPE_METHOD("permutations", - &seq_permutations, - "(r:?Dint=!N)->?S?DSequence\n" - "#tIntegerOverflow{@r is negative, or too large}" - "Same as #combinations, however the order of elements must " - /**/ "not be enforced, though indices may not be repeated\n" - "When @r is ?N, ${##this} is used instead\n" - "${" - /**/ "/* { (\"A\", \"B\"), (\"A\", \"C\"), (\"B\", \"A\"),\n" - /**/ " * (\"B\", \"C\"), (\"C\", \"A\"), (\"C\", \"B\") } */\n" - /**/ "print repr \"ABC\".permutations(2);" - "}\n" - "When @this Sequence implements ?#{op:getitem} and ?#{op:size}, those will be invoked " - /**/ "as items are retrieved by index. Otherwise, all elements from @this Sequence " - /**/ "are loaded at once when #repeatcombinations is called first.\n" - "When @r is $0, a Sequence containing a single, empty Sequence is returned (${{{}}})\n" - "When ${##this} is zero, an empty Sequence is returned (${{}})\n" - "Hint: The python equivalent of this function is " - /**/ "#A{itertools.permutations|https://docs.python.org/3/library/itertools.html##itertools.permutations}"), + TYPE_KWMETHOD("combinations", + &seq_combinations, + "(r:?Dint,cached=!t)->?S?DSequence\n" + "#pcached{When true, automatically wrap using ?#cached like ${this.cached.combinations(r, cached: false)}}" + "#tIntegerOverflow{@r is negative, or too large}" + "Returns a Sequence of r-long sequences representing all possible (ordered) " + /**/ "combinations of elements retrieved from @this\n" + "${" + /**/ "/* { (\"A\", \"B\"), (\"A\", \"C\"), (\"A\", \"D\"),\n" + /**/ " * (\"B\", \"C\"), (\"B\", \"D\"), (\"C\", \"D\") } */\n" + /**/ "print repr \"ABCD\".combinations(2);" + "}\n" + "Notice that a combination such as $\"BA\" is not produced, as only possible " + /**/ "combinations with their original element order still in tact may be returned\n" + "When @this Sequence implements ?#{op:getitem} and ?#{op:size}, those will be invoked " + /**/ "as items are retrieved by index. Otherwise, all elements from @this Sequence " + /**/ "are loaded at once when #combinations is called first.\n" + "When @r is greater than ${##this}, an empty Sequence is returned (${{}})\n" + "Hint: The python equivalent of this function is " + /**/ "#A{itertools.combinations|https://docs.python.org/3/library/itertools.html##itertools.combinations}"), + TYPE_KWMETHOD("repeatcombinations", + &seq_repeatcombinations, + "(r:?Dint,cached=!t)->?S?DSequence\n" + "#pcached{When true, automatically wrap using ?#cached like ${this.cached.repeatcombinations(r, cached: false)}}" + "#tIntegerOverflow{@r is negative, or too large}" + "Same as #combinations, however elements of @this Sequence may be repeated (though element order is still enforced)\n" + "${" + /**/ "/* { (\"A\", \"A\"), (\"A\", \"B\"), (\"A\", \"C\"),\n" + /**/ " * (\"B\", \"B\"), (\"B\", \"C\"), (\"C\", \"C\") } */\n" + /**/ "print repr \"ABC\".repeatcombinations(2);" + "}\n" + "When @this Sequence implements ?#{op:getitem} and ?#{op:size}, those will be invoked " + /**/ "as items are retrieved by index. Otherwise, all elements from @this Sequence " + /**/ "are loaded at once when #repeatcombinations is called first.\n" + "When @r is $0, a Sequence containing a single, empty Sequence is returned (${{{}}})\n" + "When ${##this} is zero, an empty Sequence is returned (${{}})\n" + "Hint: The python equivalent of this function is " + /**/ "#A{itertools.combinations_with_replacement|https://docs.python.org/3/library/itertools.html##itertools.combinations_with_replacement}"), + TYPE_KWMETHOD("permutations", + &seq_permutations, + "(r?:?Dint,cached=!t)->?S?DSequence\n" + "#pcached{When true, automatically wrap using ?#cached like ${this.cached.permutations(r, cached: false)}}" + "#tIntegerOverflow{@r is negative, or too large}" + "Same as #combinations, however the order of elements must " + /**/ "not be enforced, though indices may not be repeated\n" + "When @r is ?N, ${##this} is used instead\n" + "${" + /**/ "/* { (\"A\", \"B\"), (\"A\", \"C\"), (\"B\", \"A\"),\n" + /**/ " * (\"B\", \"C\"), (\"C\", \"A\"), (\"C\", \"B\") } */\n" + /**/ "print repr \"ABC\".permutations(2);" + "}\n" + "When @this Sequence implements ?#{op:getitem} and ?#{op:size}, those will be invoked " + /**/ "as items are retrieved by index. Otherwise, all elements from @this Sequence " + /**/ "are loaded at once when #repeatcombinations is called first.\n" + "When @r is $0, a Sequence containing a single, empty Sequence is returned (${{{}}})\n" + "When ${##this} is zero, an empty Sequence is returned (${{}})\n" + "Hint: The python equivalent of this function is " + /**/ "#A{itertools.permutations|https://docs.python.org/3/library/itertools.html##itertools.permutations}"), TYPE_KWMETHOD("byhash", &seq_byhash, DOC_GET(seq_byhash_doc)), diff --git a/src/deemon/objects/seq/combinations.c b/src/deemon/objects/seq/combinations.c index 97f284fff..df3ec2bea 100644 --- a/src/deemon/objects/seq/combinations.c +++ b/src/deemon/objects/seq/combinations.c @@ -20,483 +20,277 @@ #ifndef GUARD_DEEMON_OBJECTS_SEQ_COMBINATIONS_C #define GUARD_DEEMON_OBJECTS_SEQ_COMBINATIONS_C 1 -#include #include #include -#include -#include #include -#include #include -#include -#include #include -#include -#include #include -#include -#include "combinations.h" -/**/ +#include +/**/ #include "../../runtime/runtime_error.h" #include "../../runtime/strings.h" +#include "default-api.h" -DECL_BEGIN - -#ifndef CONFIG_HAVE_memsetp -#define CONFIG_HAVE_memsetp -#define memsetp(dst, pointer, num_pointers) \ - dee_memsetp(dst, (__UINTPTR_TYPE__)(pointer), num_pointers) -DeeSystem_DEFINE_memsetp(dee_memsetp) -#endif /* !CONFIG_HAVE_memsetp */ +/**/ +#include "combinations.h" -PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL -Combinations_GetSeqItem(Combinations *__restrict self, size_t index) { - DREF DeeObject *temp, *result; - struct type_nsi const *nsi; - ASSERT(index < self->c_seqlen); - if (self->c_elem) - return_reference_(self->c_elem[index]); - ASSERT(self->c_getitem != NULL); - ASSERT(self->c_getitem->tp_getitem != NULL); - nsi = self->c_getitem->tp_nsi; - if (nsi && - nsi->nsi_class == TYPE_SEQX_CLASS_SEQ && - nsi->nsi_seqlike.nsi_getitem) - return (*nsi->nsi_seqlike.nsi_getitem)(self->c_seq, index); - temp = DeeInt_NewSize(index); - if unlikely(!temp) - goto err; - result = DeeType_invoke_seq_tp_getitem(self->c_getitem_tp, - self->c_getitem->tp_getitem, - self->c_seq, temp); - Dee_Decref(temp); - return result; -err: - return NULL; -} +DECL_BEGIN +/************************************************************************/ +/* SEQUENCE */ +/************************************************************************/ -PRIVATE NONNULL((1)) void DCALL -comiter_fini(CombinationsIterator *__restrict self) { - Dee_Free(self->ci_indices); - Dee_Decref_likely(self->ci_combi); -} +STATIC_ASSERT(offsetof(SeqCombinations, sc_seq) == offsetof(ProxyObject, po_obj)); +#define sc_fini generic_proxy_fini +#define sc_visit generic_proxy_visit +#define src_fini generic_proxy_fini +#define src_visit generic_proxy_visit +#define sp_fini generic_proxy_fini +#define sp_visit generic_proxy_visit +#define src_ctor sc_ctor +#define sp_ctor sc_ctor PRIVATE WUNUSED NONNULL((1)) int DCALL -comiter_ctor(CombinationsIterator *__restrict self) { - self->ci_combi = (DREF Combinations *)DeeObject_NewDefault(&SeqCombinations_Type); - if unlikely(!self->ci_combi) - goto err; - self->ci_indices = (size_t *)Dee_Callocc(self->ci_combi->c_comlen, - sizeof(size_t)); - if unlikely(!self->ci_indices) - goto err_combi; - self->ci_first = true; - Dee_atomic_rwlock_init(&self->ci_lock); +sc_ctor(SeqCombinations *__restrict self) { + Dee_Incref(Dee_EmptySeq); + self->sc_seq = Dee_EmptySeq; + self->sc_trygetitem_index = &DeeSeq_DefaultOperatorTryGetItemIndexWithEmpty; + self->sc_seqsize = 0; + self->sc_rparam = 1; return 0; -err_combi: - Dee_Decref_likely(self->ci_combi); -err: - return -1; } -PRIVATE WUNUSED NONNULL((1)) int DCALL -comiter_init(CombinationsIterator *__restrict self, - size_t argc, DeeObject *const *argv) { - size_t i, comlen; - if (DeeArg_Unpack(argc, argv, "o:_SeqCombinationsIterator", &self->ci_combi)) - goto err; - if (DeeObject_AssertTypeExact(self->ci_combi, &SeqCombinations_Type)) - goto err; - Dee_atomic_rwlock_init(&self->ci_lock); - comlen = self->ci_combi->c_comlen; - self->ci_indices = (size_t *)Dee_Mallocc(comlen, sizeof(size_t)); - if unlikely(!self->ci_indices) - goto err; - for (i = 0; i < comlen; ++i) - self->ci_indices[i] = i; - self->ci_first = true; - Dee_Incref(self->ci_combi); +#define src_copy sc_copy +#define sp_copy sc_copy +PRIVATE WUNUSED NONNULL((1, 2)) int DCALL +sc_copy(SeqCombinations *__restrict self, + SeqCombinations *__restrict other) { + Dee_Incref(other->sc_seq); + self->sc_seq = other->sc_seq; + self->sc_trygetitem_index = other->sc_trygetitem_index; + self->sc_seqsize = other->sc_seqsize; + self->sc_rparam = other->sc_rparam; return 0; -err: - return -1; } +#define src_deep sc_deep +#define sp_deep sc_deep PRIVATE WUNUSED NONNULL((1, 2)) int DCALL -comiter_copy(CombinationsIterator *__restrict self, - CombinationsIterator *__restrict other) { - self->ci_indices = (size_t *)Dee_Mallocc(other->ci_combi->c_comlen, - sizeof(size_t)); - if unlikely(!self->ci_indices) +sc_deep(SeqCombinations *__restrict self, + SeqCombinations *__restrict other) { + self->sc_seq = DeeObject_DeepCopy(other->sc_seq); + if unlikely(!self->sc_seq) goto err; - CombinationsIterator_LockRead(other); - memcpyc(self->ci_indices, - other->ci_indices, - other->ci_combi->c_comlen, - sizeof(size_t)); - self->ci_first = other->ci_first; - CombinationsIterator_LockEndRead(other); - Dee_atomic_rwlock_init(&self->ci_lock); - self->ci_combi = other->ci_combi; - Dee_Incref(self->ci_combi); + self->sc_trygetitem_index = DeeType_RequireSeqOperatorTryGetItemIndex(Dee_TYPE(self->sc_seq)); + self->sc_seqsize = other->sc_seqsize; + self->sc_rparam = other->sc_rparam; return 0; err: return -1; } -PRIVATE WUNUSED NONNULL((1, 2)) int DCALL -comiter_deep(CombinationsIterator *__restrict self, - CombinationsIterator *__restrict other) { - self->ci_indices = (size_t *)Dee_Mallocc(other->ci_combi->c_comlen, - sizeof(size_t)); - if unlikely(!self->ci_indices) - goto err; - CombinationsIterator_LockRead(other); - memcpyc(self->ci_indices, - other->ci_indices, - other->ci_combi->c_comlen, - sizeof(size_t)); - self->ci_first = other->ci_first; - CombinationsIterator_LockEndRead(other); - Dee_atomic_rwlock_init(&self->ci_lock); - self->ci_combi = (DREF Combinations *)DeeObject_DeepCopy((DeeObject *)other->ci_combi); - if unlikely(!self->ci_combi) - goto err_indices; +#define src_init sc_init +#define sp_init sc_init +PRIVATE WUNUSED NONNULL((1)) int DCALL +sc_init(SeqCombinations *__restrict self, + size_t argc, DeeObject *const *argv) { + if (argc < 1 || argc > 2) + return err_invalid_argc(Dee_TYPE(self)->tp_name, argc, 1, 2); + self->sc_rparam = (size_t)-1; + if (argc >= 2) { + if unlikely(DeeObject_AsSize(argv[1], &self->sc_rparam)) + goto err; + if unlikely(!self->sc_rparam) + goto err_zero_rparam; + } + self->sc_seq = argv[0]; + Dee_Incref(self->sc_seq); + self->sc_trygetitem_index = DeeType_RequireSeqOperatorTryGetItemIndex(Dee_TYPE(self->sc_seq)); + self->sc_seqsize = (size_t)-1; return 0; -err_indices: - Dee_Free(self->ci_indices); +err_zero_rparam: + DeeError_Throwf(&DeeError_ValueError, "'r' parameter of '%s' must not be 0", + Dee_TYPE(self)->tp_name); err: return -1; } -PRIVATE NONNULL((1, 2)) void DCALL -comiter_visit(CombinationsIterator *__restrict self, dvisit_t proc, void *arg) { - Dee_Visit(self->ci_combi); -} -PRIVATE WUNUSED NONNULL((1)) DREF DeeTupleObject *DCALL -comiter_next(CombinationsIterator *__restrict self) { - DREF DeeTupleObject *result; - size_t *result_indices, i, comlen, seqlen; - comlen = self->ci_combi->c_comlen; - seqlen = self->ci_combi->c_seqlen; - result_indices = (size_t *)Dee_Mallocac(comlen, sizeof(size_t)); - if unlikely(!result_indices) - goto err; - CombinationsIterator_LockWrite(self); - if (self->ci_first) { - self->ci_first = false; - goto copy_indices; - } - for (i = comlen; i;) { - --i; - if (self->ci_indices[i] != i + seqlen - comlen) - goto update_indices; - } - /* Signal `ITER_DONE' */ - CombinationsIterator_LockEndWrite(self); - Dee_Freea(result_indices); - return (DREF DeeTupleObject *)ITER_DONE; -update_indices: - ++self->ci_indices[i]; - for (++i; i < comlen; ++i) - self->ci_indices[i] = self->ci_indices[i - 1] + 1; -copy_indices: - memcpyc(result_indices, - self->ci_indices, - comlen, - sizeof(size_t)); - CombinationsIterator_LockEndWrite(self); - result = DeeTuple_NewUninitialized(comlen); - if unlikely(!result) - goto err_indices; - for (i = 0; i < comlen; ++i) { - DREF DeeObject *temp; - temp = Combinations_GetSeqItem(self->ci_combi, - result_indices[i]); - if unlikely(!temp) - goto err_indices_r; - DeeTuple_SET(result, i, temp); /* Inherit reference. */ +PRIVATE WUNUSED NONNULL((1)) size_t DCALL +sc_getseqsize(SeqCombinations *__restrict self) { + size_t result = atomic_read(&self->sc_seqsize); + if (result == (size_t)-1) { + result = DeeSeq_OperatorSize(self->sc_seq); + if likely(result != (size_t)-1) + atomic_write(&self->sc_seqsize, result); } - Dee_Freea(result_indices); return result; -err_indices_r: - Dee_Decrefv(DeeTuple_ELEM(result), i); - DeeTuple_FreeUninitialized(result); -err_indices: - Dee_Freea(result_indices); -err: - return NULL; } -PRIVATE struct type_member tpconst comiter_members[] = { - TYPE_MEMBER_FIELD_DOC(STR_seq, STRUCT_OBJECT, offsetof(CombinationsIterator, ci_combi), "->?Ert:SeqCombinations"), - TYPE_MEMBER_END -}; - - -PRIVATE WUNUSED NONNULL((1, 2)) int DCALL -comiter_compare(CombinationsIterator *self, CombinationsIterator *other) { - size_t i; - int result = 0; - if (DeeObject_AssertTypeExact(other, Dee_TYPE(self))) - goto err; - Dee_return_compare_if_ne(self->ci_combi, other->ci_combi); - DeeLock_Acquire2(CombinationsIterator_LockRead(self), - CombinationsIterator_LockTryRead(self), - CombinationsIterator_LockEndRead(self), - CombinationsIterator_LockRead(other), - CombinationsIterator_LockTryRead(other), - CombinationsIterator_LockEndRead(other)); - for (i = 0; i < self->ci_combi->c_comlen; ++i) { - size_t lhs_index = self->ci_indices[i]; - size_t rhs_index = other->ci_indices[i]; - if (lhs_index != rhs_index) { - result = Dee_CompareNe(lhs_index, rhs_index); - break; - } +PRIVATE WUNUSED NONNULL((1)) size_t DCALL +sc_getrparam(SeqCombinations *__restrict self) { + size_t result = atomic_read(&self->sc_rparam); + if (result == (size_t)-1) { + result = sc_getseqsize(self); + if unlikely(result == 0) + result = 1; + if likely(result != (size_t)-1) + atomic_write(&self->sc_rparam, result); } - CombinationsIterator_LockEndRead(other); - CombinationsIterator_LockEndRead(self); return result; -err: - return Dee_COMPARE_ERR; } -PRIVATE struct type_cmp comiter_cmp = { - /* .tp_hash = */ NULL, - /* .tp_compare_eq = */ NULL, - /* .tp_compare = */ (int (DCALL *)(DeeObject *, DeeObject *))&comiter_compare, -}; - -INTERN DeeTypeObject SeqCombinationsIterator_Type = { - OBJECT_HEAD_INIT(&DeeType_Type), - /* .tp_name = */ "_SeqCombinationsIterator", - /* .tp_doc = */ DOC("(seq?:?Ert:SeqCombinations)"), - /* .tp_flags = */ TP_FNORMAL | TP_FFINAL, - /* .tp_weakrefs = */ 0, - /* .tp_features = */ TF_NONE, - /* .tp_base = */ &DeeIterator_Type, - /* .tp_init = */ { - { - /* .tp_alloc = */ { - /* .tp_ctor = */ (dfunptr_t)&comiter_ctor, - /* .tp_copy_ctor = */ (dfunptr_t)&comiter_copy, - /* .tp_deep_ctor = */ (dfunptr_t)&comiter_deep, - /* .tp_any_ctor = */ (dfunptr_t)&comiter_init, - TYPE_FIXED_ALLOCATOR(CombinationsIterator) - } - }, - /* .tp_dtor = */ (void (DCALL *)(DeeObject *__restrict))&comiter_fini, - /* .tp_assign = */ NULL, - /* .tp_move_assign = */ NULL - }, - /* .tp_cast = */ { - /* .tp_str = */ NULL, - /* .tp_repr = */ NULL, - /* .tp_bool = */ NULL - }, - /* .tp_call = */ NULL, - /* .tp_visit = */ (void (DCALL *)(DeeObject *__restrict, dvisit_t, void *))&comiter_visit, - /* .tp_gc = */ NULL, - /* .tp_math = */ NULL, - /* .tp_cmp = */ &comiter_cmp, - /* .tp_seq = */ NULL, - /* .tp_iter_next = */ (DREF DeeObject *(DCALL *)(DeeObject *__restrict))&comiter_next, - /* .tp_iterator = */ NULL, - /* .tp_attr = */ NULL, - /* .tp_with = */ NULL, - /* .tp_buffer = */ NULL, - /* .tp_methods = */ NULL, - /* .tp_getsets = */ NULL, - /* .tp_members = */ comiter_members, - /* .tp_class_methods = */ NULL, - /* .tp_class_getsets = */ NULL, - /* .tp_class_members = */ NULL -}; - -PRIVATE WUNUSED NONNULL((1)) DREF CombinationsIterator *DCALL -com_iter(Combinations *__restrict self) { - DREF CombinationsIterator *result; - size_t i, comlen; - result = DeeObject_MALLOC(CombinationsIterator); +PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL +sc_iter(SeqCombinations *__restrict self) { + DREF SeqCombinationsIterator *result; + size_t i, seqsize, rparam; + seqsize = sc_getseqsize(self); + if unlikely(seqsize == (size_t)-1) + goto err; /* Must be loaded for there to be an iterator! */ + rparam = sc_getrparam(self); + if unlikely(rparam == (size_t)-1) + goto err; + if unlikely(rparam > seqsize) + return_empty_iterator; + result = (DREF SeqCombinationsIterator *)DeeObject_Mallocc(offsetof(SeqCombinationsIterator, sci_idx), + rparam, sizeof(size_t)); if unlikely(!result) - goto done; - result->ci_combi = self; - Dee_atomic_rwlock_init(&result->ci_lock); - comlen = self->c_comlen; - result->ci_indices = (size_t *)Dee_Mallocc(comlen, sizeof(size_t)); - if unlikely(!result->ci_indices) - goto err_r; - for (i = 0; i < comlen; ++i) - result->ci_indices[i] = i; - result->ci_first = true; + goto err; + /* Fill in iterator as the normal matrix (truncated to "rparam"). */ + for (i = 0; i < rparam; ++i) + result->sci_idx[i] = i; + --result->sci_idx[rparam - 1]; /* Hack to get the first element to load correctly */ Dee_Incref(self); + result->sci_com = self; + Dee_weakref_initempty(&result->sci_view); DeeObject_Init(result, &SeqCombinationsIterator_Type); -done: - return result; -err_r: - DeeObject_FREE(result); + return (DREF DeeObject *)result; +err: return NULL; } -PRIVATE int DCALL -com_bool(Combinations *__restrict UNUSED(self)) { - /* Combinations are always non-empty. - * The creator function `DeeSeq_Combinations()' returns a - * different sequence type if we would have been empty. */ - return 1; +PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL +src_iter(SeqCombinations *__restrict self) { + DREF SeqCombinationsIterator *result; + size_t rparam; + if unlikely(sc_getseqsize(self) == (size_t)-1) + goto err; /* Must be loaded for there to be an iterator! */ + rparam = sc_getrparam(self); + if unlikely(rparam == (size_t)-1) + goto err; + result = (DREF SeqCombinationsIterator *)DeeObject_Callocc(offsetof(SeqCombinationsIterator, sci_idx), + rparam, sizeof(size_t)); + if unlikely(!result) + goto err; + Dee_Incref(self); + result->sci_com = self; + result->sci_idx[rparam - 1] = (size_t)-1; /* Hack to get the first element to load correctly */ + Dee_weakref_initempty(&result->sci_view); + DeeObject_Init(result, &SeqRepeatCombinationsIterator_Type); + return (DREF DeeObject *)result; +err: + return NULL; } -PRIVATE WUNUSED NONNULL((1, 2)) int DCALL -com_copy(Combinations *__restrict self, - Combinations *__restrict other) { - /* NOTE: `DeeTuple_ELEM()' just returns an invalid - * pointer for any object that isn't a tuple. */ - self->c_elem = other->c_elem; - if (other->c_elem && - other->c_elem != DeeTuple_ELEM(other->c_seq)) { - DREF DeeObject **elem_copy; - ASSERT(other->c_seqlen != 0); - elem_copy = (DREF DeeObject **)Dee_Mallocc(other->c_seqlen, - sizeof(DREF DeeObject *)); - if unlikely(!elem_copy) - goto err; - self->c_elem = Dee_Movrefv(elem_copy, - other->c_elem, - other->c_seqlen); - } - self->c_seq = other->c_seq; - self->c_seqlen = other->c_seqlen; - self->c_comlen = other->c_comlen; - self->c_getitem = other->c_getitem; - self->c_getitem_tp = other->c_getitem_tp; - Dee_Incref(self->c_seq); - return 0; +PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL +sp_iter(SeqCombinations *__restrict self) { + DREF SeqCombinationsIterator *result; + size_t i, seqsize, rparam; + seqsize = sc_getseqsize(self); + if unlikely(seqsize == (size_t)-1) + goto err; /* Must be loaded for there to be an iterator! */ + rparam = sc_getrparam(self); + if unlikely(rparam == (size_t)-1) + goto err; + if unlikely(rparam > seqsize) + return_empty_iterator; + result = (DREF SeqCombinationsIterator *)DeeObject_Mallocc(offsetof(SeqCombinationsIterator, sci_idx), + rparam, sizeof(size_t)); + if unlikely(!result) + goto err; + /* Fill in iterator as the normal matrix (truncated to "rparam"). */ + for (i = 0; i < rparam; ++i) + result->sci_idx[i] = i; + --result->sci_idx[rparam - 1]; /* Hack to get the first element to load correctly */ + Dee_Incref(self); + result->sci_com = self; + Dee_weakref_initempty(&result->sci_view); + DeeObject_Init(result, &SeqPermutationsIterator_Type); + return (DREF DeeObject *)result; err: - return -1; + return NULL; } -PRIVATE WUNUSED NONNULL((1, 2)) int DCALL -com_deepcopy(Combinations *__restrict self, - Combinations *__restrict other) { - /* NOTE: `DeeTuple_ELEM()' just returns an invalid - * pointer for any object that isn't a tuple. */ - self->c_elem = other->c_elem; - self->c_comlen = other->c_comlen; - if (other->c_elem && - other->c_elem != DeeTuple_ELEM(other->c_seq)) { - size_t i; - DREF DeeObject **elem_copy; - ASSERT(other->c_seqlen != 0); - elem_copy = (DREF DeeObject **)Dee_Mallocc(other->c_seqlen, - sizeof(DREF DeeObject *)); - if unlikely(!elem_copy) - goto err; - for (i = 0; i < other->c_seqlen; ++i) { - elem_copy[i] = DeeObject_DeepCopy(other->c_elem[i]); - if unlikely(!elem_copy[i]) { - Dee_Decrefv(elem_copy, i); - Dee_Free(elem_copy); - goto err; - } - } - self->c_elem = elem_copy; - self->c_seq = other->c_seq; - Dee_Incref(self->c_seq); - self->c_seqlen = other->c_seqlen; - } else { - self->c_seq = DeeObject_DeepCopy(other->c_seq); - if unlikely(!self->c_seq) - goto err; - ASSERT(Dee_TYPE(self->c_seq) == Dee_TYPE(other->c_seq)); - if (other->c_elem == DeeTuple_ELEM(other->c_seq)) { - self->c_elem = DeeTuple_ELEM(self->c_seq); - self->c_seqlen = other->c_seqlen; - } else { - ASSERT(self->c_elem == NULL); - ASSERT(other->c_elem == NULL); - /* Reload the sequence length, as it may have - * changed after copying the underlying sequence. */ - self->c_seqlen = DeeObject_Size(self->c_seq); - if unlikely(self->c_seqlen == (size_t)-1) { -err_seq_len: - Dee_Decref(self->c_seq); - goto err; - } - if unlikely(self->c_seqlen == 0) { - err_empty_sequence(self->c_seq); - goto err_seq_len; - } - /* Make sure that the sequence fulfills the minimum length requirements. */ - if unlikely(self->c_comlen >= self->c_seqlen) { - DeeError_Throwf(&DeeError_ValueError, - "Sequence too short after deepcopy (needs at " - "least %" PRFuSIZ " items, but only has %" PRFuSIZ ")", - self->c_comlen, self->c_seqlen); - goto err_seq_len; - } - } - } - self->c_getitem = other->c_getitem; - self->c_getitem_tp = other->c_getitem_tp; - return 0; +PRIVATE struct type_seq sc_seq = { + /* .tp_iter = */ (DREF DeeObject *(DCALL *)(DeeObject *__restrict))&sc_iter, + /* TODO: Formula for getitem/size */ +}; + +PRIVATE struct type_seq src_seq = { + /* .tp_iter = */ (DREF DeeObject *(DCALL *)(DeeObject *__restrict))&src_iter, + /* TODO: Formula for getitem/size */ +}; + +PRIVATE struct type_seq sp_seq = { + /* .tp_iter = */ (DREF DeeObject *(DCALL *)(DeeObject *__restrict))&sp_iter, + /* TODO: Formula for getitem/size */ +}; + + +PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL +sc_getseqsize_ob(SeqCombinations *__restrict self) { + size_t result = sc_getseqsize(self); + if unlikely(result == (size_t)-1) + goto err; + return DeeInt_NewSize(result); err: - return -1; + return NULL; } -PRIVATE WUNUSED NONNULL((1)) int DCALL -com_ctor(Combinations *__restrict self) { - self->c_seq = DeeTuple_Pack(1, Dee_None); - if unlikely(!self->c_seq) +PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL +sc_getrparam_ob(SeqCombinations *__restrict self) { + size_t result = sc_getrparam(self); + if unlikely(result == (size_t)-1) goto err; - self->c_elem = DeeTuple_ELEM(self->c_seq); - self->c_seqlen = 1; - self->c_comlen = 1; - self->c_getitem = DeeTuple_Type.tp_seq; - self->c_getitem_tp = &DeeTuple_Type; - return 0; + return DeeInt_NewSize(result); err: - return -1; + return NULL; } -PRIVATE NONNULL((1)) void DCALL -com_fini(Combinations *__restrict self) { - /* NOTE: `DeeTuple_ELEM()' just returns an invalid - * pointer for any object that isn't a tuple. */ - if (self->c_elem && - self->c_elem != DeeTuple_ELEM(self->c_seq)) { - Dee_Decrefv(self->c_elem, self->c_seqlen); - Dee_Free(self->c_elem); - } - Dee_Decref(self->c_seq); -} -PRIVATE NONNULL((1, 2)) void DCALL -com_visit(Combinations *__restrict self, dvisit_t proc, void *arg) { - /* NOTE: `DeeTuple_ELEM()' just returns an invalid - * pointer for any object that isn't a tuple. */ - if (self->c_elem && - self->c_elem != DeeTuple_ELEM(self->c_seq)) - Dee_Visitv(self->c_elem, self->c_seqlen); - Dee_Visit(self->c_seq); -} +#define src_getsets sc_getsets +#define sp_getsets sc_getsets +PRIVATE struct type_getset tpconst sc_getsets[] = { + TYPE_GETTER_F("__seqsize__", &sc_getseqsize_ob, METHOD_FNOREFESCAPE, "->?Dint"), + TYPE_GETTER_F("__rparam__", &sc_getrparam_ob, METHOD_FNOREFESCAPE, "->?Dint"), + TYPE_GETSET_END +}; -PRIVATE struct type_seq com_seq = { - /* .tp_iter = */ (DREF DeeObject *(DCALL *)(DeeObject *__restrict))&com_iter +#define src_members sc_members +#define sp_members sc_members +PRIVATE struct type_member tpconst sc_members[] = { + TYPE_MEMBER_FIELD_DOC("__seq__", STRUCT_OBJECT, offsetof(SeqCombinations, sc_seq), "->?DSequence"), + TYPE_MEMBER_END }; -PRIVATE struct type_member tpconst com_class_members[] = { +PRIVATE struct type_member tpconst sc_class_members[] = { TYPE_MEMBER_CONST(STR_Iterator, &SeqCombinationsIterator_Type), - /* TODO: "Frozen" */ + TYPE_MEMBER_CONST(STR_ItemType, &SeqCombinationsView_Type), + TYPE_MEMBER_END +}; + +PRIVATE struct type_member tpconst src_class_members[] = { + TYPE_MEMBER_CONST(STR_Iterator, &SeqRepeatCombinationsIterator_Type), + TYPE_MEMBER_CONST(STR_ItemType, &SeqCombinationsView_Type), TYPE_MEMBER_END }; -PRIVATE struct type_member tpconst com_members[] = { - TYPE_MEMBER_FIELD_DOC("__seq__", STRUCT_OBJECT, offsetof(Combinations, c_seq), "->?DSequence"), - /* TODO: GETTER: "frozen" */ +PRIVATE struct type_member tpconst sp_class_members[] = { + TYPE_MEMBER_CONST(STR_Iterator, &SeqPermutationsIterator_Type), + TYPE_MEMBER_CONST(STR_ItemType, &SeqCombinationsView_Type), TYPE_MEMBER_END }; @@ -504,7 +298,8 @@ PRIVATE struct type_member tpconst com_members[] = { INTERN DeeTypeObject SeqCombinations_Type = { OBJECT_HEAD_INIT(&DeeType_Type), /* .tp_name = */ "_SeqCombinations", - /* .tp_doc = */ NULL, + /* .tp_doc = */ DOC("()\n" + "(seq:?DSequence,r?:?Dint)"), /* .tp_flags = */ TP_FNORMAL | TP_FFINAL, /* .tp_weakrefs = */ 0, /* .tp_features = */ TF_NONE, @@ -512,189 +307,63 @@ INTERN DeeTypeObject SeqCombinations_Type = { /* .tp_init = */ { { /* .tp_alloc = */ { - /* .tp_ctor = */ (dfunptr_t)&com_ctor, - /* .tp_copy_ctor = */ (dfunptr_t)&com_copy, - /* .tp_deep_ctor = */ (dfunptr_t)&com_deepcopy, - /* .tp_any_ctor = */ (dfunptr_t)NULL, /* TODO */ - TYPE_FIXED_ALLOCATOR(Combinations) + /* .tp_ctor = */ (dfunptr_t)&sc_ctor, + /* .tp_copy_ctor = */ (dfunptr_t)&sc_copy, + /* .tp_deep_ctor = */ (dfunptr_t)&sc_deep, + /* .tp_any_ctor = */ (dfunptr_t)&sc_init, + TYPE_FIXED_ALLOCATOR(SeqCombinations) } }, - /* .tp_dtor = */ (void (DCALL *)(DeeObject *__restrict))&com_fini, + /* .tp_dtor = */ (void (DCALL *)(DeeObject *__restrict))&sc_fini, /* .tp_assign = */ NULL, /* .tp_move_assign = */ NULL }, /* .tp_cast = */ { /* .tp_str = */ NULL, /* .tp_repr = */ NULL, - /* .tp_bool = */ (int (DCALL *)(DeeObject *__restrict))&com_bool + /* .tp_bool = */ NULL }, /* .tp_call = */ NULL, - /* .tp_visit = */ (void (DCALL *)(DeeObject *__restrict, dvisit_t, void *))&com_visit, + /* .tp_visit = */ (void (DCALL *)(DeeObject *__restrict, dvisit_t, void *))&sc_visit, /* .tp_gc = */ NULL, /* .tp_math = */ NULL, /* .tp_cmp = */ NULL, - /* .tp_seq = */ &com_seq, + /* .tp_seq = */ &sc_seq, /* .tp_iter_next = */ NULL, /* .tp_iterator = */ NULL, /* .tp_attr = */ NULL, /* .tp_with = */ NULL, /* .tp_buffer = */ NULL, /* .tp_methods = */ NULL, - /* .tp_getsets = */ NULL, - /* .tp_members = */ com_members, + /* .tp_getsets = */ sc_getsets, + /* .tp_members = */ sc_members, /* .tp_class_methods = */ NULL, /* .tp_class_getsets = */ NULL, - /* .tp_class_members = */ com_class_members -}; - - - - -PRIVATE WUNUSED NONNULL((1)) DREF DeeTupleObject *DCALL -rcomiter_next(CombinationsIterator *__restrict self) { - DREF DeeTupleObject *result; - size_t *result_indices, i, comlen, seqlen, offset; - comlen = self->ci_combi->c_comlen; - seqlen = self->ci_combi->c_seqlen; - if (self->ci_first) { - CombinationsIterator_LockWrite(self); - COMPILER_READ_BARRIER(); - if (!self->ci_first) { - CombinationsIterator_LockEndWrite(self); - } else { - DREF DeeObject *elem; - self->ci_first = false; - CombinationsIterator_LockEndWrite(self); - result = DeeTuple_NewUninitialized(comlen); - if unlikely(!result) - goto err; - elem = Combinations_GetSeqItem(self->ci_combi, 0); - if unlikely(!elem) { - DeeTuple_FreeUninitialized(result); - goto err; - } - memsetp(DeeTuple_ELEM(result), elem, comlen); - Dee_Incref_n(elem, comlen); - return result; - } - } - result_indices = (size_t *)Dee_Mallocac(comlen, sizeof(size_t)); - if unlikely(!result_indices) - goto err; - CombinationsIterator_LockWrite(self); - i = comlen; - while (i--) { - if (self->ci_indices[i] != seqlen - 1) - goto update_indices; - } - /* Signal `ITER_DONE' */ - CombinationsIterator_LockEndWrite(self); - Dee_Freea(result_indices); - return (DREF DeeTupleObject *)ITER_DONE; -update_indices: - offset = self->ci_indices[i] + 1; - for (; i < comlen; ++i) - self->ci_indices[i] = offset; - memcpyc(result_indices, - self->ci_indices, - comlen, - sizeof(size_t)); - CombinationsIterator_LockEndWrite(self); - result = DeeTuple_NewUninitialized(comlen); - if unlikely(!result) - goto err_indices; - for (i = 0; i < comlen; ++i) { - DREF DeeObject *temp; - size_t j, index = result_indices[i]; - for (j = 0; j < i; ++j) { - if (result_indices[j] == index) { - temp = DeeTuple_GET(result, j); - Dee_Incref(temp); - goto set_temp; - } - } - temp = Combinations_GetSeqItem(self->ci_combi, index); - if unlikely(!temp) - goto err_indices_r; -set_temp: - DeeTuple_SET(result, i, temp); /* Inherit reference. */ - } - Dee_Freea(result_indices); - return result; -err_indices_r: - Dee_Decrefv(DeeTuple_ELEM(result), i); - DeeTuple_FreeUninitialized(result); -err_indices: - Dee_Freea(result_indices); -err: - return NULL; -} - -PRIVATE struct type_member tpconst rcomiter_members[] = { - TYPE_MEMBER_FIELD_DOC(STR_seq, STRUCT_OBJECT, offsetof(CombinationsIterator, ci_combi), "->?Ert:SeqRepeatCombinations"), - TYPE_MEMBER_END + /* .tp_class_members = */ sc_class_members }; - -PRIVATE WUNUSED NONNULL((1)) int DCALL -rcomiter_ctor(CombinationsIterator *__restrict self) { - self->ci_combi = (DREF Combinations *)DeeObject_NewDefault(&SeqRepeatCombinations_Type); - if unlikely(!self->ci_combi) - goto err; - self->ci_indices = (size_t *)Dee_Callocc(self->ci_combi->c_comlen, - sizeof(size_t)); - if unlikely(!self->ci_indices) - goto err_combi; - self->ci_first = true; - Dee_atomic_rwlock_init(&self->ci_lock); - return 0; -err_combi: - Dee_Decref_likely(self->ci_combi); -err: - return -1; -} - -PRIVATE WUNUSED NONNULL((1)) int DCALL -rcomiter_init(CombinationsIterator *__restrict self, - size_t argc, DeeObject *const *argv) { - size_t i, comlen; - if (DeeArg_Unpack(argc, argv, "o:_SeqRepeatCombinationsIterator", &self->ci_combi)) - goto err; - if (DeeObject_AssertTypeExact(self->ci_combi, &SeqRepeatCombinations_Type)) - goto err; - Dee_atomic_rwlock_init(&self->ci_lock); - comlen = self->ci_combi->c_comlen; - self->ci_indices = (size_t *)Dee_Mallocc(comlen, sizeof(size_t)); - if unlikely(!self->ci_indices) - goto err; - for (i = 0; i < comlen; ++i) - self->ci_indices[i] = i; - self->ci_first = true; - Dee_Incref(self->ci_combi); - return 0; -err: - return -1; -} - -INTERN DeeTypeObject SeqRepeatCombinationsIterator_Type = { +INTERN DeeTypeObject SeqRepeatCombinations_Type = { OBJECT_HEAD_INIT(&DeeType_Type), - /* .tp_name = */ "_SeqRepeatCombinationsIterator", - /* .tp_doc = */ DOC("(seq?:?Ert:SeqRepeatCombinations)"), + /* .tp_name = */ "_SeqRepeatCombinations", + /* .tp_doc = */ DOC("()\n" + "(seq:?DSequence,r?:?Dint)\n" + "\n" + "iter->?#Iterator"), /* .tp_flags = */ TP_FNORMAL | TP_FFINAL, /* .tp_weakrefs = */ 0, /* .tp_features = */ TF_NONE, - /* .tp_base = */ &DeeIterator_Type, + /* .tp_base = */ &DeeSeq_Type, /* .tp_init = */ { { /* .tp_alloc = */ { - /* .tp_ctor = */ (dfunptr_t)&rcomiter_ctor, - /* .tp_copy_ctor = */ (dfunptr_t)&comiter_copy, - /* .tp_deep_ctor = */ (dfunptr_t)&comiter_deep, - /* .tp_any_ctor = */ (dfunptr_t)&rcomiter_init, - TYPE_FIXED_ALLOCATOR(CombinationsIterator) + /* .tp_ctor = */ (dfunptr_t)&src_ctor, + /* .tp_copy_ctor = */ (dfunptr_t)&src_copy, + /* .tp_deep_ctor = */ (dfunptr_t)&src_deep, + /* .tp_any_ctor = */ (dfunptr_t)&src_init, + TYPE_FIXED_ALLOCATOR(SeqCombinations) } }, - /* .tp_dtor = */ (void (DCALL *)(DeeObject *__restrict))&comiter_fini, + /* .tp_dtor = */ (void (DCALL *)(DeeObject *__restrict))&src_fini, /* .tp_assign = */ NULL, /* .tp_move_assign = */ NULL }, @@ -704,60 +373,29 @@ INTERN DeeTypeObject SeqRepeatCombinationsIterator_Type = { /* .tp_bool = */ NULL }, /* .tp_call = */ NULL, - /* .tp_visit = */ (void (DCALL *)(DeeObject *__restrict, dvisit_t, void *))&comiter_visit, + /* .tp_visit = */ (void (DCALL *)(DeeObject *__restrict, dvisit_t, void *))&src_visit, /* .tp_gc = */ NULL, /* .tp_math = */ NULL, - /* .tp_cmp = */ &comiter_cmp, - /* .tp_seq = */ NULL, - /* .tp_iter_next = */ (DREF DeeObject *(DCALL *)(DeeObject *__restrict))&rcomiter_next, + /* .tp_cmp = */ NULL, + /* .tp_seq = */ &src_seq, + /* .tp_iter_next = */ NULL, /* .tp_iterator = */ NULL, /* .tp_attr = */ NULL, /* .tp_with = */ NULL, /* .tp_buffer = */ NULL, /* .tp_methods = */ NULL, - /* .tp_getsets = */ NULL, - /* .tp_members = */ rcomiter_members, + /* .tp_getsets = */ src_getsets, + /* .tp_members = */ src_members, /* .tp_class_methods = */ NULL, /* .tp_class_getsets = */ NULL, - /* .tp_class_members = */ NULL -}; - -PRIVATE WUNUSED NONNULL((1)) DREF CombinationsIterator *DCALL -rcom_iter(Combinations *__restrict self) { - DREF CombinationsIterator *result; - result = DeeObject_MALLOC(CombinationsIterator); - if unlikely(!result) - goto done; - result->ci_combi = self; - Dee_atomic_rwlock_init(&result->ci_lock); - result->ci_indices = (size_t *)Dee_Callocc(self->c_comlen, sizeof(size_t)); - if unlikely(!result->ci_indices) - goto err_r; - result->ci_first = true; - Dee_Incref(self); - DeeObject_Init(result, &SeqRepeatCombinationsIterator_Type); -done: - return result; -err_r: - DeeObject_FREE(result); - return NULL; -} - -PRIVATE struct type_seq rcom_seq = { - /* .tp_iter = */ (DREF DeeObject *(DCALL *)(DeeObject *__restrict))&rcom_iter -}; - -PRIVATE struct type_member tpconst rcom_class_members[] = { - TYPE_MEMBER_CONST(STR_Iterator, &SeqRepeatCombinationsIterator_Type), - TYPE_MEMBER_END + /* .tp_class_members = */ src_class_members }; -#define rcom_members com_members - -INTERN DeeTypeObject SeqRepeatCombinations_Type = { +INTERN DeeTypeObject SeqPermutations_Type = { OBJECT_HEAD_INIT(&DeeType_Type), - /* .tp_name = */ "_SeqRepeatCombinations", - /* .tp_doc = */ NULL, + /* .tp_name = */ "_SeqPermutations", + /* .tp_doc = */ DOC("()\n" + "(seq:?DSequence,r?:?Dint)"), /* .tp_flags = */ TP_FNORMAL | TP_FFINAL, /* .tp_weakrefs = */ 0, /* .tp_features = */ TF_NONE, @@ -765,274 +403,889 @@ INTERN DeeTypeObject SeqRepeatCombinations_Type = { /* .tp_init = */ { { /* .tp_alloc = */ { - /* .tp_ctor = */ (dfunptr_t)&com_ctor, - /* .tp_copy_ctor = */ (dfunptr_t)&com_copy, - /* .tp_deep_ctor = */ (dfunptr_t)&com_deepcopy, - /* .tp_any_ctor = */ (dfunptr_t)NULL, /* TODO */ - TYPE_FIXED_ALLOCATOR(Combinations) + /* .tp_ctor = */ (dfunptr_t)&sp_ctor, + /* .tp_copy_ctor = */ (dfunptr_t)&sp_copy, + /* .tp_deep_ctor = */ (dfunptr_t)&sp_deep, + /* .tp_any_ctor = */ (dfunptr_t)&sp_init, + TYPE_FIXED_ALLOCATOR(SeqCombinations) } }, - /* .tp_dtor = */ (void (DCALL *)(DeeObject *__restrict))&com_fini, + /* .tp_dtor = */ (void (DCALL *)(DeeObject *__restrict))&sp_fini, /* .tp_assign = */ NULL, /* .tp_move_assign = */ NULL }, /* .tp_cast = */ { /* .tp_str = */ NULL, /* .tp_repr = */ NULL, - /* .tp_bool = */ (int (DCALL *)(DeeObject *__restrict))&com_bool + /* .tp_bool = */ NULL }, /* .tp_call = */ NULL, - /* .tp_visit = */ (void (DCALL *)(DeeObject *__restrict, dvisit_t, void *))&com_visit, + /* .tp_visit = */ (void (DCALL *)(DeeObject *__restrict, dvisit_t, void *))&sp_visit, /* .tp_gc = */ NULL, /* .tp_math = */ NULL, /* .tp_cmp = */ NULL, - /* .tp_seq = */ &rcom_seq, + /* .tp_seq = */ &sp_seq, /* .tp_iter_next = */ NULL, /* .tp_iterator = */ NULL, /* .tp_attr = */ NULL, /* .tp_with = */ NULL, /* .tp_buffer = */ NULL, /* .tp_methods = */ NULL, - /* .tp_getsets = */ NULL, - /* .tp_members = */ rcom_members, + /* .tp_getsets = */ sp_getsets, + /* .tp_members = */ sp_members, /* .tp_class_methods = */ NULL, /* .tp_class_getsets = */ NULL, - /* .tp_class_members = */ rcom_class_members + /* .tp_class_members = */ sp_class_members }; -PRIVATE WUNUSED NONNULL((1)) DREF DeeTupleObject *DCALL -pmutiter_next(CombinationsIterator *__restrict self) { - DREF DeeTupleObject *result; - size_t *result_indices, i, comlen, seqlen; - comlen = self->ci_combi->c_comlen; - seqlen = self->ci_combi->c_seqlen; - result_indices = (size_t *)Dee_Mallocac(comlen, sizeof(size_t)); - if unlikely(!result_indices) + + + + + + + + + + + + + +/************************************************************************/ +/* ITERATOR */ +/************************************************************************/ + +PRIVATE WUNUSED NONNULL((1)) DREF SeqCombinationsIterator *DCALL +generic_default_iter_of(DeeTypeObject *__restrict type) { + DREF SeqCombinationsIterator *result; + DREF SeqCombinations *com; + com = (DREF SeqCombinations *)DeeObject_NewDefault(type); + if unlikely(!com) goto err; - CombinationsIterator_LockWrite(self); - if (self->ci_first) { - self->ci_first = false; - goto copy_indices; - } - if (self->ci_indices[0] >= seqlen) { - /* Signal `ITER_DONE' */ -signal_done: - CombinationsIterator_LockEndWrite(self); - Dee_Freea(result_indices); - return (DREF DeeTupleObject *)ITER_DONE; - } - i = comlen; - for (;;) { - size_t j, index; - --i; + result = (DREF SeqCombinationsIterator *)DeeObject_Iter((DeeObject *)com); + Dee_Decref_unlikely(com); + return result; +err: + return NULL; +} + +PRIVATE WUNUSED DREF SeqCombinationsIterator *DCALL sci_ctor(void) { + return generic_default_iter_of(&SeqCombinations_Type); +} + +PRIVATE WUNUSED DREF SeqCombinationsIterator *DCALL srci_ctor(void) { + return generic_default_iter_of(&SeqRepeatCombinations_Type); +} + +PRIVATE WUNUSED DREF SeqCombinationsIterator *DCALL spi_ctor(void) { + return generic_default_iter_of(&SeqPermutations_Type); +} + +#define srci_copy sci_copy +#define spi_copy sci_copy +PRIVATE WUNUSED NONNULL((1)) DREF SeqCombinationsIterator *DCALL +sci_copy(SeqCombinationsIterator *__restrict self) { + DREF SeqCombinationsIterator *result; + size_t i, rparam = atomic_read(&self->sci_com->sc_rparam); + result = (DREF SeqCombinationsIterator *)DeeObject_Mallocc(offsetof(SeqCombinationsIterator, sci_idx), + rparam, sizeof(size_t)); + if unlikely(!result) + goto err; + Dee_Incref(self->sci_com); + result->sci_com = self->sci_com; + for (i = 0; i < rparam; ++i) + result->sci_idx[i] = atomic_read(&self->sci_idx[i]); + Dee_weakref_initempty(&result->sci_view); + DeeObject_Init(result, Dee_TYPE(self)); + return result; +err: + return NULL; +} + +#define srci_deep sci_deep +#define spi_deep sci_deep +PRIVATE WUNUSED NONNULL((1)) DREF SeqCombinationsIterator *DCALL +sci_deep(SeqCombinationsIterator *__restrict self) { + DREF SeqCombinationsIterator *result = sci_copy(self); + if (DeeObject_InplaceDeepCopy((DREF DeeObject **)&result->sci_com)) + goto err_r; + return result; +err_r: + Dee_DecrefDokill(result); + return NULL; +} + +PRIVATE WUNUSED NONNULL((3, 4)) DREF SeqCombinationsIterator *DCALL +sci_init_generic(size_t argc, DeeObject *const *argv, + DeeTypeObject *expected_seq_type, + DeeTypeObject *returned_iter_type) { + SeqCombinations *com; + if unlikely(argc != 1) + goto err_bad_argc; + com = (DREF SeqCombinations *)argv[0]; + if (DeeObject_AssertTypeExact(com, expected_seq_type)) + goto err; + return (DREF SeqCombinationsIterator *)DeeObject_Iter((DeeObject *)com); +err_bad_argc: + err_invalid_argc(returned_iter_type->tp_name, argc, 1, 1); +err: + return NULL; +} + +PRIVATE WUNUSED DREF SeqCombinationsIterator *DCALL +sci_init(size_t argc, DeeObject *const *argv) { + return sci_init_generic(argc, argv, &SeqCombinations_Type, &SeqCombinationsIterator_Type); +} + +PRIVATE WUNUSED DREF SeqCombinationsIterator *DCALL +srci_init(size_t argc, DeeObject *const *argv) { + return sci_init_generic(argc, argv, &SeqRepeatCombinations_Type, &SeqRepeatCombinationsIterator_Type); +} + +PRIVATE WUNUSED DREF SeqCombinationsIterator *DCALL +spi_init(size_t argc, DeeObject *const *argv) { + return sci_init_generic(argc, argv, &SeqPermutations_Type, &SeqPermutationsIterator_Type); +} + +#define srci_fini sci_fini +#define spi_fini sci_fini +PRIVATE NONNULL((1)) void DCALL +sci_fini(SeqCombinationsIterator *__restrict self) { + Dee_Decref(self->sci_com); + Dee_weakref_fini(&self->sci_view); +} + +STATIC_ASSERT(offsetof(SeqCombinationsIterator, sci_com) == offsetof(ProxyObject, po_obj)); +#define sci_visit generic_proxy_visit +#define srci_visit generic_proxy_visit +#define spi_visit generic_proxy_visit + +PRIVATE WUNUSED NONNULL((1)) int DCALL +sci_unshare_view(SeqCombinationsIterator *__restrict self) { + DREF SeqCombinationsView *view; + view = (DREF SeqCombinationsView *)Dee_weakref_lock(&self->sci_view); + if (!view) + return 0; + if (SeqCombinationsView_GetIdx(view) == self->sci_idx) { + /* Do the unshare */ + size_t i, rparam = self->sci_com->sc_rparam, *idx_copy; + idx_copy = (size_t *)Dee_Mallocc(rparam, sizeof(size_t)); + if unlikely(!idx_copy) + goto err_view; + for (i = 0; i < rparam; ++i) + idx_copy[i] = atomic_read(&self->sci_idx[i]); + /* Store the unshared copy within the view (this also asserts + * that no other thread already did this in the mean-time, and + * if some other thread did, then we simply free our copy) */ + if unlikely(!SeqCombinationsView_SetIdx(view, idx_copy)) + Dee_Free(idx_copy); + } + Dee_Decref_unlikely(view); + /* Clear the weakref since its indices won't reference us anymore. */ + (void)Dee_weakref_clear(&self->sci_view); + return 0; +err_view: + Dee_Decref_unlikely(view); + return -1; +} + +#define srci_getview sci_getview +#define spi_getview sci_getview +PRIVATE WUNUSED NONNULL((1)) DREF SeqCombinationsView *DCALL +sci_getview(SeqCombinationsIterator *__restrict self) { + DREF SeqCombinationsView *result; + result = (DREF SeqCombinationsView *)Dee_weakref_lock(&self->sci_view); + if (!result) { + DREF SeqCombinationsView *old_view; + /* Lazily allocate view */ + result = DeeObject_MALLOC(SeqCombinationsView); + if unlikely(!result) + goto err; + Dee_Incref(self); + result->scv_iter = self; + result->scv_com = self->sci_com; + result->scv_idx = self->sci_idx; + weakref_support_init(result); + DeeObject_Init(result, &SeqCombinationsView_Type); + COMPILER_WRITE_BARRIER(); + + /* Cache the view within the weakref, and handle the + * case where another view was created in the mean-time. */ + old_view = (DREF SeqCombinationsView *)Dee_weakref_cmpxch(&self->sci_view, NULL, + (DeeObject *)result); + ASSERT(old_view != (DREF SeqCombinationsView *)ITER_DONE); + if unlikely(old_view) { + Dee_DecrefDokill(result); + result = old_view; + } + } + return result; +err: + return NULL; +} + +#define srci_assign sci_assign +#define spi_assign sci_assign +PRIVATE WUNUSED NONNULL((1, 2)) int DCALL +sci_assign(SeqCombinationsIterator *self, + SeqCombinationsIterator *other) { + size_t i; + if unlikely(self == other) + return 0; + if (DeeObject_AssertTypeExact(other, Dee_TYPE(self))) + goto err; + if unlikely(self->sci_com->sc_seq != other->sci_com->sc_seq || + self->sci_com->sc_rparam != other->sci_com->sc_rparam) + goto wrong_com; + if unlikely(sci_unshare_view(self)) + goto err; + for (i = 0; i < self->sci_com->sc_rparam; ++i) + self->sci_idx[i] = atomic_read(&other->sci_idx[i]); + return 0; +wrong_com: + DeeError_Throwf(&DeeError_ValueError, + "Cannot assign incompatible combination iterators"); +err: + return -1; +} + +PRIVATE WUNUSED NONNULL((1)) int DCALL +sci_bool(SeqCombinationsIterator *__restrict self) { + size_t i, rparam = self->sci_com->sc_rparam; + size_t seqsize = self->sci_com->sc_seqsize; + size_t value; + ASSERT(rparam != (size_t)-1); + ASSERT(seqsize != (size_t)-1); + ASSERT(rparam > 0); + i = rparam; + do { + --i; + value = atomic_read(&self->sci_idx[i]); + if (value < i + seqsize - rparam) + return 1; + } while (i); + return 0; +} + +PRIVATE WUNUSED NONNULL((1)) int DCALL +srci_bool(SeqCombinationsIterator *__restrict self) { + size_t i, rparam = self->sci_com->sc_rparam; + size_t offset, seqsize = self->sci_com->sc_seqsize; + ASSERT(rparam != (size_t)-1); + ASSERT(seqsize != (size_t)-1); + ASSERT(rparam > 0); + i = rparam; + do { + --i; + offset = atomic_read(&self->sci_idx[i]) + 1; + if (offset < seqsize) + return 1; + } while (i); + return 0; +} + +PRIVATE WUNUSED NONNULL((1)) int DCALL +spi_bool(SeqCombinationsIterator *__restrict self) { + size_t i, rparam = self->sci_com->sc_rparam; + size_t seqsize = self->sci_com->sc_seqsize; + ASSERT(rparam != (size_t)-1); + ASSERT(seqsize != (size_t)-1); + ASSERT(rparam > 0); + /* For "ABCD".permutations(3), the final state is "DCB", so check for that! */ + i = 0; + do { + if ((self->sci_idx[i] + 1) < (seqsize - i)) + return 1; + } while (++i < rparam); + return 0; +} + +PRIVATE WUNUSED NONNULL((1)) bool DCALL +sci_inc(SeqCombinationsIterator *__restrict self) { + size_t i, rparam = self->sci_com->sc_rparam; + size_t seqsize = self->sci_com->sc_seqsize; + size_t value; + ASSERT(rparam != (size_t)-1); + ASSERT(seqsize != (size_t)-1); + ASSERT(rparam > 0); + i = rparam; + do { + --i; + value = atomic_read(&self->sci_idx[i]); + if (value < i + seqsize - rparam) + goto do_inc_at_i; + } while (i); + return false; +do_inc_at_i: + do { + ++value; + atomic_write(&self->sci_idx[i], value); + } while (++i < rparam); + return true; +} + +PRIVATE WUNUSED NONNULL((1)) bool DCALL +srci_inc(SeqCombinationsIterator *__restrict self) { + size_t i, rparam = self->sci_com->sc_rparam; + size_t offset, seqsize = self->sci_com->sc_seqsize; + ASSERT(rparam != (size_t)-1); + ASSERT(seqsize != (size_t)-1); + ASSERT(rparam > 0); + i = rparam; + do { + --i; + offset = atomic_read(&self->sci_idx[i]) + 1; + if (offset < seqsize) + goto do_inc_at_i; + } while (i); + return false; +do_inc_at_i: + do { + atomic_write(&self->sci_idx[i], offset); + } while (++i < rparam); + return true; +} + +PRIVATE WUNUSED NONNULL((1)) bool DCALL +spi_inc(SeqCombinationsIterator *__restrict self) { + size_t i, rparam = self->sci_com->sc_rparam; + size_t seqsize = self->sci_com->sc_seqsize; + ASSERT(rparam != (size_t)-1); + ASSERT(seqsize != (size_t)-1); + ASSERT(rparam > 0); + if (self->sci_idx[0] >= seqsize && (self->sci_idx[0] != (size_t)-1 && rparam != 0)) + return false; + i = rparam; + for (;;) { + size_t j, index; + --i; increment_i: - if (++self->ci_indices[i] >= seqlen) { + if (++self->sci_idx[i] >= seqsize) { if (i == 0) { - self->ci_indices[i] = seqlen - 1; - goto signal_done; + self->sci_idx[i] = seqsize - 1; + return false; } - self->ci_indices[i] = 0; + self->sci_idx[i] = 0; continue; } - index = self->ci_indices[i]; - for (j = 0; j < comlen; ++j) { + index = self->sci_idx[i]; + for (j = 0; j < rparam; ++j) { if (j == i) continue; - if (self->ci_indices[j] == index) + if (self->sci_idx[j] == index) goto increment_i; } break; } -copy_indices: - memcpyc(result_indices, - self->ci_indices, - comlen, - sizeof(size_t)); - CombinationsIterator_LockEndWrite(self); - result = DeeTuple_NewUninitialized(comlen); - if unlikely(!result) - goto err_indices; - for (i = 0; i < comlen; ++i) { - DREF DeeObject *temp; - temp = Combinations_GetSeqItem(self->ci_combi, - result_indices[i]); - if unlikely(!temp) - goto err_indices_r; - DeeTuple_SET(result, i, temp); /* Inherit reference. */ - } - Dee_Freea(result_indices); - return result; -err_indices_r: - Dee_Decrefv(DeeTuple_ELEM(result), i); - DeeTuple_FreeUninitialized(result); -err_indices: - Dee_Freea(result_indices); -err: - return NULL; + return true; } -PRIVATE struct type_member tpconst pmutiter_members[] = { - TYPE_MEMBER_FIELD_DOC(STR_seq, STRUCT_OBJECT, offsetof(CombinationsIterator, ci_combi), "->?Ert:SeqPermutations"), - TYPE_MEMBER_END -}; +PRIVATE WUNUSED NONNULL((1)) DREF SeqCombinationsView *DCALL +sci_next(SeqCombinationsIterator *__restrict self) { + if (!sci_inc(self)) + return (DREF SeqCombinationsView *)ITER_DONE; + return sci_getview(self); +} -PRIVATE WUNUSED NONNULL((1)) int DCALL -pmutiter_ctor(CombinationsIterator *__restrict self) { - self->ci_combi = (DREF Combinations *)DeeObject_NewDefault(&SeqPermutations_Type); - if unlikely(!self->ci_combi) - goto err; - self->ci_indices = (size_t *)Dee_Callocc(self->ci_combi->c_comlen, - sizeof(size_t)); - if unlikely(!self->ci_indices) - goto err_combi; - self->ci_first = true; - Dee_atomic_rwlock_init(&self->ci_lock); - return 0; -err_combi: - Dee_Decref_likely(self->ci_combi); -err: - return -1; +PRIVATE WUNUSED NONNULL((1)) DREF SeqCombinationsView *DCALL +srci_next(SeqCombinationsIterator *__restrict self) { + if (!srci_inc(self)) + return (DREF SeqCombinationsView *)ITER_DONE; + return srci_getview(self); } -PRIVATE WUNUSED NONNULL((1)) int DCALL -pmutiter_init(CombinationsIterator *__restrict self, - size_t argc, DeeObject *const *argv) { - size_t i, comlen; - if (DeeArg_Unpack(argc, argv, "o:_SeqPermutationsIterator", &self->ci_combi)) - goto err; - if (DeeObject_AssertTypeExact(self->ci_combi, &SeqPermutations_Type)) - goto err; - Dee_atomic_rwlock_init(&self->ci_lock); - comlen = self->ci_combi->c_comlen; - self->ci_indices = (size_t *)Dee_Mallocc(comlen, sizeof(size_t)); - if unlikely(!self->ci_indices) +PRIVATE WUNUSED NONNULL((1)) DREF SeqCombinationsView *DCALL +spi_next(SeqCombinationsIterator *__restrict self) { + if (!spi_inc(self)) + return (DREF SeqCombinationsView *)ITER_DONE; + return spi_getview(self); +} + +#define srci_compare sci_compare +#define spi_compare sci_compare +PRIVATE WUNUSED NONNULL((1, 2)) int DCALL +sci_compare(SeqCombinationsIterator *lhs, SeqCombinationsIterator *rhs) { + size_t i, rparam; + if (DeeObject_AssertTypeExact(rhs, Dee_TYPE(lhs))) goto err; - for (i = 0; i < comlen; ++i) - self->ci_indices[i] = i; - self->ci_first = true; - Dee_Incref(self->ci_combi); + Dee_return_compare_if_ne(lhs->sci_com, lhs->sci_com); + rparam = lhs->sci_com->sc_rparam; + ASSERT(rparam != (size_t)-1); + /* All combinations iterators increment starting at "sci_idx[0]", + * so we can compare all of them the same way by starting at the + * greatest index "sci_idx[rparam - 1]" */ + i = rparam; + do { + Dee_ssize_t lhs_index, rhs_index; + --i; + /* Force use of signed indices here, so we're correctly handling + * the case where we make use of integer roll-over to represent + * the -1'th matrix state (as set-up for the initial state) */ + lhs_index = (Dee_ssize_t)atomic_read(&lhs->sci_idx[i]); + rhs_index = (Dee_ssize_t)atomic_read(&rhs->sci_idx[i]); + Dee_return_compare_if_ne(lhs_index, rhs_index); + } while (i); return 0; err: - return -1; + return Dee_COMPARE_ERR; } +#define srci_cmp sci_cmp +#define spi_cmp sci_cmp +PRIVATE struct type_cmp sci_cmp = { + /* .tp_hash = */ NULL, + /* .tp_compare_eq = */ NULL, + /* .tp_compare = */ (int (DCALL *)(DeeObject *, DeeObject *))&sci_compare, +}; + +#define srci_getsets sci_getsets +#define spi_getsets sci_getsets +PRIVATE struct type_getset tpconst sci_getsets[] = { + TYPE_GETTER("__view__", &sci_getview, "->?Ert:SeqCombinationsView"), + TYPE_GETSET_END +}; + +#define srci_members sci_members +#define spi_members sci_members +PRIVATE struct type_member tpconst sci_members[] = { + TYPE_MEMBER_FIELD_DOC("__wview__", STRUCT_WOBJECT, + offsetof(SeqCombinationsIterator, sci_view), + "->?Ert:SeqCombinationsView"), + TYPE_MEMBER_END +}; + +INTERN DeeTypeObject SeqCombinationsIterator_Type = { + OBJECT_HEAD_INIT(&DeeType_Type), + /* .tp_name = */ "_SeqCombinationsIterator", + /* .tp_doc = */ DOC("(seq?:?Ert:SeqCombinations)\n" + "\n" + "iter->?Ert:SeqCombinationsView"), + /* .tp_flags = */ TP_FNORMAL | TP_FVARIABLE | TP_FFINAL, + /* .tp_weakrefs = */ 0, + /* .tp_features = */ TF_NONE, + /* .tp_base = */ &DeeIterator_Type, + /* .tp_init = */ { + { + /* .tp_var = */ { + /* .tp_ctor = */ (dfunptr_t)&sci_ctor, + /* .tp_copy_ctor = */ (dfunptr_t)&sci_copy, + /* .tp_deep_ctor = */ (dfunptr_t)&sci_deep, + /* .tp_any_ctor = */ (dfunptr_t)&sci_init, + } + }, + /* .tp_dtor = */ (void (DCALL *)(DeeObject *__restrict))&sci_fini, + /* .tp_assign = */ (int (DCALL *)(DeeObject *, DeeObject *))&sci_assign, + /* .tp_move_assign = */ NULL + }, + /* .tp_cast = */ { + /* .tp_str = */ NULL, + /* .tp_repr = */ NULL, + /* .tp_bool = */ (int (DCALL *)(DeeObject *__restrict))&sci_bool + }, + /* .tp_call = */ NULL, + /* .tp_visit = */ (void (DCALL *)(DeeObject *__restrict, dvisit_t, void *))&sci_visit, + /* .tp_gc = */ NULL, + /* .tp_math = */ NULL, + /* .tp_cmp = */ &sci_cmp, + /* .tp_seq = */ NULL, + /* .tp_iter_next = */ (DREF DeeObject *(DCALL *)(DeeObject *__restrict))&sci_next, + /* .tp_iterator = */ NULL, + /* .tp_attr = */ NULL, + /* .tp_with = */ NULL, + /* .tp_buffer = */ NULL, + /* .tp_methods = */ NULL, + /* .tp_getsets = */ sci_getsets, + /* .tp_members = */ sci_members, + /* .tp_class_methods = */ NULL, + /* .tp_class_getsets = */ NULL, + /* .tp_class_members = */ NULL, +}; + +INTERN DeeTypeObject SeqRepeatCombinationsIterator_Type = { + OBJECT_HEAD_INIT(&DeeType_Type), + /* .tp_name = */ "_SeqRepeatCombinationsIterator", + /* .tp_doc = */ DOC("(seq?:?Ert:SeqRepeatCombinations)\n" + "\n" + "iter->?Ert:SeqCombinationsView"), + /* .tp_flags = */ TP_FNORMAL | TP_FVARIABLE | TP_FFINAL, + /* .tp_weakrefs = */ 0, + /* .tp_features = */ TF_NONE, + /* .tp_base = */ &DeeIterator_Type, + /* .tp_init = */ { + { + /* .tp_var = */ { + /* .tp_ctor = */ (dfunptr_t)&srci_ctor, + /* .tp_copy_ctor = */ (dfunptr_t)&srci_copy, + /* .tp_deep_ctor = */ (dfunptr_t)&srci_deep, + /* .tp_any_ctor = */ (dfunptr_t)&srci_init, + } + }, + /* .tp_dtor = */ (void (DCALL *)(DeeObject *__restrict))&srci_fini, + /* .tp_assign = */ (int (DCALL *)(DeeObject *, DeeObject *))&srci_assign, + /* .tp_move_assign = */ NULL + }, + /* .tp_cast = */ { + /* .tp_str = */ NULL, + /* .tp_repr = */ NULL, + /* .tp_bool = */ (int (DCALL *)(DeeObject *__restrict))&srci_bool + }, + /* .tp_call = */ NULL, + /* .tp_visit = */ (void (DCALL *)(DeeObject *__restrict, dvisit_t, void *))&srci_visit, + /* .tp_gc = */ NULL, + /* .tp_math = */ NULL, + /* .tp_cmp = */ &srci_cmp, + /* .tp_seq = */ NULL, + /* .tp_iter_next = */ (DREF DeeObject *(DCALL *)(DeeObject *__restrict))&srci_next, + /* .tp_iterator = */ NULL, + /* .tp_attr = */ NULL, + /* .tp_with = */ NULL, + /* .tp_buffer = */ NULL, + /* .tp_methods = */ NULL, + /* .tp_getsets = */ srci_getsets, + /* .tp_members = */ srci_members, + /* .tp_class_methods = */ NULL, + /* .tp_class_getsets = */ NULL, + /* .tp_class_members = */ NULL, +}; + INTERN DeeTypeObject SeqPermutationsIterator_Type = { OBJECT_HEAD_INIT(&DeeType_Type), /* .tp_name = */ "_SeqPermutationsIterator", - /* .tp_doc = */ DOC("(seq?:?Ert:SeqPermutations)"), - /* .tp_flags = */ TP_FNORMAL | TP_FFINAL, + /* .tp_doc = */ DOC("(seq?:?Ert:SeqPermutations)\n" + "\n" + "iter->?Ert:SeqCombinationsView"), + /* .tp_flags = */ TP_FNORMAL | TP_FVARIABLE | TP_FFINAL, /* .tp_weakrefs = */ 0, /* .tp_features = */ TF_NONE, /* .tp_base = */ &DeeIterator_Type, /* .tp_init = */ { { - /* .tp_alloc = */ { - /* .tp_ctor = */ (dfunptr_t)&pmutiter_ctor, - /* .tp_copy_ctor = */ (dfunptr_t)&comiter_copy, - /* .tp_deep_ctor = */ (dfunptr_t)&comiter_deep, - /* .tp_any_ctor = */ (dfunptr_t)&pmutiter_init, - TYPE_FIXED_ALLOCATOR(CombinationsIterator) + /* .tp_var = */ { + /* .tp_ctor = */ (dfunptr_t)&spi_ctor, + /* .tp_copy_ctor = */ (dfunptr_t)&spi_copy, + /* .tp_deep_ctor = */ (dfunptr_t)&spi_deep, + /* .tp_any_ctor = */ (dfunptr_t)&spi_init, } }, - /* .tp_dtor = */ (void (DCALL *)(DeeObject *__restrict))&comiter_fini, - /* .tp_assign = */ NULL, + /* .tp_dtor = */ (void (DCALL *)(DeeObject *__restrict))&spi_fini, + /* .tp_assign = */ (int (DCALL *)(DeeObject *, DeeObject *))&spi_assign, /* .tp_move_assign = */ NULL }, /* .tp_cast = */ { /* .tp_str = */ NULL, /* .tp_repr = */ NULL, - /* .tp_bool = */ NULL + /* .tp_bool = */ (int (DCALL *)(DeeObject *__restrict))&spi_bool }, /* .tp_call = */ NULL, - /* .tp_visit = */ (void (DCALL *)(DeeObject *__restrict, dvisit_t, void *))&comiter_visit, + /* .tp_visit = */ (void (DCALL *)(DeeObject *__restrict, dvisit_t, void *))&spi_visit, /* .tp_gc = */ NULL, /* .tp_math = */ NULL, - /* .tp_cmp = */ &comiter_cmp, + /* .tp_cmp = */ &spi_cmp, /* .tp_seq = */ NULL, - /* .tp_iter_next = */ (DREF DeeObject *(DCALL *)(DeeObject *__restrict))&pmutiter_next, + /* .tp_iter_next = */ (DREF DeeObject *(DCALL *)(DeeObject *__restrict))&spi_next, /* .tp_iterator = */ NULL, /* .tp_attr = */ NULL, /* .tp_with = */ NULL, /* .tp_buffer = */ NULL, /* .tp_methods = */ NULL, - /* .tp_getsets = */ NULL, - /* .tp_members = */ pmutiter_members, + /* .tp_getsets = */ spi_getsets, + /* .tp_members = */ spi_members, /* .tp_class_methods = */ NULL, /* .tp_class_getsets = */ NULL, - /* .tp_class_members = */ NULL + /* .tp_class_members = */ NULL, }; -PRIVATE WUNUSED NONNULL((1)) DREF CombinationsIterator *DCALL -pmut_iter(Combinations *__restrict self) { - DREF CombinationsIterator *result; - size_t i, comlen; - result = DeeObject_MALLOC(CombinationsIterator); - if unlikely(!result) - goto done; - result->ci_combi = self; - Dee_atomic_rwlock_init(&result->ci_lock); - comlen = self->c_comlen; - result->ci_indices = (size_t *)Dee_Mallocc(comlen, sizeof(size_t)); - if unlikely(!result->ci_indices) - goto err_r; - for (i = 0; i < comlen; ++i) - result->ci_indices[i] = i; - result->ci_first = true; - Dee_Incref(self); - DeeObject_Init(result, &SeqPermutationsIterator_Type); -done: - return result; -err_r: - DeeObject_FREE(result); - return NULL; + + + + + + + + + + + + + + +/************************************************************************/ +/* VIEW */ +/************************************************************************/ + +STATIC_ASSERT(offsetof(SeqCombinationsView, scv_iter) == offsetof(ProxyObject, po_obj)); +#define scv_visit generic_proxy_visit + +PRIVATE WUNUSED NONNULL((1)) int DCALL +scv_ctor(SeqCombinationsView *__restrict self) { + self->scv_iter = (DREF SeqCombinationsIterator *)DeeObject_NewDefault(&SeqCombinationsIterator_Type); + if unlikely(!self->scv_iter) + goto err; + self->scv_com = self->scv_iter->sci_com; + self->scv_idx = self->scv_iter->sci_idx; + Dee_weakref_support_init(self); + (void)Dee_weakref_set(&self->scv_iter->sci_view, (DeeObject *)self); + return 0; +err: + return -1; } -PRIVATE struct type_seq pmut_seq = { - /* .tp_iter = */ (DREF DeeObject *(DCALL *)(DeeObject *__restrict))&pmut_iter -}; +PRIVATE NONNULL((1)) void DCALL +scv_fini(SeqCombinationsView *__restrict self) { + if unlikely(self->scv_idx != self->scv_iter->sci_idx) + Dee_Free(self->scv_idx); + Dee_Decref_unlikely(self->scv_iter); + Dee_weakref_support_fini(self); +} -PRIVATE struct type_member tpconst pmut_class_members[] = { - TYPE_MEMBER_CONST(STR_Iterator, &SeqPermutationsIterator_Type), +PRIVATE WUNUSED NONNULL((1, 2)) int DCALL +scv_copy(SeqCombinationsView *__restrict self, + SeqCombinationsView *__restrict other) { + size_t i, rparam = other->scv_com->sc_rparam, *idx_copy, *idx_other; + idx_copy = (size_t *)Dee_Mallocc(rparam, sizeof(size_t)); + if unlikely(!idx_copy) + goto err; + idx_other = SeqCombinationsView_GetIdx(other); + for (i = 0; i < rparam; ++i) + idx_copy[i] = atomic_read(&idx_other[i]); + self->scv_idx = idx_copy; + Dee_Incref(other->scv_iter); + self->scv_iter = other->scv_iter; + self->scv_com = self->scv_iter->sci_com; + Dee_weakref_support_init(self); + return 0; +err: + return -1; +} + +PRIVATE WUNUSED NONNULL((1, 2)) int DCALL +scv_deep(SeqCombinationsView *__restrict self, + SeqCombinationsView *__restrict other) { + if unlikely(scv_copy(self, other)) + goto err; + if (DeeObject_InplaceDeepCopy((DeeObject **)&self->scv_iter)) + goto err_self; + self->scv_com = self->scv_iter->sci_com; + return 0; +err_self: + scv_fini(self); +err: + return -1; +} + +PRIVATE WUNUSED NONNULL((1)) int DCALL +scv_init(SeqCombinationsView *__restrict self, + size_t argc, DeeObject *const *argv) { + size_t i, rparam, *idx_copy, *idx_other; + if (DeeArg_Unpack(argc, argv, "o:_SeqCombinationsView", &self->scv_iter)) + goto err; + if unlikely(!DeeObject_InstanceOfExact(self->scv_iter, &SeqCombinationsIterator_Type) && + !DeeObject_InstanceOfExact(self->scv_iter, &SeqRepeatCombinationsIterator_Type) && + !DeeObject_InstanceOfExact(self->scv_iter, &SeqPermutationsIterator_Type)) + goto err_bad_iter_type; + self->scv_com = self->scv_iter->sci_com; + rparam = self->scv_com->sc_rparam; + idx_copy = (size_t *)Dee_Mallocc(rparam, sizeof(size_t)); + if unlikely(!idx_copy) + goto err; + idx_other = self->scv_iter->sci_idx; + for (i = 0; i < rparam; ++i) + idx_copy[i] = atomic_read(&idx_other[i]); + self->scv_idx = idx_copy; + Dee_Incref(self->scv_iter); + Dee_weakref_support_init(self); + return 0; +err_bad_iter_type: + DeeObject_TypeAssertFailed3((DeeObject *)self->scv_iter, + &SeqCombinationsIterator_Type, + &SeqRepeatCombinationsIterator_Type, + &SeqPermutationsIterator_Type); +err: + return -1; +} + +PRIVATE struct type_member tpconst scv_members[] = { + TYPE_MEMBER_FIELD_DOC("__iter__", STRUCT_OBJECT, offsetof(SeqCombinationsView, scv_iter), + "->?X3?Ert:SeqCombinationsIterator" + /**/ "?Ert:SeqRepeatCombinationsIterator" + /**/ "?Ert:SeqPermutationsIterator"), + TYPE_MEMBER_FIELD_DOC("__com__", STRUCT_OBJECT, offsetof(SeqCombinationsView, scv_com), + "->?X3?Ert:SeqCombinations" + /**/ "?Ert:SeqRepeatCombinations" + /**/ "?Ert:SeqPermutations"), TYPE_MEMBER_END }; -#define pmut_members com_members +PRIVATE WUNUSED NONNULL((1)) size_t DCALL +scv_size(SeqCombinationsView *__restrict self) { + ASSERT(self->scv_com->sc_rparam != (size_t)-1); + return self->scv_com->sc_rparam; +} -INTERN DeeTypeObject SeqPermutations_Type = { +PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL +scv_getitem_index(SeqCombinationsView *__restrict self, size_t index) { + size_t *idx = SeqCombinationsView_GetIdx(self); + ASSERT(self->scv_com->sc_rparam != (size_t)-1); + if unlikely(index >= self->scv_com->sc_rparam) + goto err_oob; + index = idx[index]; + return DeeSeq_OperatorGetItemIndex(self->scv_com->sc_seq, index); +err_oob: + err_index_out_of_bounds((DeeObject *)self, index, self->scv_com->sc_rparam); + return NULL; +} + +PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL +scv_trygetitem_index(SeqCombinationsView *__restrict self, size_t index) { + size_t *idx = SeqCombinationsView_GetIdx(self); + ASSERT(self->scv_com->sc_rparam != (size_t)-1); + if unlikely(index >= self->scv_com->sc_rparam) + return ITER_DONE; + index = idx[index]; + return (*self->scv_com->sc_trygetitem_index)(self->scv_com->sc_seq, index); +} + +PRIVATE WUNUSED NONNULL((1)) int DCALL +scv_bounditem_index(SeqCombinationsView *__restrict self, size_t index) { + size_t *idx = SeqCombinationsView_GetIdx(self); + ASSERT(self->scv_com->sc_rparam != (size_t)-1); + if unlikely(index >= self->scv_com->sc_rparam) + return -2; + index = idx[index]; + return DeeSeq_OperatorBoundItemIndex(self->scv_com->sc_seq, index); +} + +PRIVATE WUNUSED NONNULL((1)) Dee_ssize_t DCALL +scv_foreach(SeqCombinationsView *__restrict self, Dee_foreach_t cb, void *arg) { + Dee_ssize_t temp, result = 0; + size_t i, rparam = self->scv_com->sc_rparam, *idx = SeqCombinationsView_GetIdx(self); + ASSERT(rparam != (size_t)-1); + for (i = 0; i < rparam; ++i) { + DREF DeeObject *elem; + size_t index = idx[i]; + elem = (*self->scv_com->sc_trygetitem_index)(self->scv_com->sc_seq, index); + if unlikely(!ITER_ISOK(elem)) { + if unlikely(!elem) + goto err; + } else { + temp = (*cb)(arg, elem); + Dee_Decref(elem); + if unlikely(temp < 0) + goto err_temp; + result += temp; + } + } + return result; +err_temp: + return temp; +err: + return -1; +} + +PRIVATE WUNUSED NONNULL((1, 2)) Dee_ssize_t DCALL +scv_enumerate_index(SeqCombinationsView *__restrict self, Dee_enumerate_index_t proc, + void *arg, size_t start, size_t end) { + Dee_ssize_t temp, result = 0; + size_t i, *idx = SeqCombinationsView_GetIdx(self); + ASSERT(self->scv_com->sc_rparam != (size_t)-1); + if (end > self->scv_com->sc_rparam) + end = self->scv_com->sc_rparam; + for (i = start; i < end; ++i) { + DREF DeeObject *elem; + size_t index = idx[i]; + elem = (*self->scv_com->sc_trygetitem_index)(self->scv_com->sc_seq, index); + if unlikely(!ITER_ISOK(elem)) { + if unlikely(!elem) + goto err; + } else { + temp = (*proc)(arg, i, elem); + Dee_Decref(elem); + if unlikely(temp < 0) + goto err_temp; + result += temp; + } + } + return result; +err_temp: + return temp; +err: + return -1; +} + +PRIVATE struct type_seq scv_seq = { + /* .tp_iter = */ NULL, + /* .tp_sizeob = */ NULL, + /* .tp_contains = */ NULL, + /* .tp_getitem = */ NULL, + /* .tp_delitem = */ NULL, + /* .tp_setitem = */ NULL, + /* .tp_getrange = */ NULL, + /* .tp_delrange = */ NULL, + /* .tp_setrange = */ NULL, + /* .tp_nsi = */ NULL, + /* .tp_foreach = */ (Dee_ssize_t (DCALL *)(DeeObject *__restrict, Dee_foreach_t, void *))&scv_foreach, + /* .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))&scv_enumerate_index, + /* .tp_iterkeys = */ NULL, + /* .tp_bounditem = */ NULL, + /* .tp_hasitem = */ NULL, + /* .tp_size = */ (size_t (DCALL *)(DeeObject *__restrict))&scv_size, + /* .tp_size_fast = */ (size_t (DCALL *)(DeeObject *__restrict))&scv_size, + /* .tp_getitem_index = */ (DREF DeeObject *(DCALL *)(DeeObject *, size_t))&scv_getitem_index, + /* .tp_getitem_index_fast = */ NULL, + /* .tp_delitem_index = */ NULL, + /* .tp_setitem_index = */ NULL, + /* .tp_bounditem_index = */ (int (DCALL *)(DeeObject *, size_t))&scv_bounditem_index, + /* .tp_hasitem_index = */ &DeeSeq_DefaultHasItemIndexWithSize, + /* .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))&scv_trygetitem_index, +}; + +INTERN DeeTypeObject SeqCombinationsView_Type = { OBJECT_HEAD_INIT(&DeeType_Type), - /* .tp_name = */ "_SeqPermutations", - /* .tp_doc = */ NULL, + /* .tp_name = */ "_SeqCombinationsView", + /* .tp_doc = */ DOC("()\n" + "(iter:?X3?Ert:SeqCombinationsIterator" + /* */ "?Ert:SeqRepeatCombinationsIterator" + /* */ "?Ert:SeqPermutationsIterator)"), /* .tp_flags = */ TP_FNORMAL | TP_FFINAL, - /* .tp_weakrefs = */ 0, + /* .tp_weakrefs = */ WEAKREF_SUPPORT_ADDR(SeqCombinationsView), /* .tp_features = */ TF_NONE, /* .tp_base = */ &DeeSeq_Type, /* .tp_init = */ { { /* .tp_alloc = */ { - /* .tp_ctor = */ (dfunptr_t)&com_ctor, - /* .tp_copy_ctor = */ (dfunptr_t)&com_copy, - /* .tp_deep_ctor = */ (dfunptr_t)&com_deepcopy, - /* .tp_any_ctor = */ (dfunptr_t)NULL, /* TODO */ - TYPE_FIXED_ALLOCATOR(Combinations) + /* .tp_ctor = */ (dfunptr_t)&scv_ctor, + /* .tp_copy_ctor = */ (dfunptr_t)&scv_copy, + /* .tp_deep_ctor = */ (dfunptr_t)&scv_deep, + /* .tp_any_ctor = */ (dfunptr_t)&scv_init, + TYPE_FIXED_ALLOCATOR(SeqCombinationsView) } }, - /* .tp_dtor = */ (void (DCALL *)(DeeObject *__restrict))&com_fini, + /* .tp_dtor = */ (void (DCALL *)(DeeObject *__restrict))&scv_fini, /* .tp_assign = */ NULL, /* .tp_move_assign = */ NULL }, /* .tp_cast = */ { /* .tp_str = */ NULL, /* .tp_repr = */ NULL, - /* .tp_bool = */ (int (DCALL *)(DeeObject *__restrict))&com_bool + /* .tp_bool = */ NULL }, /* .tp_call = */ NULL, - /* .tp_visit = */ (void (DCALL *)(DeeObject *__restrict, dvisit_t, void *))&com_visit, + /* .tp_visit = */ (void (DCALL *)(DeeObject *__restrict, dvisit_t, void *))&scv_visit, /* .tp_gc = */ NULL, /* .tp_math = */ NULL, /* .tp_cmp = */ NULL, - /* .tp_seq = */ &pmut_seq, + /* .tp_seq = */ &scv_seq, /* .tp_iter_next = */ NULL, /* .tp_iterator = */ NULL, /* .tp_attr = */ NULL, @@ -1040,519 +1293,57 @@ INTERN DeeTypeObject SeqPermutations_Type = { /* .tp_buffer = */ NULL, /* .tp_methods = */ NULL, /* .tp_getsets = */ NULL, - /* .tp_members = */ pmut_members, + /* .tp_members = */ scv_members, /* .tp_class_methods = */ NULL, /* .tp_class_getsets = */ NULL, - /* .tp_class_members = */ pmut_class_members + /* .tp_class_members = */ NULL }; -INTERN WUNUSED NONNULL((1)) DREF DeeObject *DCALL -DeeSeq_Combinations(DeeObject *__restrict self, size_t r) { - DREF Combinations *result; - DeeTypeObject *tp_iter; - DeeTypeMRO mro; - result = DeeObject_MALLOC(Combinations); - if unlikely(!result) - goto done; - - /* Quickly check if we can use the fast-sequence interface. */ - tp_iter = Dee_TYPE(self); - if (tp_iter == &DeeTuple_Type) { - if (r >= DeeTuple_SIZE(self)) { - DeeObject_FREE(result); - if (r == DeeTuple_SIZE(self)) - return DeeTuple_Pack(1, self); - return_empty_seq; - } - result->c_getitem = NULL; - result->c_elem = DeeTuple_ELEM(self); - result->c_seqlen = DeeTuple_SIZE(self); - goto fill_in_result_2; - } - result->c_seqlen = DeeFastSeq_GetSize_deprecated(self); - if (result->c_seqlen != DEE_FASTSEQ_NOTFAST_DEPRECATED) { - result->c_getitem = tp_iter->tp_seq; - result->c_elem = NULL; - result->c_getitem_tp = tp_iter; - ASSERT(result->c_getitem); - goto fill_in_result; - } - DeeTypeMRO_Init(&mro, tp_iter); - do { - struct type_seq *seq; - if ((seq = tp_iter->tp_seq) == NULL) - continue; - if (seq->tp_getitem) { - /* Use the getitem/size variant. */ - result->c_getitem = seq; - result->c_getitem_tp = tp_iter; - result->c_elem = NULL; - if (!seq->tp_sizeob) { - for (;;) { - tp_iter = DeeTypeMRO_Next(&mro, tp_iter); - if (!tp_iter) { - err_unimplemented_operator(Dee_TYPE(self), OPERATOR_SIZE); - goto err_r; - } - seq = tp_iter->tp_seq; - if (seq && seq->tp_sizeob) - break; - } - } - goto load_tp_size; - } - if (seq->tp_sizeob) { - /* Use the getitem/size variant. */ - for (;;) { - tp_iter = DeeTypeMRO_Next(&mro, tp_iter); - if (!tp_iter) { - err_unimplemented_operator(Dee_TYPE(self), OPERATOR_GETITEM); - goto err_r; - } - if (tp_iter->tp_seq && - tp_iter->tp_seq->tp_getitem) - break; - } - result->c_getitem = tp_iter->tp_seq; - result->c_getitem_tp = tp_iter; -load_tp_size: - result->c_elem = NULL; - { - DREF DeeObject *temp; - int error; - temp = (*seq->tp_sizeob)(self); - if unlikely(!temp) - goto err_r; - error = DeeObject_AsSize(temp, &result->c_seqlen); - Dee_Decref(temp); - if unlikely(error) - goto err_r; - } - goto fill_in_result; - } - if (seq->tp_iter) { - DREF DeeObject *iterator, *elem; - DREF DeeObject **elem_v, **new_elem_v; - size_t elem_c, elem_a; - /* Use the iterator variant */ - iterator = (*seq->tp_iter)(self); - if unlikely(!iterator) - goto err_r; - elem_c = elem_a = 0; - elem_v = NULL; - while (ITER_ISOK(elem = DeeObject_IterNext(iterator))) { - ASSERT(elem_c <= elem_a); - if (elem_c >= elem_a) { - size_t new_alloc = elem_a * 2; - if (!new_alloc) - new_alloc = 8; - new_elem_v = (DREF DeeObject **)Dee_TryReallocc(elem_v, new_alloc, - sizeof(DREF DeeObject *)); - if unlikely(!new_elem_v) { - new_alloc = elem_c + 1; - new_elem_v = (DREF DeeObject **)Dee_TryReallocc(elem_v, new_alloc, - sizeof(DREF DeeObject *)); - if unlikely(!new_elem_v) { - Dee_Decref(elem); -err_elem_v: - Dee_Decrefv(elem_v, elem_c); - Dee_Free(elem_v); - goto err_r; - } - } - elem_v = new_elem_v; - elem_a = new_alloc; - } - elem_v[elem_c++] = elem; /* Inherit reference. */ - if (DeeThread_CheckInterrupt()) - goto err_elem_v; - } - if unlikely(!elem) - goto err_elem_v; - Dee_Decref(iterator); - if (r >= elem_c) { - Dee_Decrefv(elem_v, elem_c); - Dee_Free(elem_v); - DeeObject_FREE(result); - if (r == elem_c) - return DeeTuple_Pack(1, self); - return_empty_seq; - } - if likely(elem_a > elem_c) { - new_elem_v = (DREF DeeObject **)Dee_TryReallocc(elem_v, elem_c, - sizeof(DREF DeeObject *)); - if likely(new_elem_v) - elem_v = new_elem_v; - } - result->c_getitem = NULL; - result->c_elem = elem_v; - result->c_seqlen = elem_c; - goto fill_in_result_2; - } - } while ((tp_iter = DeeTypeMRO_Next(&mro, tp_iter)) != NULL); - err_unimplemented_operator(Dee_TYPE(self), OPERATOR_ITER); - goto err_r; -fill_in_result: - if (r >= result->c_seqlen) { - size_t seqlen = result->c_seqlen; - ASSERT(!result->c_elem); - DeeObject_FREE(result); - if (r == seqlen) - return DeeTuple_Pack(1, self); - return_empty_seq; +PRIVATE DEFINE_TUPLE(empty_combinations, 1, { Dee_EmptyTuple }); + +PRIVATE WUNUSED NONNULL((1, 3)) DREF DeeObject *DCALL +SeqCombinations_New(/*inherit(always)*/ DREF DeeObject *__restrict seq, + size_t rparam, DeeTypeObject *__restrict type) { + DREF SeqCombinations *result; + if unlikely(!rparam) { + Dee_Decref(seq); + return_reference_((DeeObject *)&empty_combinations); } -fill_in_result_2: - result->c_seq = self; - result->c_comlen = r; - Dee_Incref(self); - DeeObject_Init(result, &SeqCombinations_Type); -done: + result = DeeObject_MALLOC(SeqCombinations); + if unlikely(!result) + goto err_seq; + result->sc_trygetitem_index = DeeType_RequireSeqOperatorTryGetItemIndex(Dee_TYPE(seq)); + if unlikely(result->sc_trygetitem_index == &DeeSeq_DefaultOperatorTryGetItemIndexWithError) + goto err_seq_r_combinations_not_supported; + result->sc_seqsize = (size_t)-1; /* Will be calculated lazily */ + result->sc_rparam = rparam; + result->sc_seq = seq; /* Inherit reference */ + DeeObject_Init(result, type); return (DREF DeeObject *)result; -err_r: +err_seq_r_combinations_not_supported: DeeObject_FREE(result); + DeeError_Throwf(&DeeError_SequenceError, + "Type %r does not support sequence combinations", + Dee_TYPE(seq)); +err_seq: + Dee_Decref(seq); return NULL; } - INTERN WUNUSED NONNULL((1)) DREF DeeObject *DCALL -DeeSeq_RepeatCombinations(DeeObject *__restrict self, size_t r) { - DREF Combinations *result; - DeeTypeObject *tp_iter; - DeeTypeMRO mro; - if (!r) - return DeeTuple_Pack(1, Dee_EmptySeq); - result = DeeObject_MALLOC(Combinations); - if unlikely(!result) - goto done; - - /* Quickly check if we can use the fast-sequence interface. */ - tp_iter = Dee_TYPE(self); - if (tp_iter == &DeeTuple_Type) { - if (!DeeTuple_SIZE(self)) { - DeeObject_FREE(result); - return_empty_seq; - } - result->c_getitem = NULL; - result->c_elem = DeeTuple_ELEM(self); - result->c_seqlen = DeeTuple_SIZE(self); - goto fill_in_result_2; - } - result->c_seqlen = DeeFastSeq_GetSize_deprecated(self); - if (result->c_seqlen != DEE_FASTSEQ_NOTFAST_DEPRECATED) { - result->c_getitem = tp_iter->tp_seq; - result->c_elem = NULL; - result->c_getitem_tp = tp_iter; - ASSERT(result->c_getitem); - goto fill_in_result; - } - DeeTypeMRO_Init(&mro, tp_iter); - do { - struct type_seq *seq; - if ((seq = tp_iter->tp_seq) == NULL) - continue; - if (seq->tp_getitem) { - /* Use the getitem/size variant. */ - result->c_getitem = seq; - result->c_getitem_tp = tp_iter; - result->c_elem = NULL; - if (!seq->tp_sizeob) { - for (;;) { - tp_iter = DeeTypeMRO_Next(&mro, tp_iter); - if (!tp_iter) { - err_unimplemented_operator(Dee_TYPE(self), OPERATOR_SIZE); - goto err_r; - } - seq = tp_iter->tp_seq; - if (seq && seq->tp_sizeob) - break; - } - } - goto load_tp_size; - } - if (seq->tp_sizeob) { - /* Use the getitem/size variant. */ - tp_iter = tp_iter; - for (;;) { - tp_iter = DeeTypeMRO_Next(&mro, tp_iter); - if (!tp_iter) { - err_unimplemented_operator(Dee_TYPE(self), OPERATOR_GETITEM); - goto err_r; - } - if (tp_iter->tp_seq && - tp_iter->tp_seq->tp_getitem) - break; - } - result->c_getitem = tp_iter->tp_seq; - result->c_getitem_tp = tp_iter; -load_tp_size: - result->c_elem = NULL; - { - DREF DeeObject *temp; - int error; - temp = (*seq->tp_sizeob)(self); - if unlikely(!temp) - goto err_r; - error = DeeObject_AsSize(temp, &result->c_seqlen); - Dee_Decref(temp); - if unlikely(error) - goto err_r; - } - goto fill_in_result; - } - if (seq->tp_iter) { - DREF DeeObject *iterator, *elem; - DREF DeeObject **elem_v, **new_elem_v; - size_t elem_c, elem_a; - /* Use the iterator variant */ - iterator = (*seq->tp_iter)(self); - if unlikely(!iterator) - goto err_r; - elem_c = elem_a = 0; - elem_v = NULL; - while (ITER_ISOK(elem = DeeObject_IterNext(iterator))) { - ASSERT(elem_c <= elem_a); - if (elem_c >= elem_a) { - size_t new_alloc = elem_a * 2; - if (!new_alloc) - new_alloc = 8; - new_elem_v = (DREF DeeObject **)Dee_TryReallocc(elem_v, new_alloc, - sizeof(DREF DeeObject *)); - if unlikely(!new_elem_v) { - new_alloc = elem_c + 1; - new_elem_v = (DREF DeeObject **)Dee_TryReallocc(elem_v, new_alloc, - sizeof(DREF DeeObject *)); - if unlikely(!new_elem_v) { - Dee_Decref(elem); -err_elem_v: - Dee_Decrefv(elem_v, elem_c); - Dee_Free(elem_v); - goto err_r; - } - } - elem_v = new_elem_v; - elem_a = new_alloc; - } - elem_v[elem_c++] = elem; /* Inherit reference. */ - if (DeeThread_CheckInterrupt()) - goto err_elem_v; - } - if unlikely(!elem) - goto err_elem_v; - Dee_Decref(iterator); - if (!elem_c) { - Dee_Free(elem_v); - DeeObject_FREE(result); - return_empty_seq; - } - if likely(elem_a > elem_c) { - new_elem_v = (DREF DeeObject **)Dee_TryReallocc(elem_v, elem_c, - sizeof(DREF DeeObject *)); - if likely(new_elem_v) - elem_v = new_elem_v; - } - result->c_getitem = NULL; - result->c_elem = elem_v; - result->c_seqlen = elem_c; - goto fill_in_result_2; - } - } while ((tp_iter = DeeTypeMRO_Next(&mro, tp_iter)) != NULL); - err_unimplemented_operator(Dee_TYPE(self), OPERATOR_ITER); - goto err_r; -fill_in_result: - if (!result->c_seqlen) { - ASSERT(!result->c_elem); - DeeObject_FREE(result); - return_empty_seq; - } -fill_in_result_2: - result->c_seq = self; - result->c_comlen = r; - Dee_Incref(self); - DeeObject_Init(result, &SeqRepeatCombinations_Type); -done: - return (DREF DeeObject *)result; -err_r: - DeeObject_FREE(result); - return NULL; +DeeSeq_Combinations(/*inherit(always)*/ DREF DeeObject *__restrict self, size_t r) { + return SeqCombinations_New(self, r, &SeqCombinations_Type); } - INTERN WUNUSED NONNULL((1)) DREF DeeObject *DCALL -DeeSeq_Permutations(DeeObject *__restrict self) { - DREF Combinations *result; - DeeTypeObject *tp_iter; - DeeTypeMRO mro; - result = DeeObject_MALLOC(Combinations); - if unlikely(!result) - goto done; - - /* Quickly check if we can use the fast-sequence interface. */ - tp_iter = Dee_TYPE(self); - if (tp_iter == &DeeTuple_Type) { - if (!DeeTuple_SIZE(self)) { - DeeObject_FREE(result); - return DeeTuple_Pack(1, Dee_EmptySeq); - } - result->c_getitem = NULL; - result->c_elem = DeeTuple_ELEM(self); - result->c_seqlen = DeeTuple_SIZE(self); - goto fill_in_result_2; - } - result->c_seqlen = DeeFastSeq_GetSize_deprecated(self); - if (result->c_seqlen != DEE_FASTSEQ_NOTFAST_DEPRECATED) { - result->c_getitem = tp_iter->tp_seq; - result->c_elem = NULL; - result->c_getitem_tp = tp_iter; - ASSERT(result->c_getitem); - goto fill_in_result; - } - DeeTypeMRO_Init(&mro, tp_iter); - do { - struct type_seq *seq; - if ((seq = tp_iter->tp_seq) == NULL) - continue; - if (seq->tp_getitem) { - /* Use the getitem/size variant. */ - result->c_getitem = seq; - result->c_getitem_tp = tp_iter; - result->c_elem = NULL; - if (!seq->tp_sizeob) { - for (;;) { - tp_iter = DeeTypeMRO_Next(&mro, tp_iter); - if (!tp_iter) { - err_unimplemented_operator(Dee_TYPE(self), OPERATOR_SIZE); - goto err_r; - } - seq = tp_iter->tp_seq; - if (seq && seq->tp_sizeob) - break; - } - } - goto load_tp_size; - } - if (seq->tp_sizeob) { - /* Use the getitem/size variant. */ - for (;;) { - tp_iter = DeeTypeMRO_Next(&mro, tp_iter); - if (!tp_iter) { - err_unimplemented_operator(Dee_TYPE(self), OPERATOR_GETITEM); - goto err_r; - } - if (tp_iter->tp_seq && - tp_iter->tp_seq->tp_getitem) - break; - } - result->c_getitem = tp_iter->tp_seq; - result->c_getitem_tp = tp_iter; -load_tp_size: - result->c_elem = NULL; - { - DREF DeeObject *temp; - int error; - temp = (*seq->tp_sizeob)(self); - if unlikely(!temp) - goto err_r; - error = DeeObject_AsSize(temp, &result->c_seqlen); - Dee_Decref(temp); - if unlikely(error) - goto err_r; - } - goto fill_in_result; - } - if (seq->tp_iter) { - DREF DeeObject *iterator, *elem; - DREF DeeObject **elem_v, **new_elem_v; - size_t elem_c, elem_a; - /* Use the iterator variant */ - iterator = (*seq->tp_iter)(self); - if unlikely(!iterator) - goto err_r; - elem_a = 0; - elem_c = 0; - elem_v = NULL; - while (ITER_ISOK(elem = DeeObject_IterNext(iterator))) { - ASSERT(elem_c <= elem_a); - if (elem_c >= elem_a) { - size_t new_alloc = elem_a * 2; - if (!new_alloc) - new_alloc = 8; - new_elem_v = (DREF DeeObject **)Dee_TryReallocc(elem_v, new_alloc, - sizeof(DREF DeeObject *)); - if unlikely(!new_elem_v) { - new_alloc = elem_c + 1; - new_elem_v = (DREF DeeObject **)Dee_TryReallocc(elem_v, new_alloc, - sizeof(DREF DeeObject *)); - if unlikely(!new_elem_v) { - Dee_Decref(elem); -err_elem_v: - Dee_Decrefv(elem_v, elem_c); - Dee_Free(elem_v); - goto err_r; - } - } - elem_v = new_elem_v; - elem_a = new_alloc; - } - elem_v[elem_c++] = elem; /* Inherit reference. */ - if (DeeThread_CheckInterrupt()) - goto err_elem_v; - } - if unlikely(!elem) - goto err_elem_v; - Dee_Decref(iterator); - if (!elem_c) { - Dee_Free(elem_v); - DeeObject_FREE(result); - return DeeTuple_Pack(1, Dee_EmptySeq); - } - if likely(elem_a > elem_c) { - new_elem_v = (DREF DeeObject **)Dee_TryReallocc(elem_v, elem_c, - sizeof(DREF DeeObject *)); - if likely(new_elem_v) - elem_v = new_elem_v; - } - result->c_getitem = NULL; - result->c_elem = elem_v; - result->c_seqlen = elem_c; - goto fill_in_result_2; - } - } while ((tp_iter = DeeTypeMRO_Next(&mro, tp_iter)) != NULL); - err_unimplemented_operator(Dee_TYPE(self), OPERATOR_ITER); - goto err_r; -fill_in_result: - if (!result->c_seqlen) { - ASSERT(!result->c_elem); - DeeObject_FREE(result); - return DeeTuple_Pack(1, Dee_EmptySeq); - } -fill_in_result_2: - result->c_seq = self; - result->c_comlen = result->c_seqlen; - Dee_Incref(self); - DeeObject_Init(result, &SeqPermutations_Type); -done: - return (DREF DeeObject *)result; -err_r: - DeeObject_FREE(result); - return NULL; +DeeSeq_RepeatCombinations(/*inherit(always)*/ DREF DeeObject *__restrict self, size_t r) { + return SeqCombinations_New(self, r, &SeqRepeatCombinations_Type); } INTERN WUNUSED NONNULL((1)) DREF DeeObject *DCALL -DeeSeq_Permutations2(DeeObject *__restrict self, size_t r) { - DREF Combinations *result; - if (!r) - return DeeTuple_Pack(1, Dee_EmptySeq); - result = (DREF Combinations *)DeeSeq_Permutations(self); - if likely(result && Dee_TYPE(result) == &SeqPermutations_Type) { - result->c_comlen = r; - if (r > result->c_seqlen) { - Dee_Decref_likely(result); - result = (DREF Combinations *)Dee_EmptySeq; - Dee_Incref(Dee_EmptySeq); - } - } - return (DREF DeeObject *)result; +DeeSeq_Permutations2(/*inherit(always)*/ DREF DeeObject *__restrict self, size_t r) { + return SeqCombinations_New(self, r, &SeqPermutations_Type); } diff --git a/src/deemon/objects/seq/combinations.h b/src/deemon/objects/seq/combinations.h index 87835749c..7cf263b5a 100644 --- a/src/deemon/objects/seq/combinations.h +++ b/src/deemon/objects/seq/combinations.h @@ -21,54 +21,47 @@ #define GUARD_DEEMON_OBJECTS_SEQ_COMBINATIONS_H 1 #include +#include #include +#include + +#include "../generic-proxy.h" DECL_BEGIN -/* TODO: Completely re-write this stuff to make use of new sequence APIs */ +typedef struct seq_combinations SeqCombinations; +typedef struct seq_combinations_iterator SeqCombinationsIterator; +typedef struct seq_combinations_view SeqCombinationsView; + +struct seq_combinations { + PROXY_OBJECT_HEAD(sc_seq) /* [1..1][const] Underlying sequence */ + Dee_mh_seq_operator_trygetitem_index_t sc_trygetitem_index; /* [1..1][const] trygetitem_index operator for "sc_seq" */ + size_t sc_seqsize; /* [valid_if(!= (size_t)-1)][lock(WRITE_ONCE)] Cache for `DeeSeq_OperatorSize(sc_seq)' */ + size_t sc_rparam; /* [!0][valid_if(!= (size_t)-1)][lock(WRITE_ONCE)] the "r" parameter (or `(size_t)-1' when `sc_seqsize ?: 1' should be used) + * NOTE: Guarantied to be valid when accessed by an iterator. */ +}; -typedef struct { - OBJECT_HEAD - DREF DeeObject *c_seq; /* [1..1][const] The underlying sequence that is being combined. */ - DREF DeeObject **c_elem; /* [1..1][0..c_seqlen][const][owned_if(!= DeeTuple_ELEM(c_seq))] - * The vector of elements found in `c_seq' - * NOTE: When `NULL', elements from `c_seq' are accessed through - * the GETITEM interface, as those items are being used. */ - size_t c_seqlen; /* [const][!0] The length of the sequence (in items) */ - size_t c_comlen; /* [const][< c_seqlen] The amount of elements per combination. */ - struct type_seq *c_getitem; /* [0..1][if(!c_elem, [1..1])][const] The seq-interface of the type - * to-be used to access the items of `c_seq' */ - DeeTypeObject *c_getitem_tp; /* [1..1][valid_if(c_getitem != NULL)] The type used to invoke the getitem operator. */ -} Combinations; +struct seq_combinations_iterator { + PROXY_OBJECT_HEAD_EX(SeqCombinations, sci_com) /* [1..1][const] Underlying sequence combinations controller */ + WEAKREF(SeqCombinationsView) sci_view; /* [0..1] View that is aliasing "sci_idx" */ + COMPILER_FLEXIBLE_ARRAY(size_t, sci_idx); /* [lock(ATOMIC)][sci_com->sc_rparam] Index matrix */ +}; -typedef struct { - OBJECT_HEAD - DREF Combinations *ci_combi; /* [1..1][const] The underlying combinations sequence proxy. */ - size_t *ci_indices; /* [1..ci_combi->c_comlen][lock(ci_lock)][owned] - * Indices to-be used for the next set of combinations to-be - * combined to generate the next item. */ -#ifndef CONFIG_NO_THREADS - Dee_atomic_rwlock_t ci_lock; /* Lock for this combinations iterator. */ -#endif /* !CONFIG_NO_THREADS */ - bool ci_first; /* [lock(ci_lock)] True prior to the first iteration. */ -} CombinationsIterator; +struct seq_combinations_view { + PROXY_OBJECT_HEAD_EX(SeqCombinationsIterator, scv_iter) /* [1..1] Iterator being viewed */ + SeqCombinations *scv_com; /* [1..1][== scv_iter->sci_com][const] Shallow alias */ + size_t *scv_idx; /* [1..scv_com->sc_rparam][owned_if(!= scv_iter->sci_idx)] + * [lock(ATOMIC && WRITE_ONCE && KEEP_VALID)] + * Used table of indices. You can (atomically) read this pointer + * and dereference it without needing to hold any locks, because + * at the moment that this pointer is exchanged, the old location + * will remain valid. */ + WEAKREF_SUPPORT +}; -#define CombinationsIterator_LockReading(self) Dee_atomic_rwlock_reading(&(self)->ci_lock) -#define CombinationsIterator_LockWriting(self) Dee_atomic_rwlock_writing(&(self)->ci_lock) -#define CombinationsIterator_LockTryRead(self) Dee_atomic_rwlock_tryread(&(self)->ci_lock) -#define CombinationsIterator_LockTryWrite(self) Dee_atomic_rwlock_trywrite(&(self)->ci_lock) -#define CombinationsIterator_LockCanRead(self) Dee_atomic_rwlock_canread(&(self)->ci_lock) -#define CombinationsIterator_LockCanWrite(self) Dee_atomic_rwlock_canwrite(&(self)->ci_lock) -#define CombinationsIterator_LockWaitRead(self) Dee_atomic_rwlock_waitread(&(self)->ci_lock) -#define CombinationsIterator_LockWaitWrite(self) Dee_atomic_rwlock_waitwrite(&(self)->ci_lock) -#define CombinationsIterator_LockRead(self) Dee_atomic_rwlock_read(&(self)->ci_lock) -#define CombinationsIterator_LockWrite(self) Dee_atomic_rwlock_write(&(self)->ci_lock) -#define CombinationsIterator_LockTryUpgrade(self) Dee_atomic_rwlock_tryupgrade(&(self)->ci_lock) -#define CombinationsIterator_LockUpgrade(self) Dee_atomic_rwlock_upgrade(&(self)->ci_lock) -#define CombinationsIterator_LockDowngrade(self) Dee_atomic_rwlock_downgrade(&(self)->ci_lock) -#define CombinationsIterator_LockEndWrite(self) Dee_atomic_rwlock_endwrite(&(self)->ci_lock) -#define CombinationsIterator_LockEndRead(self) Dee_atomic_rwlock_endread(&(self)->ci_lock) -#define CombinationsIterator_LockEnd(self) Dee_atomic_rwlock_end(&(self)->ci_lock) +/* Get/Set(once) the "scv_idx" field of "SeqCombinationsView" */ +#define SeqCombinationsView_GetIdx(self) atomic_read(&(self)->scv_idx) +#define SeqCombinationsView_SetIdx(self, p) atomic_cmpxch(&(self)->scv_idx, (self)->scv_iter->sci_idx, p) INTDEF DeeTypeObject SeqCombinations_Type; @@ -77,12 +70,18 @@ INTDEF DeeTypeObject SeqRepeatCombinations_Type; INTDEF DeeTypeObject SeqRepeatCombinationsIterator_Type; INTDEF DeeTypeObject SeqPermutations_Type; INTDEF DeeTypeObject SeqPermutationsIterator_Type; +INTDEF DeeTypeObject SeqCombinationsView_Type; - -INTDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeSeq_Combinations(DeeObject *__restrict self, size_t r); -INTDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeSeq_RepeatCombinations(DeeObject *__restrict self, size_t r); -INTDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeSeq_Permutations(DeeObject *__restrict self); -INTDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeSeq_Permutations2(DeeObject *__restrict self, size_t r); +/* Sequence combinatoric functions: + * >> DeeSeq_Combinations("ABCD", 2) -> AB AC AD BC BD CD + * >> DeeSeq_RepeatCombinations("ABC", 2) -> AA AB AC BB BC CC + * >> DeeSeq_Permutations2("ABCD", 2) -> AB AC BA BC CA CB + * >> DeeSeq_Permutations2("ABC", 2) -> AB AC BA BC CA CB + * >> DeeSeq_Permutations("ABC") -> ABC ACA ACB BAA BAC BCA CAA CAB CBA */ +INTDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeSeq_Combinations(/*inherit(always)*/ DREF DeeObject *__restrict self, size_t r); +INTDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeSeq_RepeatCombinations(/*inherit(always)*/ DREF DeeObject *__restrict self, size_t r); +INTDEF WUNUSED NONNULL((1)) DREF DeeObject *DCALL DeeSeq_Permutations2(/*inherit(always)*/ DREF DeeObject *__restrict self, size_t r); +#define DeeSeq_Permutations(self) DeeSeq_Permutations2(self, (size_t)-1) DECL_END diff --git a/src/deemon/objects/string.c b/src/deemon/objects/string.c index 2ba76b368..b1b4e4049 100644 --- a/src/deemon/objects/string.c +++ b/src/deemon/objects/string.c @@ -1334,7 +1334,8 @@ PRIVATE struct type_cmp stringiter_cmp = { INTERN DeeTypeObject StringIterator_Type = { OBJECT_HEAD_INIT(&DeeType_Type), /* .tp_name = */ "_StringIterator", - /* .tp_doc = */ DOC("(seq?:?Dstring)"), + /* .tp_doc = */ DOC("()\n" + "(s:?Dstring)"), /* .tp_flags = */ TP_FNORMAL, /* .tp_weakrefs = */ 0, /* .tp_features = */ TF_NONLOOPING, diff --git a/src/deemon/runtime/kwlist.h b/src/deemon/runtime/kwlist.h index 6b008d129..eeefc7e7b 100644 --- a/src/deemon/runtime/kwlist.h +++ b/src/deemon/runtime/kwlist.h @@ -124,6 +124,7 @@ local kw_lists = { {"obj", "callback"}, {"code", "positional", "kwargs", "kwds"}, {"code", "positional", "kwds"}, + {"r", "cached"}, {"#ifdef CONFIG_HOST_WINDOWS", "message", "inner", "errno", "nterr_np"}, {"#ifndef CONFIG_HOST_WINDOWS", "message", "inner", "errno"}, @@ -228,6 +229,7 @@ DECLARE_KWLIST(kwlist__pattern_start_end_rules, { KEX("pattern", 0x6ea88732, 0x8 DECLARE_KWLIST(kwlist__pos_maxbytes_readall, { KEX("pos", 0xb1aecbb4, 0x277b6d36f75741ae), KEX("maxbytes", 0x3b196fc0, 0x93d3b3615fcacd4a), KEX("readall", 0x331ceae8, 0x8ad608764266c76d), KEND }); DECLARE_KWLIST(kwlist__precision, { KEX("precision", 0xb3c93bdd, 0x3d6866f78be60b), KEND }); DECLARE_KWLIST(kwlist__predicate_answer, { KEX("predicate", 0x3c672fb4, 0xb5f52435e811385), KEX("answer", 0x63c165df, 0x76fd5eeb2e58020), KEND }); +DECLARE_KWLIST(kwlist__r_cached, { KEX("r", 0x5c9373f1, 0x6ece84440d42ecf6), KEX("cached", 0x915e175e, 0xddfd408a14eae4b4), KEND }); DECLARE_KWLIST(kwlist__radix_precision_mode, { KEX("radix", 0xb10d4185, 0xbf2dcb32c6415f32), KEX("precision", 0xb3c93bdd, 0x3d6866f78be60b), KEX("mode", 0x11abbac9, 0xa978c54b1db00143), KEND }); DECLARE_KWLIST(kwlist__should_start_end_max, { KEX("should", 0x28877b82, 0xbb3cb749df0a8b51), KEX("start", 0xa2ed6890, 0x80b621ce3c3982d5), KEX("end", 0x37fb4a05, 0x6de935c204dc3d01), KEX("max", 0xc293979b, 0x822bd5c706bd9850), KEND }); DECLARE_KWLIST(kwlist__signed, { KEX("signed", 0x17a15883, 0x58a245b6f802625f), KEND }); diff --git a/src/deemon/runtime/runtime_error.c b/src/deemon/runtime/runtime_error.c index 034ad2293..1c0771d18 100644 --- a/src/deemon/runtime/runtime_error.c +++ b/src/deemon/runtime/runtime_error.c @@ -102,6 +102,21 @@ PUBLIC ATTR_COLD NONNULL((1, 2, 3)) int Dee_TYPE(self), self); } +PUBLIC ATTR_COLD NONNULL((1, 2, 3, 4)) int +(DCALL DeeObject_TypeAssertFailed3)(DeeObject *self, + DeeTypeObject *required_type1, + DeeTypeObject *required_type2, + DeeTypeObject *required_type3) { + ASSERT_OBJECT(self); + ASSERT_OBJECT(required_type1); + ASSERT_OBJECT(required_type2); + ASSERT_OBJECT(required_type3); + return DeeError_Throwf(&DeeError_TypeError, + "Expected instance of `%r', `%r' or `%r', but got a `%r' object: %k", + required_type1, required_type2, required_type3, + Dee_TYPE(self), self); +} + INTERN ATTR_COLD NONNULL((1)) int (DCALL err_unimplemented_constructor_kw)(DeeTypeObject *tp, size_t argc, DeeObject *const *argv, DeeObject *kw) { diff --git a/src/deemon/runtime/strings.h b/src/deemon/runtime/strings.h index ca4f82433..2f9e69b21 100644 --- a/src/deemon/runtime/strings.h +++ b/src/deemon/runtime/strings.h @@ -912,6 +912,9 @@ DEF_STRING(str_this_function, "this_function", 0xe2b69fa3, 0xdf2ba17d58877ece) #ifndef STR_Typed #define STR_Typed "Typed" #endif /* !STR_Typed */ +#ifndef STR_ItemType +#define STR_ItemType "ItemType" +#endif /* !STR_ItemType */ /* Some versions of GCC think that using DeeString_STR() on a static * string object will result in us reading from out-of-bounds memory, diff --git a/src/dex/rt/librt.c b/src/dex/rt/librt.c index fe8c719f9..8a9e4bf0b 100644 --- a/src/dex/rt/librt.c +++ b/src/dex/rt/librt.c @@ -298,6 +298,10 @@ PRIVATE DEFINE_STRING_EX(str_Iterator, "Iterator", 0xfce46883, 0x3c33c9d5c64ebff /*[[[end]]]*/ #endif +/*[[[deemon (PRIVATE_DEFINE_STRING from rt.gen.string)("str_ItemType", "ItemType");]]]*/ +PRIVATE DEFINE_STRING_EX(str_ItemType, "ItemType", 0x6e2bcfbc, 0x930e682d9edfa03b); +/*[[[end]]]*/ + #ifdef __OPTIMIZ_SIZE__ #define return_cached(expr) return expr @@ -356,6 +360,17 @@ get_iterator_of(DREF DeeObject *ob) { return result; } +PRIVATE WUNUSED DREF DeeObject *DCALL +get_itemtype_of(DREF DeeObject *ob) { + DREF DeeObject *result = NULL; + if likely(ob) { + result = DeeObject_GetAttr((DeeObject *)ob, + (DeeObject *)&str_ItemType); + Dee_Decref_unlikely(ob); + } + return result; +} + PRIVATE WUNUSED DREF DeeObject *DCALL get_typed_of(DREF DeeObject *ob) { DREF DeeObject *result = NULL; @@ -811,6 +826,11 @@ librt_get_SeqPermutationsIterator_f(size_t UNUSED(argc), DeeObject *const *UNUSE return_cached(get_iterator_of(librt_get_SeqPermutations_impl_f())); } +PRIVATE WUNUSED DREF DeeObject *DCALL +librt_get_SeqCombinationsView_f(size_t UNUSED(argc), DeeObject *const *UNUSED(argv)) { + return_cached(get_itemtype_of(librt_get_SeqCombinations_impl_f())); +} + PRIVATE WUNUSED DREF DeeObject *DCALL librt_get_SeqSegments_impl_f(void) { /* Since string overrides `segments', we must use a true sequence here! */ @@ -3288,6 +3308,7 @@ PRIVATE DEFINE_CMETHOD(librt_get_SeqRepeatCombinations, &librt_get_SeqRepeatComb PRIVATE DEFINE_CMETHOD(librt_get_SeqRepeatCombinationsIterator, &librt_get_SeqRepeatCombinationsIterator_f, METHOD_FCONSTCALL); PRIVATE DEFINE_CMETHOD(librt_get_SeqPermutations, &librt_get_SeqPermutations_f, METHOD_FCONSTCALL); PRIVATE DEFINE_CMETHOD(librt_get_SeqPermutationsIterator, &librt_get_SeqPermutationsIterator_f, METHOD_FCONSTCALL); +PRIVATE DEFINE_CMETHOD(librt_get_SeqCombinationsView, &librt_get_SeqCombinationsView_f, METHOD_FCONSTCALL); PRIVATE DEFINE_CMETHOD(librt_get_SeqSegments, &librt_get_SeqSegments_f, METHOD_FCONSTCALL); PRIVATE DEFINE_CMETHOD(librt_get_SeqSegmentsIterator, &librt_get_SeqSegmentsIterator_f, METHOD_FCONSTCALL); PRIVATE DEFINE_CMETHOD(librt_get_SeqConcat, &librt_get_SeqConcat_f, METHOD_FCONSTCALL); @@ -3661,6 +3682,8 @@ PRIVATE struct dex_symbol symbols[] = { { "SeqRepeatCombinationsIterator", (DeeObject *)&librt_get_SeqRepeatCombinationsIterator, MODSYM_FREADONLY | MODSYM_FPROPERTY | MODSYM_FCONSTEXPR }, /* SeqRepeatCombinationsIterator_Type */ { "SeqPermutations", (DeeObject *)&librt_get_SeqPermutations, MODSYM_FREADONLY | MODSYM_FPROPERTY | MODSYM_FCONSTEXPR }, /* SeqPermutations_Type */ { "SeqPermutationsIterator", (DeeObject *)&librt_get_SeqPermutationsIterator, MODSYM_FREADONLY | MODSYM_FPROPERTY | MODSYM_FCONSTEXPR }, /* SeqPermutationsIterator_Type */ + { "SeqCombinationsView", (DeeObject *)&librt_get_SeqCombinationsView, MODSYM_FREADONLY | MODSYM_FPROPERTY | MODSYM_FCONSTEXPR }, /* SeqCombinationsView_Type */ + { "SeqSegments", (DeeObject *)&librt_get_SeqSegments, MODSYM_FREADONLY | MODSYM_FPROPERTY | MODSYM_FCONSTEXPR }, /* SeqSegments_Type */ { "SeqSegmentsIterator", (DeeObject *)&librt_get_SeqSegmentsIterator, MODSYM_FREADONLY | MODSYM_FPROPERTY | MODSYM_FCONSTEXPR }, /* SeqSegmentsIterator_Type */ { "SeqConcat", (DeeObject *)&librt_get_SeqConcat, MODSYM_FREADONLY | MODSYM_FPROPERTY | MODSYM_FCONSTEXPR }, /* SeqConcat_Type */ diff --git a/util/test/deemon-sequence-combinations.dee b/util/test/deemon-sequence-combinations.dee new file mode 100644 index 000000000..e82aa178c --- /dev/null +++ b/util/test/deemon-sequence-combinations.dee @@ -0,0 +1,54 @@ +#!/usr/bin/deemon +/* 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. * + */ + +import * from deemon; + +function n(x: {{string...}...}): (int, string) { + return (#x, " ".join(x.each.sum())); +} + +assert {{}} == "ABCD".combinations(0); +assert {{}} == "ABCD".repeatcombinations(0); +assert {{}} == "ABCD".permutations(0); + +assert (0, "") == n("ABCD".combinations(1)); +assert (4, "A B C D") == n("ABCD".repeatcombinations(1)); +assert (4, "A B C D") == n("ABCD".permutations(1)); + +assert (6, "AB AC AD BC BD CD") == n("ABCD".combinations(2)); +assert (10, "AA AB AC AD BB BC BD CC CD DD") + == n("ABCD".repeatcombinations(2)); +assert (12, "AB AC AD BA BC BD CA CB CD DA DB DC") + == n("ABCD".permutations(2)); + +assert (4, "ABC ABD ACD BCD") == n("ABCD".combinations(3)); +assert (20, "AAA AAB AAC AAD ABB ABC ABD ACC ACD ADD BBB BBC BBD BCC BCD BDD CCC CCD CDD DDD") + == n("ABCD".repeatcombinations(3)); +assert (29, "ABC ABD ACA ACB ACD ADA ADB ADC BAA BAC BAD BCA BCD BDA BDC CAA CAB CAD CBA CBD CDA CDB DAA DAB DAC DBA DBC DCA DCB") + == n("ABCD".permutations(3)); + +assert (1, "ABCD") == n("ABCD".combinations(4)); +assert (35, "AAAA AAAB AAAC AAAD AABB AABC AABD AACC AACD AADD ABBB ABBC ABBD ABCC ABCD ABDD ACCC ACCD ACDD ADDD BBBB BBBC BBBD BBCC BBCD BBDD BCCC BCCD BCDD BDDD CCCC CCCD CCDD CDDD DDDD") + == n("ABCD".repeatcombinations(4)); +assert (56, "ABCD ABDA ABDC ACAA ACAB ACAD ACBA ACBD ACDA ACDB ADAA ADAB ADAC ADBA ADBC ADCA ADCB BAAA BAAC BAAD BACA BACD BADA BADC BCAA BCAD BCDA BDAA BDAC BDCA CAAA CAAB CAAD CABA CABD CADA CADB CBAA CBAD CBDA CDAA CDAB CDBA DAAA DAAB DAAC DABA DABC DACA DACB DBAA DBAC DBCA DCAA DCAB DCBA") + == n("ABCD".permutations(4)); +assert n("ABCD".permutations(4)) == n("ABCD".permutations()); + diff --git a/util/test/rt-linkage.dee b/util/test/rt-linkage.dee index 7ad1726ed..68ffbd27c 100644 --- a/util/test/rt-linkage.dee +++ b/util/test/rt-linkage.dee @@ -39,6 +39,7 @@ assertRtTypeName("SeqRepeatCombinations"); assertRtTypeName("SeqRepeatCombinationsIterator"); assertRtTypeName("SeqPermutations"); assertRtTypeName("SeqPermutationsIterator"); +assertRtTypeName("SeqCombinationsView"); assertRtTypeName("SeqSegments"); assertRtTypeName("SeqSegmentsIterator"); assertRtTypeName("SeqConcat");