diff --git a/xo-alloc2/include/xo/alloc2/dp.hpp b/xo-alloc2/include/xo/alloc2/dp.hpp new file mode 100644 index 00000000..6c768ce8 --- /dev/null +++ b/xo-alloc2/include/xo/alloc2/dp.hpp @@ -0,0 +1,110 @@ +/** @file dp.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "Allocator.hpp" +#include +#include + +namespace xo { + namespace mm { + + /** unimorphic "data pointer" with known representation and owned memory. + * runs dtor *but not delete*. Does not store allocator! + * + * Compare with abox + **/ + template + struct dp { + dp() = default; + + /** dp takes ownership of data @p ptr; + * will run dtor when dp goes out of scope. + * + * Note this is not useful when DRepr=DVariablePlaceholder + **/ + explicit dp(DRepr * ptr) : ptr_{ptr} {} + + /** (copy ctor not supported -- ownership is unique) **/ + dp(const dp & other) = delete; + + /** Move constructor **/ + dp(dp && other) + { + ptr_ = other.ptr_; + other.ptr_ = nullptr; + } + + /** allocates for sizeof(DRepr), so DRepr must not use flexible array **/ + template + static dp make(obj alloc, Args&&... args) { + void * mem = alloc.alloc_for(); + + if (mem) { + DRepr * data = ::new (mem) DRepr(std::forward(args)...); + assert(data); + + return dp(data); + } else { + assert(false); + + return dp(); + } + } + + dp & operator=(const dp & x) = delete; + + /** move assignment **/ + dp & operator=(dp && x) { + ptr_ = x.ptr_; + x.ptr_ = nullptr; + } + + // -------------------------------- + + DRepr * data() const noexcept { return ptr_; } + + operator bool() const noexcept { return ptr_ != nullptr; } + + DRepr * operator->() const noexcept { return ptr_; } + DRepr & operator*() const noexcept { return *ptr_; } + +#ifdef NOT_YET + /** explicit conversion to obj **/ + obj to_op() const noexcept { + return obj(this->iface(), this->data()); + } +#endif + +#ifdef NOT_YET + /** Take ownership from unowned object **/ + template + dp & adopt(const obj & other) + requires (std::is_same_v + || std::is_same_v) + { + /* replace .iface_ along w/ .data_ */ + this->from_obj(other); + + return *this; + } +#endif + + ~dp() { + if (ptr_) { + ptr_->~DRepr(); + } + } + + private: + DRepr * ptr_ = nullptr; + }; + } /*namespace mm*/ + + using mm::dp; +} /*namespace xo*/ + +/* end dp.hpp */ diff --git a/xo-expression2/include/xo/expression2/DGlobalSymtab.hpp b/xo-expression2/include/xo/expression2/DGlobalSymtab.hpp index 32fb9570..566d8981 100644 --- a/xo-expression2/include/xo/expression2/DGlobalSymtab.hpp +++ b/xo-expression2/include/xo/expression2/DGlobalSymtab.hpp @@ -8,6 +8,7 @@ #include "Binding.hpp" #include "DVariable.hpp" #include +#include #include namespace xo { @@ -35,16 +36,16 @@ namespace xo { /** @defgroup scm-globalsymtab-ctors constructors **/ ///@{ - DGlobalSymtab(repr_type * map, DArray * vars); + DGlobalSymtab(dp map, DArray * vars); /** create instance. * Use memory from @p fixed_mm for @ref map_. * Use memory from @p mm for DGlobalSymtab instance. * Hashmap configured per @p cfg. **/ - DGlobalSymtab * make(obj fixed_mm, - obj mm, - const ArenaHashMapConfig & cfg); + dp make(obj fixed_mm, + obj mm, + const ArenaHashMapConfig & cfg); ///@} /** @defgroup scm-globalsymtab-access-methods access methods **/ @@ -81,21 +82,21 @@ namespace xo { ///@} /** @defgroup scm-globalsymtab-gcobject-facet gcobject facet **/ ///@{ - + std::size_t shallow_size() const noexcept; DGlobalSymtab * shallow_copy(obj mm) const noexcept; std::size_t forward_children(obj gc) noexcept; ///@} - + private: /** map symbols -> bindings. * Minor point: storing offsets instead of Variables allows us to omit * iterating over map elements during GC. Possible savings if map_ slots * sparsely populated. **/ - repr_type * map_ = nullptr; - + dp map_; + /** array of variables. * When S is a unique-string for a global symbol, then: * 1. map_[S] is unique global index i(S) for S. diff --git a/xo-expression2/src/expression2/DGlobalSymtab.cpp b/xo-expression2/src/expression2/DGlobalSymtab.cpp index 85fd6e93..b7eb4d73 100644 --- a/xo-expression2/src/expression2/DGlobalSymtab.cpp +++ b/xo-expression2/src/expression2/DGlobalSymtab.cpp @@ -18,35 +18,25 @@ namespace xo { namespace scm { - DGlobalSymtab::DGlobalSymtab(repr_type * map, + DGlobalSymtab::DGlobalSymtab(dp map, DArray * vars) - : map_{map}, vars_{vars} + : map_{std::move(map)}, vars_{vars} { } - DGlobalSymtab * - DGlobalSymtab::make(obj global_mm, + dp + DGlobalSymtab::make(obj aux_mm, obj mm, const ArenaHashMapConfig & cfg) { - repr_type * map = nullptr; - { - /** memory DGlobalSymtab::map_ - * (but not counting the mmap()'s that map will make for itself) - **/ - void * global_mem = global_mm.alloc_for(); - - map = new (global_mem) repr_type(cfg); - } + auto map = dp::make(aux_mm, cfg); assert(map); - void * symtab_mem = mm.alloc_for(); - /* choosing same capacity for hash, vars */ DArray * vars = DArray::empty(mm, map->capacity()); assert(vars); - DGlobalSymtab * symtab = new (symtab_mem) DGlobalSymtab(map, vars); + auto symtab = dp::make(mm, std::move(map), vars); assert(symtab); return symtab; @@ -133,7 +123,7 @@ namespace xo { auto ix = map_->find(sym); - if (ix == map_->end()) + if (ix == map_->end()) return Binding::null(); return Binding::global(ix->second); @@ -150,7 +140,22 @@ namespace xo { DGlobalSymtab * DGlobalSymtab::shallow_copy(obj mm) const noexcept { - return mm.std_copy_for(this); + /** can't use std_copy_for because of non-copyable dp + * + * TODO: rename to shallow_move() throughout, and have std_copy_for() + * -> std_move_for() + * + **/ + + void * copy_mem = mm.alloc_copy_for(this); + + if (copy_mem) { + DGlobalSymtab * self = const_cast(this); + + return new (copy_mem) DGlobalSymtab(std::move(self->map_), vars_); + } + + return nullptr; } std::size_t