/** @file IAlloc.hpp * * @author: Roland Conybeare, Jul 2025 **/ #pragma once #include #include namespace xo { template using up = std::unique_ptr; class IObject; namespace gc { /** @class IAllocator * @brief Abstract API for allocation interface * * Garbage collector support methods: * - checkpoint() * - assign_member() * - alloc_gc_copy() * * See class GC for copying incremental collector. * See class ArenaAlloc for arena allocator **/ class IAlloc { public: virtual ~IAlloc() {} static inline std::uint32_t alloc_padding(std::size_t z) { /* word size for alignment */ constexpr uint32_t c_bpw = sizeof(std::uintptr_t); /* round up to multiple of c_bpw, but map 0 -> 0 * (table assuming c_bpw==8) * * z%c_bpw dz * ------------ * 0 0 * 1 7 * 2 6 * .. .. * 7 1 */ std::uint32_t dz = (c_bpw - (z % c_bpw)) % c_bpw; z += dz; return dz; } static inline std::size_t with_padding(std::size_t z) { return z + alloc_padding(z); } /** optional name for this allocator; labelling for diagnostics **/ virtual const std::string & name() const = 0; /** allocator size in bytes (up to reserved limit) * Includes unallocated mmeory **/ virtual std::size_t size() const = 0; /** committed size in bytes **/ virtual std::size_t committed() const = 0; /** number of unallocated bytes available (up to soft limit) * from this allocator **/ virtual std::size_t available() const = 0; /** number of bytes allocated from this allocator **/ virtual std::size_t allocated() const = 0; /** true iff pointer x comes from this allocator **/ virtual bool contains(const void * x) const = 0; /** true iff object at address @p x was allocated by this allocator, * and before checkpoint **/ virtual bool is_before_checkpoint(const void * x) const = 0; /** number of bytes allocated before @ref checkpoint **/ virtual std::size_t before_checkpoint() const = 0; /** number of bytes allocated since @ref checkpoint **/ virtual std::size_t after_checkpoint() const = 0; /** @return true iff debug logging enabled **/ virtual bool debug_flag() const = 0; /** remember allocator state. All currently-allocated addresses xo * will satisfy is_before_checkpoint(x). Subsequent allocations x * will fail is_before_checkpoint(x), until checkpoint superseded * by @ref clear or another call to @ref checkpoint **/ virtual void checkpoint() = 0; /** allocate @p z bytes of memory. returns pointer to first address **/ virtual std::byte * alloc(std::size_t z) = 0; /** reset allocator to empty state. **/ virtual void clear() = 0; // ----- GC-specific methods ----- /** true iff this allocator owns object at address @p src. * Use to assist Object::_shallow_move **/ virtual bool check_owned(IObject * /*src*/) const { return false; } /** true iff object at address @p src must move as part of * in-progress collection phase **/ virtual bool check_move(IObject * /*src*/) const { return false; } /** write barrier for collector. perform assignment * @code * *lhs = rhs * @endcode * plus additional book keeping if needed (e.g. in @ref GC) * Default implementation just does the assignment. **/ virtual void assign_member(IObject * /*parent*/, IObject ** lhs, IObject * rhs) { *lhs = rhs; } /** allocate @p z bytes for copy of object at @p src. * Only used in @ref GC. Default implementation asserts and returns nullptr **/ virtual std::byte * alloc_gc_copy(std::size_t /*z*/, const void * /*src*/) { // LCOV_EXCL_START //assert(false); return nullptr; // LCOV_EXCL_STOP } }; } /*namespace gc*/ class MMPtr { public: explicit MMPtr(gc::IAlloc * mm) : mm_{mm} {} gc::IAlloc * mm_ = nullptr; }; } /*namespace xo*/ inline void * operator new (std::size_t z, const xo::MMPtr & mmp) { return mmp.mm_->alloc(z); } //inline void operator delete (void * p, const MMPtr & mmp) { // mmp.mm_->free(reinterpret_cast(p)); //} inline void * operator new[] (std::size_t z, const xo::MMPtr & mmp) { return mmp.mm_->alloc(z); } //inline void operator delete[] (void * p, const MMPtr & mmp) { // mmp.mm_->free(reinterpret_cast(p)); //} /* end IAlloc.hpp */