diff --git a/include/xo/object2/DArray.hpp b/include/xo/object2/DArray.hpp index 1d3499a..de65d1d 100644 --- a/include/xo/object2/DArray.hpp +++ b/include/xo/object2/DArray.hpp @@ -15,6 +15,24 @@ namespace xo { namespace scm { + class DArray; + + namespace detail { + /** null base case **/ + static inline bool do_array_push_back(DArray *, + obj) + { + return true; + } + + template + requires (std::convertible_to>) + static bool do_array_push_back(DArray * lhs, + obj gc, + A arg1, + Rest... rest); + } + /** @class DArray * @brief Polymorphic array implementation with gc hooks * @@ -30,11 +48,8 @@ namespace xo { /** type for array size **/ using size_type = std::uint32_t; - /** xo allocator facet **/ using AAllocator = xo::mm::AAllocator; - /** garbage collector facet **/ - //using ACollector = xo::mm::ACollector; - /** gc-aware object facet **/ + using ACollector = xo::mm::ACollector; using AGCObject = xo::mm::AGCObject; /** gc-centric object visitor **/ using AGCObjectVisitor = xo::mm::AGCObjectVisitor; @@ -59,8 +74,8 @@ namespace xo { * using memory from allocator @p mm. * Nullptr if space exhausted **/ - static DArray * empty(obj mm, - size_type cap); + static DArray * _empty(obj mm, + size_type cap); /** create copy of @p src using memory from @p mm * with capacity for @p new_cap elements @@ -80,8 +95,13 @@ namespace xo { static DArray * array(obj mm, Args... args); ///@} - /** @defgroup darray-access acecss methods **/ + /** @defgroup darray-access access methods **/ ///@{ + + /** create fop for this instance **/ + template + obj ref() { return obj(this); } + /** true iff array is empty **/ bool is_empty() const noexcept { return size_ == 0; } /** only support finite arrays :-) **/ @@ -108,13 +128,17 @@ namespace xo { /** store @p elt at position @p index. * true on success, false otherwise **/ - bool assign_at(size_type index, obj elt) noexcept; + bool assign_at(obj gc, size_type index, obj elt) noexcept; /** append @p elt at the end of array. * true on success, false otherwise. * on failure array is unaltered **/ - bool push_back(obj elt) noexcept; + bool push_back(obj gc, obj elt) noexcept; + + template + requires (std::convertible_to> && ...) + bool push_back_all(obj gc, Args... args) noexcept; /** store last element in array into @p elt and decrement array size. * true on success; false on failure (implies array was empty) @@ -182,13 +206,34 @@ namespace xo { DArray * DArray::array(obj mm, Args... args) { - DArray * result = empty(mm, sizeof...(args)); + obj gc = mm.try_to_facet(); + DArray * result = _empty(mm, sizeof...(args)); if (result) { - (result->push_back(args), ...); + detail::do_array_push_back(result, gc, args...); } return result; } + namespace detail { + template + requires (std::convertible_to>) + static bool do_array_push_back(DArray * lhs, + obj gc, + A arg1, + Rest... rest) + { + return (lhs->push_back(gc, arg1) + && do_array_push_back(lhs, gc, rest...)); + } + } + + template + requires (std::convertible_to> && ...) + bool + DArray::push_back_all(obj gc, Args... args) noexcept { + return detail::do_array_push_back(this, gc, args...); + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/include/xo/object2/DDictionary.hpp b/include/xo/object2/DDictionary.hpp index 8227721..972c71b 100644 --- a/include/xo/object2/DDictionary.hpp +++ b/include/xo/object2/DDictionary.hpp @@ -144,12 +144,12 @@ namespace xo { * * @return true if key-value pair updated; false if key not found **/ - bool try_update(const pair_type & kvpair); + bool try_update(obj gc, const pair_type & kvpair); /** update key-value pair for existing @p key to map to @p value. * false if @p key not already present. **/ - bool try_update_cstr(const char * key, obj value); + bool try_update_cstr(obj gc, const char * key, obj value); /** convenience method: * try_upsert pair (k, @p value), after boxing c-style string @p key with @p mm to get k @@ -167,7 +167,7 @@ namespace xo { * * False if dictionary already at capacity **/ - bool try_upsert(const pair_type & kvpair); + bool try_upsert(obj gc, const pair_type & kvpair); /** upsert key-value pair @p kvpair into dictionary. * If at capacity, expand capacity, getting new memory from @p mm. @@ -217,7 +217,7 @@ namespace xo { /** append {key, value} pair @p kv_pair to this dictionary * Require: @p kv_pair.first not already present in @ref keys_ **/ - bool _append_kv_aux(const pair_type & kv_pair); + bool _append_kv_aux(obj gc, const pair_type & kv_pair); ///@} private: diff --git a/src/object2/DArray.cpp b/src/object2/DArray.cpp index a181f9c..1910e8e 100644 --- a/src/object2/DArray.cpp +++ b/src/object2/DArray.cpp @@ -4,6 +4,7 @@ **/ #include "DArray.hpp" +#include "gc/RCollector_aux.hpp" #include #include #include @@ -15,13 +16,14 @@ namespace xo { using xo::print::APrintable; using xo::facet::FacetRegistry; using xo::mm::AGCObject; + using xo::mm::mm_do_assign; using xo::facet::typeseq; namespace scm { // TODO: error reporting? DArray * - DArray::empty(obj mm, - size_type cap) + DArray::_empty(obj mm, + size_type cap) { DArray * result = nullptr; @@ -45,7 +47,7 @@ namespace xo { DArray * src, size_type new_cap) { - DArray * dest = empty(mm, new_cap); + DArray * dest = _empty(mm, new_cap); if (dest) [[likely]] { /** could just memcpy here **/ @@ -73,20 +75,20 @@ namespace xo { } bool - DArray::assign_at(size_type ix, obj x) noexcept + DArray::assign_at(obj gc, size_type ix, obj x) noexcept { if (ix >= size_) return false; scope log(XO_DEBUG(true), "need write barrier"); - this->elts_[ix] = x; + mm_do_assign(gc, this, &elts_[ix], x); return true; } bool - DArray::push_back(obj elt) noexcept + DArray::push_back(obj gc, obj elt) noexcept { if (size_ >= capacity_) { return false; @@ -94,8 +96,9 @@ namespace xo { static_assert(!std::is_trivially_constructible_v>); void * mem = &(elts_[size_]); + new (mem) obj(); - new (mem) obj(elt); + mm_do_assign(gc, this, &(elts_[size_]), elt); ++(this->size_); diff --git a/src/object2/DDictionary.cpp b/src/object2/DDictionary.cpp index 57e71ed..43a4e1c 100644 --- a/src/object2/DDictionary.cpp +++ b/src/object2/DDictionary.cpp @@ -30,8 +30,8 @@ namespace xo { if (cap <= 0) cap = 1; - DArray * keys = DArray::empty(mm, cap); - DArray * values = DArray::empty(mm, cap); + DArray * keys = DArray::_empty(mm, cap); + DArray * values = DArray::_empty(mm, cap); if (keys && values) return new (mem) DDictionary(keys, values); @@ -108,7 +108,7 @@ namespace xo { } bool - DDictionary::try_update(const pair_type & kv_pair) + DDictionary::try_update(obj gc, const pair_type & kv_pair) { for (size_type i = 0, n = keys_->size(); i < n; ++i) { auto key_i = obj::from((*keys_)[i]); @@ -116,7 +116,7 @@ namespace xo { assert(key_i); if (*(key_i.data()) == *(kv_pair.first)) { - values_->assign_at(i, kv_pair.second); + values_->assign_at(gc, i, kv_pair.second); return true; } } @@ -125,7 +125,7 @@ namespace xo { } bool - DDictionary::try_update_cstr(const char * key, obj value) + DDictionary::try_update_cstr(obj gc, const char * key, obj value) { for (size_type i = 0, n = keys_->size(); i < n; ++i) { auto key_i = obj::from((*keys_)[i]); @@ -133,7 +133,7 @@ namespace xo { assert(key_i); if (strcmp(key, key_i->data()) == 0) { - values_->assign_at(i, value); + values_->assign_at(gc, i, value); return true; } @@ -147,8 +147,10 @@ namespace xo { { const DString * k1 = DString::from_cstr(mm, key_cstr); - if (k1) - return this->try_upsert(std::make_pair(k1, value)); + if (k1) { + obj gc = mm.try_to_facet(); + return this->try_upsert(gc, std::make_pair(k1, value)); + } return false; } @@ -165,21 +167,23 @@ namespace xo { } bool - DDictionary::try_upsert(const pair_type & kv_pair) + DDictionary::try_upsert(obj gc, const pair_type & kv_pair) { - if (this->try_update(kv_pair)) + if (this->try_update(gc, kv_pair)) return true; if (keys_->size() == keys_->capacity()) return false; - return this->_append_kv_aux(kv_pair); + return this->_append_kv_aux(gc, kv_pair); } bool DDictionary::upsert(obj mm, const pair_type & kv_pair) { - if (this->try_update(kv_pair)) + obj gc = mm.try_to_facet(); + + if (this->try_update(gc, kv_pair)) return true; // key not present -> must expand {key array, value array} @@ -200,17 +204,19 @@ namespace xo { } } - return this->_append_kv_aux(kv_pair); + return this->_append_kv_aux(gc, kv_pair); } bool - DDictionary::_append_kv_aux(const pair_type & kv_pair) + DDictionary::_append_kv_aux(obj gc, const pair_type & kv_pair) { + DString * key = const_cast(kv_pair.first); + bool ok - = keys_->push_back(obj(const_cast(kv_pair.first))); + = keys_->push_back(gc, obj(key)); if (ok) { - ok = values_->push_back(kv_pair.second); + ok = values_->push_back(gc, kv_pair.second); if (!ok) { // since we couldn't insert value, also drop key diff --git a/utest/DArray.test.cpp b/utest/DArray.test.cpp index 84afbe1..af26c71 100644 --- a/utest/DArray.test.cpp +++ b/utest/DArray.test.cpp @@ -14,6 +14,7 @@ namespace xo { using xo::scm::ListOps; using xo::scm::DArray; using xo::scm::DInteger; + using xo::mm::ACollector; using xo::mm::AAllocator; using xo::mm::AGCObject; using xo::mm::DArena; @@ -31,7 +32,10 @@ namespace xo { REQUIRE(arr.is_empty());; - REQUIRE(arr.push_back(ListOps::nil()) == false); + // null_gc: for no memory barrier + obj null_gc; + + REQUIRE(arr.push_back(null_gc, ListOps::nil()) == false); } TEST_CASE("DArray-empty", "[object2][DArray]") @@ -41,7 +45,7 @@ namespace xo { DArena arena = DArena::map(cfg); auto alloc = with_facet::mkobj(&arena); - DArray * arr = DArray::empty(alloc, 16); + DArray * arr = DArray::_empty(alloc, 16); REQUIRE(arr != nullptr); REQUIRE(arr->capacity() == 16); @@ -57,15 +61,16 @@ namespace xo { .size_ = 4*1024 }; DArena arena = DArena::map(cfg); auto alloc = with_facet::mkobj(&arena); + obj null_gc; - DArray * arr = DArray::empty(alloc, 16); + DArray * arr = DArray::_empty(alloc, 16); REQUIRE(arr != nullptr); REQUIRE(arr->capacity() == 16); REQUIRE(arr->size() == 0); obj elt = DInteger::box(alloc, 42); - bool ok = arr->push_back(elt); + bool ok = arr->push_back(null_gc, elt); REQUIRE(ok == true); REQUIRE(arr->is_empty() == false); @@ -79,8 +84,9 @@ namespace xo { .size_ = 4*1024 }; DArena arena = DArena::map(cfg); auto alloc = with_facet::mkobj(&arena); + obj null_gc; - DArray * arr = DArray::empty(alloc, 4); + DArray * arr = DArray::_empty(alloc, 4); REQUIRE(arr != nullptr); REQUIRE(arr->capacity() == 4); REQUIRE(arr->size() == 0); @@ -90,7 +96,7 @@ namespace xo { REQUIRE(arr->size() == i); obj elt = DInteger::box(alloc, 100 + i); - bool ok = arr->push_back(elt); + bool ok = arr->push_back(null_gc, elt); REQUIRE(ok == true); REQUIRE(arr->capacity() == 4); @@ -106,7 +112,8 @@ namespace xo { DArena arena = DArena::map(cfg); auto alloc = with_facet::mkobj(&arena); - DArray * arr = DArray::empty(alloc, 2); + DArray * arr = DArray::_empty(alloc, 2); + obj null_gc; REQUIRE(arr != nullptr); REQUIRE(arr->capacity() == 2); @@ -116,11 +123,11 @@ namespace xo { obj e2 = DInteger::box(alloc, 2); obj e3 = DInteger::box(alloc, 3); - REQUIRE(arr->push_back(e1) == true); + REQUIRE(arr->push_back(null_gc, e1) == true); REQUIRE(arr->size() == 1); - REQUIRE(arr->push_back(e2) == true); + REQUIRE(arr->push_back(null_gc, e2) == true); REQUIRE(arr->size() == 2); - REQUIRE(arr->push_back(e3) == false); + REQUIRE(arr->push_back(null_gc, e3) == false); REQUIRE(arr->size() == 2); REQUIRE(arr->capacity() == 2); } @@ -132,7 +139,8 @@ namespace xo { DArena arena = DArena::map(cfg); auto alloc = with_facet::mkobj(&arena); - DArray * arr = DArray::empty(alloc, 4); + DArray * arr = DArray::_empty(alloc, 4); + obj null_gc; REQUIRE(arr != nullptr); REQUIRE(arr->size() == 0); @@ -142,9 +150,9 @@ namespace xo { obj e1 = DInteger::box(alloc, 200); obj e2 = DInteger::box(alloc, 300); - arr->push_back(e0); - arr->push_back(e1); - arr->push_back(e2); + arr->push_back(null_gc, e0); + arr->push_back(null_gc, e1); + arr->push_back(null_gc, e2); REQUIRE(arr->size() == 3);