xo-alloc: + ArenaAllocT for use with std::map() etc.

This commit is contained in:
Roland Conybeare 2025-11-29 16:59:36 -05:00
commit 14a8814338
3 changed files with 140 additions and 0 deletions

View file

@ -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 <typename T>
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 <typename U>
ArenaAllocT(const ArenaAllocT<U> & other) noexcept : mm_{other.mm_} {}
T * allocate(size_t n) {
void * mem = mm_->alloc(n * sizeof(T));
return reinterpret_cast<T *>(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 */

View file

@ -0,0 +1,65 @@
/** @file ArenaAllocT.test.cpp
*
* @author Roland Conybeare, Nov 2025
**/
#include "xo/alloc/ArenaAllocT.hpp"
#include <catch2/catch.hpp>
#include <map>
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<std::pair<std::string, std::string>> kv_pairs_;
};
std::vector<testcase_ArenaAllocT>
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<std::pair<const std::string, std::string>>(arena.get());
using TestMapType = std::map<std::string,
std::string,
std::less<std::string>,
ArenaAllocT<std::pair<const std::string, std::string>>>;
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 */

View file

@ -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