diff --git a/include/deemon/object.h b/include/deemon/object.h index 873e15cb..8bc7dfc3 100644 --- a/include/deemon/object.h +++ b/include/deemon/object.h @@ -2111,6 +2111,23 @@ struct Dee_type_seq { WUNUSED_T NONNULL_T((1, 2)) int (DCALL *tp_bounditem_string_len_hash)(DeeObject *self, char const *key, size_t keylen, Dee_hash_t hash); WUNUSED_T NONNULL_T((1, 2)) int (DCALL *tp_hasitem_string_len_hash)(DeeObject *self, char const *key, size_t keylen, Dee_hash_t hash); + /* Optional helper to help implement `DeeSeq_AsHeapVector()' & friends. + * NOTES: + * - This operator is NOT used to implement stuff above, and will NOT + * be substituted using other operators. This operator gets inherited + * alongside "tp_iter", though its presence does not qualify for that + * operator being present! + * - This operator must NOT produce NULL-elements in "dst". The produced + * vector of items must be equivalent to what would be produced by a + * call to "tp_foreach" (which in turn must be equivalent to "tp_iter"). + * + * @return: <= dst_length: Success: the first "return" elements of "dst" were filled with the items of this sequence. + * @return: > dst_length: The given "dst_length" is too short. In this case, "dst" may have been modified, + * but will not contain any object references. You must resize it until it is able + * to hold at least "return" elements, and call this operator again. + * @return: (size_t)-1: Error. */ + WUNUSED_T NONNULL_T((1)) size_t (DCALL *tp_asvector)(DeeObject *self, /*out*/ DREF DeeObject **dst, size_t dst_length); + /* All of the following are *always* and *unconditionally* implemented * when the associated type has the "tp_features & TF_KW" flag set, * with the exception of `DeeKwds_Type', which has that flag, but does @@ -2484,6 +2501,14 @@ myob_hasitem_string_len_hash(MyObject *self, char const *key, size_t keylen, Dee return DeeError_NOTIMPLEMENTED(); } +PRIVATE WUNUSED NONNULL((1)) size_t DCALL +myob_asvector(MyObject *self, /*out*/ DREF DeeObject **dst, size_t dst_length) { + (void)self; + (void)dst; + (void)dst_length; + return (size_t)DeeError_NOTIMPLEMENTED(); +} + PRIVATE struct type_seq myob_seq = { /* .tp_iter = */ (DREF DeeObject *(DCALL *)(DeeObject *__restrict))&myob_iter, /* .tp_sizeob = */ (DREF DeeObject *(DCALL *)(DeeObject *__restrict))&myob_sizeob, @@ -2530,6 +2555,7 @@ PRIVATE struct type_seq myob_seq = { /* .tp_setitem_string_len_hash = */ (int (DCALL *)(DeeObject *, char const *, size_t, Dee_hash_t, DeeObject *))&myob_setitem_string_len_hash, /* .tp_bounditem_string_len_hash = */ (int (DCALL *)(DeeObject *, char const *, size_t, Dee_hash_t))&myob_bounditem_string_len_hash, /* .tp_hasitem_string_len_hash = */ (int (DCALL *)(DeeObject *, char const *, size_t, Dee_hash_t))&myob_hasitem_string_len_hash, + /* .tp_asvector = */ (size_t (DCALL *)(DeeObject *, DREF DeeObject **, size_t))&myob_asvector, /* .tp_getitemnr = */ (DeeObject *(DCALL *)(DeeObject *__restrict, /*string*/ DeeObject *__restrict))NULL, /* .tp_getitemnr_string_hash = */ (DeeObject *(DCALL *)(DeeObject *__restrict, char const *__restrict, Dee_hash_t))NULL, /* .tp_getitemnr_string_len_hash = */ (DeeObject *(DCALL *)(DeeObject *__restrict, char const *__restrict, size_t, Dee_hash_t))NULL, diff --git a/src/deemon/objects/bytes.c b/src/deemon/objects/bytes.c index db0318d5..3fe57750 100644 --- a/src/deemon/objects/bytes.c +++ b/src/deemon/objects/bytes.c @@ -1406,6 +1406,29 @@ bytes_foreach(Bytes *__restrict self, Dee_foreach_t proc, void *arg) { return temp; } +PRIVATE WUNUSED NONNULL((1)) size_t DCALL +bytes_asvector(Bytes *self, /*out*/ DREF DeeObject **dst, size_t dst_length) { + size_t size = DeeBytes_SIZE(self); + if likely(dst_length >= size) { + size_t i; + for (i = 0; i < size; ++i) { + DREF DeeObject *int_value; + byte_t value = DeeBytes_DATA(self)[i]; +#ifdef DeeInt_8bit + int_value = (DREF DeeObject *)(DeeInt_8bit + value); + Dee_Incref(int_value); +#else /* DeeInt_8bit */ + int_value = DeeInt_NewUInt8(value); + if unlikely(!int_value) { + Dee_Decrefv(dst, i); + return (size_t)-1; + } +#endif /* !DeeInt_8bit */ + dst[i] = int_value; /* Inherit reference */ + } + } + return size; +} PRIVATE struct type_nsi tpconst bytes_nsi = { /* .nsi_class = */ TYPE_SEQX_CLASS_SEQ, @@ -1482,6 +1505,7 @@ PRIVATE struct type_seq bytes_seq = { /* .tp_setitem_string_len_hash = */ NULL, /* .tp_bounditem_string_len_hash = */ NULL, /* .tp_hasitem_string_len_hash = */ NULL, + /* .tp_asvector = */ (size_t (DCALL *)(DeeObject *, DREF DeeObject **, size_t))&bytes_asvector, }; diff --git a/src/deemon/objects/cached-dict.c b/src/deemon/objects/cached-dict.c index 6b7c3845..a0326f18 100644 --- a/src/deemon/objects/cached-dict.c +++ b/src/deemon/objects/cached-dict.c @@ -1301,6 +1301,7 @@ PRIVATE struct type_seq cdict_seq = { /* .tp_setitem_string_len_hash = */ NULL, /* .tp_bounditem_string_len_hash = */ (int (DCALL *)(DeeObject *, char const *, size_t, Dee_hash_t))&cdict_bounditem_string_len_hash, /* .tp_hasitem_string_len_hash = */ NULL, + /* .tp_asvector = */ NULL, /* .tp_getitemnr = */ (DeeObject *(DCALL *)(DeeObject *__restrict, /*string*/ DeeObject *__restrict))&cdict_getitemnr, /* .tp_getitemnr_string_hash = */ (DeeObject *(DCALL *)(DeeObject *__restrict, char const *__restrict, Dee_hash_t))&cdict_getitemnr_string_hash, /* .tp_getitemnr_string_len_hash = */ (DeeObject *(DCALL *)(DeeObject *__restrict, char const *__restrict, size_t, Dee_hash_t))&cdict_getitemnr_string_len_hash, diff --git a/src/deemon/objects/hashset.c b/src/deemon/objects/hashset.c index c2a6a0c8..46522c31 100644 --- a/src/deemon/objects/hashset.c +++ b/src/deemon/objects/hashset.c @@ -1847,6 +1847,26 @@ hashset_printrepr(HashSet *__restrict self, return temp; } +PRIVATE WUNUSED NONNULL((1)) size_t DCALL +hashset_asvector(HashSet *self, /*out*/ DREF DeeObject **dst, size_t dst_length) { + size_t result; + DeeHashSet_LockRead(self); + result = self->hs_used; + if likely(dst_length >= result) { + struct hashset_item *iter, *end; + end = (iter = self->hs_elem) + (self->hs_mask + 1); + for (; iter < end; ++iter) { + DeeObject *key = iter->hsi_key; + if (key == NULL || key == dummy) + continue; + Dee_Incref(key); + *dst++ = key; + } + } + DeeHashSet_LockEndRead(self); + return result; +} + PRIVATE struct type_nsi tpconst hashset_nsi = { /* .nsi_class = */ TYPE_SEQX_CLASS_SET, /* .nsi_flags = */ TYPE_SEQX_FMUTABLE | TYPE_SEQX_FRESIZABLE, @@ -1903,6 +1923,7 @@ PRIVATE struct type_seq hashset_seq = { /* .tp_setitem_string_len_hash = */ NULL, /* .tp_bounditem_string_len_hash = */ NULL, /* .tp_hasitem_string_len_hash = */ NULL, + /* .tp_asvector = */ (size_t (DCALL *)(DeeObject *, DREF DeeObject **, size_t))&hashset_asvector, }; PRIVATE WUNUSED NONNULL((1)) int DCALL diff --git a/src/deemon/objects/list.c b/src/deemon/objects/list.c index 90b463aa..85d75c0e 100644 --- a/src/deemon/objects/list.c +++ b/src/deemon/objects/list.c @@ -2105,6 +2105,16 @@ list_enumerate_index(List *self, Dee_enumerate_index_t proc, return temp; } +PRIVATE WUNUSED NONNULL((1)) size_t DCALL +list_asvector(List *self, /*out*/ DREF DeeObject **dst, size_t dst_length) { + size_t realsize; + DeeList_LockRead(self); + realsize = self->l_list.ol_elemc; + if likely(dst_length >= realsize) + Dee_Movrefv(dst, self->l_list.ol_elemv, realsize); + DeeList_LockEndRead(self); + return realsize; +} PRIVATE struct type_nsi tpconst list_nsi = { /* .nsi_class = */ TYPE_SEQX_CLASS_SEQ, @@ -2173,6 +2183,7 @@ PRIVATE struct type_seq list_seq = { /* .tp_setitem_string_len_hash = */ NULL, /* .tp_bounditem_string_len_hash = */ NULL, /* .tp_hasitem_string_len_hash = */ NULL, + /* .tp_asvector = */ (size_t (DCALL *)(DeeObject *, DREF DeeObject **, size_t))&list_asvector, }; PRIVATE WUNUSED NONNULL((1, 2)) int DCALL diff --git a/src/deemon/objects/rodict.c b/src/deemon/objects/rodict.c index 5fa5d402..b9aec613 100644 --- a/src/deemon/objects/rodict.c +++ b/src/deemon/objects/rodict.c @@ -1043,6 +1043,7 @@ PRIVATE struct type_seq rodict_seq = { /* .tp_setitem_string_len_hash = */ NULL, /* .tp_bounditem_string_len_hash = */ NULL, /* .tp_hasitem_string_len_hash = */ (int (DCALL *)(DeeObject *, char const *, size_t, Dee_hash_t))&rodict_hasitem_string_len_hash, + /* .tp_asvector = */ NULL, /* .tp_getitemnr = */ (DeeObject *(DCALL *)(DeeObject *__restrict, /*string*/ DeeObject *__restrict))&rodict_getitemnr, /* .tp_getitemnr_string_hash = */ (DeeObject *(DCALL *)(DeeObject *__restrict, char const *__restrict, Dee_hash_t))&rodict_getitemnr_string_hash, /* .tp_getitemnr_string_len_hash = */ (DeeObject *(DCALL *)(DeeObject *__restrict, char const *__restrict, size_t, Dee_hash_t))&rodict_getitemnr_string_len_hash, diff --git a/src/deemon/objects/roset.c b/src/deemon/objects/roset.c index 5c945905..22957e40 100644 --- a/src/deemon/objects/roset.c +++ b/src/deemon/objects/roset.c @@ -501,6 +501,22 @@ roset_foreach(RoSet *self, Dee_foreach_t proc, void *arg) { return temp; } +PRIVATE WUNUSED NONNULL((1)) size_t DCALL +roset_asvector(RoSet *self, /*out*/ DREF DeeObject **dst, size_t dst_length) { + if likely(dst_length >= self->rs_size) { + struct roset_item *iter, *end; + end = (iter = self->rs_elem) + (self->rs_mask + 1); + for (; iter < end; ++iter) { + DeeObject *key = iter->rsi_key; + if (key == NULL) + continue; + Dee_Incref(key); + *dst++ = key; + } + } + return self->rs_size; +} + PRIVATE struct type_seq roset_seq = { /* .tp_iter = */ (DREF DeeObject *(DCALL *)(DeeObject *__restrict))&roset_iter, /* .tp_sizeob = */ NULL, @@ -547,6 +563,7 @@ PRIVATE struct type_seq roset_seq = { /* .tp_setitem_string_len_hash = */ NULL, /* .tp_bounditem_string_len_hash = */ NULL, /* .tp_hasitem_string_len_hash = */ NULL, + /* .tp_asvector = */ (size_t (DCALL *)(DeeObject *, DREF DeeObject **, size_t))&roset_asvector, }; PRIVATE WUNUSED NONNULL((1)) DREF DeeObject *DCALL diff --git a/src/deemon/objects/seq/fastseq.c b/src/deemon/objects/seq/fastseq.c index 5ed25713..6ea6bfdf 100644 --- a/src/deemon/objects/seq/fastseq.c +++ b/src/deemon/objects/seq/fastseq.c @@ -34,6 +34,8 @@ #include #include +#include + #include "../../runtime/runtime_error.h" #include "range.h" #include "subrange.h" @@ -285,6 +287,82 @@ foreach_seq_as_heap_vector_cb(void *arg, DeeObject *__restrict elem) { PUBLIC WUNUSED NONNULL((1, 2)) /*owned(Dee_Free)*/ DREF DeeObject **DCALL DeeSeq_AsHeapVector(DeeObject *__restrict self, size_t *__restrict p_length) { +#ifdef CONFIG_EXPERIMENTAL_NEW_SEQUENCE_OPERATORS + DeeTypeObject *tp_self = Dee_TYPE(self); + struct foreach_seq_as_heap_vector_data data; + if unlikely(!(likely(tp_self->tp_seq && tp_self->tp_seq->tp_foreach) || + unlikely(DeeType_InheritIter(tp_self)))) { + err_unimplemented_operator(tp_self, OPERATOR_ITER); + goto err; + } + + /* Try to use "tp_size_fast" to get a good guess regarding the initial buffer size. */ + if likely(tp_self->tp_seq->tp_size_fast) { + data.sahvd_alloc = (*tp_self->tp_seq->tp_size_fast)(self); + if (data.sahvd_alloc == (size_t)-1) + data.sahvd_alloc = 16; + } else { + data.sahvd_alloc = 16; + } + data.sahvd_vector = (DREF DeeObject **)Dee_TryMallocc(data.sahvd_alloc, sizeof(DREF DeeObject *)); + if unlikely(!data.sahvd_vector) { + data.sahvd_alloc = 1; + data.sahvd_vector = (DREF DeeObject **)Dee_Mallocc(1, sizeof(DREF DeeObject *)); + if unlikely(!data.sahvd_vector) + goto err; + } + + /* Check if the type supports the "tp_asvector" extension. */ + if (tp_self->tp_seq->tp_asvector) { + DREF DeeObject **new_vector; +again_asvector: + data.sahvd_size = (*tp_self->tp_seq->tp_asvector)(self, data.sahvd_vector, data.sahvd_alloc); + if likely(data.sahvd_size <= data.sahvd_alloc) { + if unlikely(data.sahvd_size < data.sahvd_alloc) + goto resize_data_and_done; + goto done; + } + if unlikely(data.sahvd_size == (size_t)-1) + goto err_vector; + /* Need a larger vector buffer. */ + data.sahvd_alloc = data.sahvd_size; + new_vector = (DREF DeeObject **)Dee_Reallocc(data.sahvd_vector, + data.sahvd_alloc, + sizeof(DREF DeeObject *)); + if unlikely(!new_vector) + goto err_vector; + data.sahvd_vector = new_vector; + goto again_asvector; + } + + /* Fallback: use "tp_foreach" to enumerate sequence items. */ + data.sahvd_size = 0; + if unlikely((*tp_self->tp_seq->tp_foreach)(self, &foreach_seq_as_heap_vector_cb, &data)) + goto err_vector_data; + ASSERT(data.sahvd_size <= data.sahvd_alloc); + + /* Free unused memory. */ + if (data.sahvd_size < data.sahvd_alloc) { + DREF DeeObject **new_vector; +resize_data_and_done: + new_vector = (DREF DeeObject **)Dee_TryReallocc(data.sahvd_vector, + data.sahvd_size, + sizeof(DREF DeeObject *)); + if likely(new_vector) + data.sahvd_vector = new_vector; + } + + /* Save the resulting length. */ +done: + *p_length = data.sahvd_size; + return data.sahvd_vector; +err_vector_data: + Dee_Decrefv(data.sahvd_vector, data.sahvd_size); +err_vector: + Dee_Free(data.sahvd_vector); +err: + return NULL; +#else /* CONFIG_EXPERIMENTAL_NEW_SEQUENCE_OPERATORS */ struct foreach_seq_as_heap_vector_data data; data.sahvd_size = DeeFastSeq_GetSize_deprecated(self); if (data.sahvd_size != DEE_FASTSEQ_NOTFAST_DEPRECATED) { @@ -343,6 +421,7 @@ DeeSeq_AsHeapVector(DeeObject *__restrict self, Dee_Free(data.sahvd_vector); err: return NULL; +#endif /* !CONFIG_EXPERIMENTAL_NEW_SEQUENCE_OPERATORS */ } #ifdef Dee_MallocUsableSize @@ -371,6 +450,71 @@ DeeSeq_AsHeapVectorWithAlloc(DeeObject *__restrict self, /*[out]*/ size_t *__restrict p_allocated) #endif /* !Dee_MallocUsableSize */ { +#ifdef CONFIG_EXPERIMENTAL_NEW_SEQUENCE_OPERATORS + DeeTypeObject *tp_self = Dee_TYPE(self); + struct foreach_seq_as_heap_vector_data data; + if unlikely(!(likely(tp_self->tp_seq && tp_self->tp_seq->tp_foreach) || + unlikely(DeeType_InheritIter(tp_self)))) { + err_unimplemented_operator(tp_self, OPERATOR_ITER); + goto err; + } + + /* Try to use "tp_size_fast" to get a good guess regarding the initial buffer size. */ + if likely(tp_self->tp_seq->tp_size_fast) { + data.sahvd_alloc = (*tp_self->tp_seq->tp_size_fast)(self); + if (data.sahvd_alloc == (size_t)-1) + data.sahvd_alloc = 16; + } else { + data.sahvd_alloc = 16; + } + data.sahvd_vector = (DREF DeeObject **)Dee_TryMallocc(data.sahvd_alloc, sizeof(DREF DeeObject *)); + if unlikely(!data.sahvd_vector) { + data.sahvd_alloc = 1; + data.sahvd_vector = (DREF DeeObject **)Dee_Mallocc(1, sizeof(DREF DeeObject *)); + if unlikely(!data.sahvd_vector) + goto err; + } + + /* Check if the type supports the "tp_asvector" extension. */ + if (tp_self->tp_seq->tp_asvector) { + DREF DeeObject **new_vector; +again_asvector: + data.sahvd_size = (*tp_self->tp_seq->tp_asvector)(self, data.sahvd_vector, data.sahvd_alloc); + if likely(data.sahvd_size <= data.sahvd_alloc) + goto done; + if unlikely(data.sahvd_size == (size_t)-1) + goto err_vector; + /* Need a larger vector buffer. */ + data.sahvd_alloc = data.sahvd_size; + new_vector = (DREF DeeObject **)Dee_Reallocc(data.sahvd_vector, + data.sahvd_alloc, + sizeof(DREF DeeObject *)); + if unlikely(!new_vector) + goto err_vector; + data.sahvd_vector = new_vector; + goto again_asvector; + } + + /* Fallback: use "tp_foreach" to enumerate sequence items. */ + data.sahvd_size = 0; + if unlikely((*tp_self->tp_seq->tp_foreach)(self, &foreach_seq_as_heap_vector_cb, &data)) + goto err_vector_data; + ASSERT(data.sahvd_size <= data.sahvd_alloc); + + /* Save the resulting length. */ +done: +#ifndef Dee_MallocUsableSize + *p_allocated = data.sahvd_alloc; +#endif /* !Dee_MallocUsableSize */ + *p_length = data.sahvd_size; + return data.sahvd_vector; +err_vector_data: + Dee_Decrefv(data.sahvd_vector, data.sahvd_size); +err_vector: + Dee_Free(data.sahvd_vector); +err: + return NULL; +#else /* CONFIG_EXPERIMENTAL_NEW_SEQUENCE_OPERATORS */ struct foreach_seq_as_heap_vector_data data; data.sahvd_size = DeeFastSeq_GetSize_deprecated(self); if (data.sahvd_size != DEE_FASTSEQ_NOTFAST_DEPRECATED) { @@ -425,6 +569,7 @@ DeeSeq_AsHeapVectorWithAlloc(DeeObject *__restrict self, Dee_Free(data.sahvd_vector); err: return NULL; +#endif /* !CONFIG_EXPERIMENTAL_NEW_SEQUENCE_OPERATORS */ } @@ -474,6 +619,78 @@ DeeSeq_AsHeapVectorWithAllocReuse(DeeObject *__restrict self, /*in-out*/ size_t *__restrict p_allocated) #endif /* !Dee_MallocUsableSize */ { +#ifdef CONFIG_EXPERIMENTAL_NEW_SEQUENCE_OPERATORS + DeeTypeObject *tp_self = Dee_TYPE(self); + struct foreach_seq_as_heap_vector_data data; + if unlikely(!(likely(tp_self->tp_seq && tp_self->tp_seq->tp_foreach) || + unlikely(DeeType_InheritIter(tp_self)))) { + err_unimplemented_operator(tp_self, OPERATOR_ITER); + goto err; + } + + data.sahvd_vector = *p_vector; +#ifdef Dee_MallocUsableSize + data.sahvd_alloc = Dee_MallocUsableSize(data.sahvd_vector) / sizeof(DREF DeeObject *); +#else /* Dee_MallocUsableSize */ + data.sahvd_alloc = *p_allocated; +#endif /* !Dee_MallocUsableSize */ + ASSERT(!data.sahvd_alloc || data.sahvd_vector); + + /* Try to use "tp_size_fast" to get a good guess regarding the initial buffer size. */ + if likely(tp_self->tp_seq->tp_size_fast) { + size_t min_alloc; + min_alloc = (*tp_self->tp_seq->tp_size_fast)(self); + if (min_alloc != (size_t)-1 && min_alloc > data.sahvd_alloc) { + DREF DeeObject **new_vector; + new_vector = (DREF DeeObject **)Dee_TryReallocc(data.sahvd_vector, min_alloc, + sizeof(DREF DeeObject *)); + if likely(new_vector) { + data.sahvd_vector = new_vector; + data.sahvd_alloc = min_alloc; + } + } + } + + /* Check if the type supports the "tp_asvector" extension. */ + if (tp_self->tp_seq->tp_asvector) { + DREF DeeObject **new_vector; +again_asvector: + data.sahvd_size = (*tp_self->tp_seq->tp_asvector)(self, data.sahvd_vector, data.sahvd_alloc); + if likely(data.sahvd_size <= data.sahvd_alloc) + goto done; + if unlikely(data.sahvd_size == (size_t)-1) + goto done; + /* Need a larger vector buffer. */ + data.sahvd_alloc = data.sahvd_size; + new_vector = (DREF DeeObject **)Dee_Reallocc(data.sahvd_vector, + data.sahvd_alloc, + sizeof(DREF DeeObject *)); + if unlikely(!new_vector) + goto err_writeback; + data.sahvd_vector = new_vector; + goto again_asvector; + } + + /* Fallback: use "tp_foreach" to enumerate sequence items. */ + data.sahvd_size = 0; + if unlikely((*tp_self->tp_seq->tp_foreach)(self, &foreach_seq_as_heap_vector_cb, &data)) + goto err_writeback_data; + ASSERT(data.sahvd_size <= data.sahvd_alloc); + +done: + *p_vector = data.sahvd_vector; +#ifndef Dee_MallocUsableSize + *p_allocated = data.sahvd_alloc; +#endif /* !Dee_MallocUsableSize */ + return data.sahvd_size; +err_writeback_data: + Dee_Decrefv(data.sahvd_vector, data.sahvd_size); +err_writeback: + data.sahvd_size = (size_t)-1; + goto done; +err: + return (size_t)-1; +#else /* CONFIG_EXPERIMENTAL_NEW_SEQUENCE_OPERATORS */ Dee_ssize_t error; struct foreach_seq_as_heap_vector_data data; data.sahvd_vector = *p_vector; @@ -511,7 +728,7 @@ DeeSeq_AsHeapVectorWithAllocReuse(DeeObject *__restrict self, elem = DeeFastSeq_GetItem_deprecated(self, i); if unlikely(!elem) { data.sahvd_size = i; - goto err_data; + goto err_writeback_data; } data.sahvd_vector[i] = elem; /* Inherit reference. */ } @@ -528,12 +745,13 @@ DeeSeq_AsHeapVectorWithAllocReuse(DeeObject *__restrict self, *p_allocated = data.sahvd_alloc; #endif /* !Dee_MallocUsableSize */ if unlikely(error) - goto err_data; + goto err_writeback_data; return data.sahvd_size; -err_data: +err_writeback_data: Dee_Decrefv(data.sahvd_vector, data.sahvd_size); err: return (size_t)-1; +#endif /* !CONFIG_EXPERIMENTAL_NEW_SEQUENCE_OPERATORS */ } @@ -575,6 +793,93 @@ DeeSeq_AsHeapVectorWithAllocReuseOffset(DeeObject *__restrict self, /*in*/ size_t offset) #endif /* !Dee_MallocUsableSize */ { +#ifdef CONFIG_EXPERIMENTAL_NEW_SEQUENCE_OPERATORS + DeeTypeObject *tp_self = Dee_TYPE(self); + struct foreach_seq_as_heap_vector_data data; + if unlikely(!(likely(tp_self->tp_seq && tp_self->tp_seq->tp_foreach) || + unlikely(DeeType_InheritIter(tp_self)))) { + err_unimplemented_operator(tp_self, OPERATOR_ITER); + goto err; + } + + data.sahvd_vector = *p_vector; +#ifdef Dee_MallocUsableSize + data.sahvd_alloc = Dee_MallocUsableSize(data.sahvd_vector) / sizeof(DREF DeeObject *); +#else /* Dee_MallocUsableSize */ + data.sahvd_alloc = *p_allocated; +#endif /* !Dee_MallocUsableSize */ + ASSERT(data.sahvd_alloc >= offset); + ASSERT(!data.sahvd_alloc || data.sahvd_vector); + + /* Try to use "tp_size_fast" to get a good guess regarding the initial buffer size. */ + if likely(tp_self->tp_seq->tp_size_fast) { + size_t min_alloc; + min_alloc = (*tp_self->tp_seq->tp_size_fast)(self); + if (min_alloc != (size_t)-1 && !OVERFLOW_UADD(min_alloc, offset, &min_alloc)) { + if (min_alloc > data.sahvd_alloc) { + DREF DeeObject **new_vector; + new_vector = (DREF DeeObject **)Dee_TryReallocc(data.sahvd_vector, min_alloc, + sizeof(DREF DeeObject *)); + if likely(new_vector) { + data.sahvd_vector = new_vector; + data.sahvd_alloc = min_alloc; + } + } + } + } + + /* Check if the type supports the "tp_asvector" extension. */ + if (tp_self->tp_seq->tp_asvector) { + DREF DeeObject **new_vector; +again_asvector: + data.sahvd_size = (*tp_self->tp_seq->tp_asvector)(self, + data.sahvd_vector + offset, + data.sahvd_alloc - offset); + if likely(data.sahvd_size <= (data.sahvd_alloc - offset)) { + data.sahvd_size += offset; + goto done; + } + if unlikely(data.sahvd_size == (size_t)-1) { + data.sahvd_size += offset; + goto done; + } + /* Need a larger vector buffer. */ + if unlikely(OVERFLOW_UADD(data.sahvd_size, offset, &data.sahvd_alloc)) { + Dee_BadAlloc((size_t)-1); + goto err_writeback; + } + new_vector = (DREF DeeObject **)Dee_Reallocc(data.sahvd_vector, + data.sahvd_alloc, + sizeof(DREF DeeObject *)); + if unlikely(!new_vector) + goto err_writeback; + data.sahvd_vector = new_vector; + goto again_asvector; + } + + /* Use `DeeObject_Foreach()' */ + data.sahvd_size = offset; + ASSERT(data.sahvd_size <= data.sahvd_alloc); + if unlikely((*tp_self->tp_seq->tp_foreach)(self, &foreach_seq_as_heap_vector_cb, &data)) + goto err_writeback_data; + ASSERT(data.sahvd_size <= data.sahvd_alloc); + ASSERT(data.sahvd_size >= offset); + +done: + *p_vector = data.sahvd_vector; +#ifndef Dee_MallocUsableSize + *p_allocated = data.sahvd_alloc; +#endif /* !Dee_MallocUsableSize */ + return data.sahvd_size - offset; +err_writeback_data: + Dee_Decrefv(data.sahvd_vector + offset, + data.sahvd_size - offset); +err_writeback: + data.sahvd_size = (size_t)-1; + goto done; +err: + return (size_t)-1; +#else /* CONFIG_EXPERIMENTAL_NEW_SEQUENCE_OPERATORS */ Dee_ssize_t error; struct foreach_seq_as_heap_vector_data data; data.sahvd_vector = *p_vector; @@ -640,6 +945,7 @@ DeeSeq_AsHeapVectorWithAllocReuseOffset(DeeObject *__restrict self, data.sahvd_size - offset); err: return (size_t)-1; +#endif /* !CONFIG_EXPERIMENTAL_NEW_SEQUENCE_OPERATORS */ } diff --git a/src/deemon/objects/seq/repeat.c b/src/deemon/objects/seq/repeat.c index 9d906843..98a5a450 100644 --- a/src/deemon/objects/seq/repeat.c +++ b/src/deemon/objects/seq/repeat.c @@ -1013,6 +1013,17 @@ repeatitem_foreach_pair(RepeatItem *self, Dee_foreach_pair_t proc, void *arg) { return -1; } +PRIVATE WUNUSED NONNULL((1)) size_t DCALL +repeatitem_asvector(RepeatItem *self, /*out*/ DREF DeeObject **dst, size_t dst_length) { + if unlikely(self->rpit_num == (size_t)-1) { + err_integer_overflow_i(sizeof(size_t) * 8, true); + } else { + if likely(dst_length >= self->rpit_num) + Dee_Setrefv(dst, self->rpit_obj, self->rpit_num); + } + return self->rpit_num; +} + PRIVATE struct type_nsi tpconst repeatitem_nsi = { /* .nsi_class = */ TYPE_SEQX_CLASS_SEQ, @@ -1077,6 +1088,7 @@ PRIVATE struct type_seq repeatitem_seq = { /* .tp_setitem_string_len_hash = */ NULL, /* .tp_bounditem_string_len_hash = */ NULL, /* .tp_hasitem_string_len_hash = */ NULL, + /* .tp_asvector = */ (size_t (DCALL *)(DeeObject *, DREF DeeObject **, size_t))&repeatitem_asvector, }; PRIVATE struct type_member tpconst repeatitem_members[] = { diff --git a/src/deemon/objects/seq/svec.c b/src/deemon/objects/seq/svec.c index 22475d86..8e9385b8 100644 --- a/src/deemon/objects/seq/svec.c +++ b/src/deemon/objects/seq/svec.c @@ -1097,6 +1097,17 @@ svec_enumerate_index(SharedVector *self, Dee_enumerate_index_t proc, return temp; } +PRIVATE WUNUSED NONNULL((1)) size_t DCALL +svec_asvector(SharedVector *self, /*out*/ DREF DeeObject **dst, size_t dst_length) { + size_t realsize; + SharedVector_LockRead(self); + realsize = self->sv_length; + if likely(dst_length >= realsize) + Dee_Movrefv(dst, self->sv_vector, realsize); + SharedVector_LockEndRead(self); + return realsize; +} + PRIVATE struct type_nsi tpconst svec_nsi = { /* .nsi_class = */ TYPE_SEQX_CLASS_SEQ, @@ -1322,6 +1333,7 @@ PRIVATE struct type_seq svec_seq = { /* .tp_setitem_string_len_hash = */ NULL, /* .tp_bounditem_string_len_hash = */ NULL, /* .tp_hasitem_string_len_hash = */ NULL, + /* .tp_asvector = */ (size_t (DCALL *)(DeeObject *, DREF DeeObject **, size_t))&svec_asvector, }; PRIVATE struct type_getset tpconst svec_getsets[] = { diff --git a/src/deemon/objects/string.c b/src/deemon/objects/string.c index d06bc342..bbcc198f 100644 --- a/src/deemon/objects/string.c +++ b/src/deemon/objects/string.c @@ -1610,6 +1610,69 @@ string_foreach(String *self, Dee_foreach_t proc, void *arg) { return -1; } +PRIVATE WUNUSED NONNULL((1)) size_t DCALL +string_asvector(String *self, /*out*/ DREF DeeObject **dst, size_t dst_length) { + size_t result; + union dcharptr ptr, end; + DREF DeeObject **dst_iter = dst; + SWITCH_SIZEOF_WIDTH(DeeString_WIDTH(self)) { + + CASE_WIDTH_1BYTE: + ptr.cp8 = DeeString_Get1Byte((DeeObject *)self); + result = WSTR_LENGTH(ptr.cp8); + if unlikely(dst_length < result) + break; + end.cp8 = ptr.cp8 + result; + for (; ptr.cp8 < end.cp8; ++ptr.cp8) { + DREF DeeObject *chr; +#ifdef CONFIG_STRING_LATIN1_STATIC + chr = (DeeObject *)&DeeString_Latin1[*ptr.cp8]; + Dee_Incref(chr); +#else /* CONFIG_STRING_LATIN1_STATIC */ + chr = DeeString_Chr(*ptr.cp8); + if unlikely(!chr) + goto err_dst_iter; +#endif /* !CONFIG_STRING_LATIN1_STATIC */ + *dst_iter++ = chr; + } + break; + + CASE_WIDTH_2BYTE: + ptr.cp16 = DeeString_Get2Byte((DeeObject *)self); + result = WSTR_LENGTH(ptr.cp16); + if unlikely(dst_length < result) + break; + end.cp16 = ptr.cp16 + result; + for (; ptr.cp16 < end.cp16; ++ptr.cp16) { + DREF DeeObject *chr; + chr = DeeString_Chr(*ptr.cp16); + if unlikely(!chr) + goto err_dst_iter; + *dst_iter++ = chr; + } + break; + + CASE_WIDTH_4BYTE: + ptr.cp32 = DeeString_Get4Byte((DeeObject *)self); + result = WSTR_LENGTH(ptr.cp32); + if unlikely(dst_length < result) + break; + end.cp32 = ptr.cp32 + result; + for (; ptr.cp32 < end.cp32; ++ptr.cp32) { + DREF DeeObject *chr; + chr = DeeString_Chr(*ptr.cp32); + if unlikely(!chr) + goto err_dst_iter; + *dst_iter++ = chr; + } + break; + } + return result; +err_dst_iter: + Dee_Decrefv(dst, (size_t)(dst_iter - dst)); + return (size_t)-1; +} + PRIVATE struct type_nsi tpconst string_nsi = { /* .nsi_class = */ TYPE_SEQX_CLASS_SEQ, /* .nsi_flags = */ TYPE_SEQX_FNORMAL, @@ -1673,6 +1736,7 @@ PRIVATE struct type_seq string_seq = { /* .tp_setitem_string_len_hash = */ NULL, /* .tp_bounditem_string_len_hash = */ NULL, /* .tp_hasitem_string_len_hash = */ NULL, + /* .tp_asvector = */ (size_t (DCALL *)(DeeObject *, DREF DeeObject **, size_t))&string_asvector, }; PRIVATE struct type_member tpconst string_class_members[] = { diff --git a/src/deemon/objects/tuple.c b/src/deemon/objects/tuple.c index 4de033c1..44895957 100644 --- a/src/deemon/objects/tuple.c +++ b/src/deemon/objects/tuple.c @@ -1581,6 +1581,14 @@ tuple_enumerate_index(Tuple *self, Dee_enumerate_index_t proc, return temp; } +PRIVATE WUNUSED NONNULL((1)) size_t DCALL +tuple_asvector(Tuple *self, /*out*/ DREF DeeObject **dst, size_t dst_length) { + if unlikely(dst_length < self->t_size) + return self->t_size; + Dee_Movrefv(dst, self->t_elem, self->t_size); + return self->t_size; +} + PRIVATE struct type_nsi tpconst tuple_nsi = { /* .nsi_class = */ TYPE_SEQX_CLASS_SEQ, /* .nsi_flags = */ TYPE_SEQX_FNORMAL, @@ -1645,6 +1653,7 @@ PRIVATE struct type_seq tuple_seq = { /* .tp_setitem_string_len_hash = */ NULL, /* .tp_bounditem_string_len_hash = */ NULL, /* .tp_hasitem_string_len_hash = */ NULL, + /* .tp_asvector = */ (size_t (DCALL *)(DeeObject *, DREF DeeObject **, size_t))&tuple_asvector, }; PRIVATE WUNUSED NONNULL((1)) DREF Tuple *DCALL diff --git a/src/deemon/runtime/kwds-wrappers.c b/src/deemon/runtime/kwds-wrappers.c index 8736efbf..c7e6e35e 100644 --- a/src/deemon/runtime/kwds-wrappers.c +++ b/src/deemon/runtime/kwds-wrappers.c @@ -817,6 +817,7 @@ PRIVATE struct type_seq blv_seq = { /* .tp_setitem_string_len_hash = */ NULL, /* .tp_bounditem_string_len_hash = */ NULL, /* .tp_hasitem_string_len_hash = */ (int (DCALL *)(DeeObject *, char const *, size_t, Dee_hash_t))&blv_hasitem_string_len_hash, + /* .tp_asvector = */ NULL, /* .tp_getitemnr = */ (DeeObject *(DCALL *)(DeeObject *__restrict, /*string*/ DeeObject *__restrict))&blv_getitemnr, /* .tp_getitemnr_string_hash = */ (DeeObject *(DCALL *)(DeeObject *__restrict, char const *__restrict, Dee_hash_t))&blv_getitemnr_string_hash, /* .tp_getitemnr_string_len_hash = */ (DeeObject *(DCALL *)(DeeObject *__restrict, char const *__restrict, size_t, Dee_hash_t))&blv_getitemnr_string_len_hash, @@ -1817,6 +1818,7 @@ PRIVATE struct type_seq blkw_seq = { /* .tp_setitem_string_len_hash = */ NULL, /* .tp_bounditem_string_len_hash = */ (int (DCALL *)(DeeObject *, char const *, size_t, Dee_hash_t))&blkw_bounditem_string_len_hash, /* .tp_hasitem_string_len_hash = */ (int (DCALL *)(DeeObject *, char const *, size_t, Dee_hash_t))&blkw_hasitem_string_len_hash, + /* .tp_asvector = */ NULL, /* .tp_getitemnr = */ (DeeObject *(DCALL *)(DeeObject *__restrict, /*string*/ DeeObject *__restrict))&blkw_getitemnr, /* .tp_getitemnr_string_hash = */ (DeeObject *(DCALL *)(DeeObject *__restrict, char const *__restrict, Dee_hash_t))&blkw_getitemnr_string_hash, /* .tp_getitemnr_string_len_hash = */ (DeeObject *(DCALL *)(DeeObject *__restrict, char const *__restrict, size_t, Dee_hash_t))&blkw_getitemnr_string_len_hash, diff --git a/src/deemon/runtime/kwds.c b/src/deemon/runtime/kwds.c index 84a1485e..455feaa8 100644 --- a/src/deemon/runtime/kwds.c +++ b/src/deemon/runtime/kwds.c @@ -1526,6 +1526,7 @@ PRIVATE struct type_seq kmap_seq = { /* .tp_setitem_string_len_hash = */ NULL, /* .tp_bounditem_string_len_hash = */ NULL, /* .tp_hasitem_string_len_hash = */ (int (DCALL *)(DeeObject *, char const *, size_t, Dee_hash_t))&kmap_hasitem_string_len_hash, + /* .tp_asvector = */ NULL, /* .tp_getitemnr = */ (DeeObject *(DCALL *)(DeeObject *__restrict, /*string*/ DeeObject *__restrict))&kmap_getitemnr, /* .tp_getitemnr_string_hash = */ (DeeObject *(DCALL *)(DeeObject *__restrict, char const *__restrict, Dee_hash_t))&kmap_getitemnr_string_hash, /* .tp_getitemnr_string_len_hash = */ (DeeObject *(DCALL *)(DeeObject *__restrict, char const *__restrict, size_t, Dee_hash_t))&kmap_getitemnr_string_len_hash, diff --git a/src/deemon/runtime/operator.c b/src/deemon/runtime/operator.c index a072fd2e..8f174dc5 100644 --- a/src/deemon/runtime/operator.c +++ b/src/deemon/runtime/operator.c @@ -16517,6 +16517,7 @@ DeeType_InheritSeqOperators(DeeTypeObject *__restrict self, unsigned int seqclas self->tp_seq->tp_setitem_string_len_hash = base_seq->tp_setitem_string_len_hash; self->tp_seq->tp_bounditem_string_len_hash = base_seq->tp_bounditem_string_len_hash; self->tp_seq->tp_hasitem_string_len_hash = base_seq->tp_hasitem_string_len_hash; + self->tp_seq->tp_asvector = base_seq->tp_asvector; } else { self->tp_seq = base_seq; } @@ -16589,6 +16590,7 @@ DeeType_InheritIter(DeeTypeObject *__restrict self) { self->tp_seq->tp_iter = base_seq->tp_iter; self->tp_seq->tp_foreach = base_seq->tp_foreach; self->tp_seq->tp_foreach_pair = base_seq->tp_foreach_pair; + self->tp_seq->tp_asvector = base_seq->tp_asvector; } else { self->tp_seq = base_seq; }