Skip to content

Commit

Permalink
Re-write Sequence.combinations to use new sequence APIs
Browse files Browse the repository at this point in the history
Also add a test for it
  • Loading branch information
GrieferAtWork committed Dec 28, 2024
1 parent 7125aad commit a509d19
Show file tree
Hide file tree
Showing 15 changed files with 1,317 additions and 1,395 deletions.
1 change: 1 addition & 0 deletions .vs/deemon-v141.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions .vs/deemon-v142.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 10 additions & 3 deletions include/deemon/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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))
Expand Down
5 changes: 4 additions & 1 deletion src/deemon/objects/dict.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
26 changes: 13 additions & 13 deletions src/deemon/objects/int.c
Original file line number Diff line number Diff line change
Expand Up @@ -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() */
};


Expand Down
159 changes: 90 additions & 69 deletions src/deemon/objects/seq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 <hybrid/limitcore.h>
#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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)),

Expand Down
Loading

0 comments on commit a509d19

Please sign in to comment.