diff --git a/xo-alloc/include/xo/alloc/ArenaAllocT.hpp b/xo-alloc/include/xo/alloc/ArenaAllocT.hpp new file mode 100644 index 00000000..6c8a9b41 --- /dev/null +++ b/xo-alloc/include/xo/alloc/ArenaAllocT.hpp @@ -0,0 +1,74 @@ +/** @file Allocator.hpp + * + * @author Roland Conybeare, Nov 2025 + **/ + +#pragma once + +#include "xo/alloc/ArenaAlloc.hpp" + +namespace xo { + namespace gc { + /** @class allocator + * @brief c++ allocator with allocator traits + * + * Can use ArenaAllocT with std::map etc. + **/ + template + class ArenaAllocT { + public: + using value_type = T; + /** copy assignment: leave lhs allocator in place **/ + using propagate_on_container_copy_assignment = std::false_type; + /** move assignment: adopt rhs allocator + * (Forced: cannot mix allocations from different allocators + * within a container) + **/ + using propagate_on_container_move_assignment = std::true_type; + /** swap: also swap allocators + * (Forced: cannot mix allocations from different allocators + * within a containers) + **/ + using propagate_on_container_swap = std::true_type; + /** An ArenaAlloc instance is unique owner of its own memory: + * no other instance can dealloc + **/ + using is_always_equal = std::false_type; + + public: + explicit ArenaAllocT(ArenaAlloc * mm) : mm_{mm} {} + ArenaAllocT(const ArenaAllocT & other) = default; + + /** rebind ctor. Allows container to use supplied allocator + * for multiple types + **/ + template + ArenaAllocT(const ArenaAllocT & other) noexcept : mm_{other.mm_} {} + + T * allocate(size_t n) { + void * mem = mm_->alloc(n * sizeof(T)); + + return reinterpret_cast(mem); + } + + void deallocate(T * p, size_t n) noexcept { + assert(mm_->contains(p)); + assert(n == 0 || mm_->contains(p + n - 1)); + + //arena_->deallocate(p, n * sizeof(T)); + } + + bool operator==(const ArenaAllocT & other) const { + return mm_ == other.mm_; + } + + bool operator!=(const ArenaAllocT & other) const { + return mm_ != other.mm_; + } + + ArenaAlloc * mm_ = nullptr; + }; + } /*namespace gc*/ +} /*namespace xo*/ + +/* end Allocator.hpp */ diff --git a/xo-alloc/utest/ArenaAllocT.test.cpp b/xo-alloc/utest/ArenaAllocT.test.cpp new file mode 100644 index 00000000..44b350be --- /dev/null +++ b/xo-alloc/utest/ArenaAllocT.test.cpp @@ -0,0 +1,65 @@ +/** @file ArenaAllocT.test.cpp + * + * @author Roland Conybeare, Nov 2025 + **/ + +#include "xo/alloc/ArenaAllocT.hpp" +#include +#include + +namespace xo { + using xo::gc::ArenaAllocT; + using xo::gc::ArenaAlloc; + + namespace ut { + + namespace { + struct testcase_ArenaAllocT { + testcase_ArenaAllocT(std::size_t z) : arena_z_{z} {} + + std::size_t arena_z_; + std::vector> kv_pairs_; + }; + + std::vector + s_testcase_v = { + testcase_ArenaAllocT(4096) + }; + } + + TEST_CASE("ArenaAllocT", "[alloc][traits]") + { + for (std::size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) { + const testcase_ArenaAllocT & tc = s_testcase_v[i_tc]; + + constexpr bool c_debug_flag = true; + + auto arena = ArenaAlloc::make("arena", tc.arena_z_, c_debug_flag); + auto alloc = ArenaAllocT>(arena.get()); + + using TestMapType = std::map, + ArenaAllocT>>; + + TestMapType test_map(alloc); + + size_t n = 0; + for (const auto & kv_ix : tc.kv_pairs_) { + test_map[kv_ix.first] = kv_ix.second; + ++n; + + REQUIRE(test_map.size() == n); + + for (const auto & map_ix : test_map) { + map_ix.first; + map_ix.second; + } + } + + } + } + } +} /*namespace xo*/ + +/* end ArenaAllocT.test.cpp */ diff --git a/xo-alloc/utest/CMakeLists.txt b/xo-alloc/utest/CMakeLists.txt index 366cf664..6c644f51 100644 --- a/xo-alloc/utest/CMakeLists.txt +++ b/xo-alloc/utest/CMakeLists.txt @@ -7,6 +7,7 @@ set(UTEST_SRCS alloc_utest_main.cpp IAlloc.test.cpp ArenaAlloc.test.cpp + ArenaAllocT.test.cpp ListAlloc.test.cpp GC.test.cpp GcStatistics.test.cpp