56#include <gtest/gtest.h>
81 static bool should_throw_;
82 static int construct_count_;
83 static int destruct_count_;
88 explicit ThrowingObject(
int v) : value(v)
92 throw std::runtime_error(
"Intentional construction failure");
102 construct_count_ = 0;
104 should_throw_ =
false;
107 static void set_throw(
bool t) { should_throw_ = t; }
108 static int constructions() {
return construct_count_; }
109 static int destructions() {
return destruct_count_; }
112bool ThrowingObject::should_throw_ =
false;
113int ThrowingObject::construct_count_ = 0;
114int ThrowingObject::destruct_count_ = 0;
120 virtual ~Base() =
default;
121 virtual int get_value()
const = 0;
122 virtual std::string
get_type()
const = 0;
126class Derived1 :
public Base
130 explicit Derived1(
int v) : value_(v) {}
131 int get_value()
const override {
return value_; }
132 std::string
get_type()
const override {
return "Derived1"; }
136class Derived2 :
public Base
140 explicit Derived2(
int v) : value_(v) {}
141 int get_value()
const override {
return value_ * 2; }
142 std::string
get_type()
const override {
return "Derived2"; }
146struct alignas(64) CacheLineAligned
149 int marker = 0xDEADBEEF;
151 CacheLineAligned() =
default;
152 explicit CacheLineAligned(
int m) : marker(m) {}
159 explicit TinyObject(
char b = 0) : byte(b) {}
167 explicit MediumObject(
int i = 0) : id(i) { std::fill(data, data + 128,
static_cast<char>(i)); }
175 explicit LargeObject(
int i = 0) : id(i) { std::fill(data, data + 4096,
static_cast<char>(i)); }
180class AllocationTracker
194 AllocationTracker(
const AllocationTracker&) =
delete;
195 AllocationTracker& operator=(
const AllocationTracker&) =
delete;
200 other.ptr_ =
nullptr;
203 T* get()
const {
return ptr_; }
204 T* operator->()
const {
return ptr_; }
221 std::vector<void*>
ptrs;
227 ASSERT_NE(ptr,
nullptr) <<
"Allocation " << i <<
" failed";
245 std::mt19937
rng(42);
246 std::uniform_int_distribution<size_t>
size_dist(1, 1024);
248 std::vector<void*>
ptrs;
273 std::vector<MediumObject*>
objects;
279 ASSERT_NE(
obj,
nullptr) <<
"Object " << i <<
" allocation failed";
311 for (
int i = 0; i < 50; ++i)
321 EXPECT_GT(allocated, 50u * (16 + 1024) * 0.8);
330 std::vector<void*>
ptrs;
335 void* ptr = arena.
alloc(1000);
358 std::uniform_int_distribution<size_t>
size_dist(10, 500);
376 void* ptr = arena.
alloc(1000);
386 ThrowingObject::reset_counters();
387 ThrowingObject::set_throw(
true);
391 ThrowingObject*
obj =
nullptr;
398 EXPECT_EQ(ThrowingObject::constructions(), 1);
399 EXPECT_EQ(ThrowingObject::destructions(), 0);
402 ThrowingObject::set_throw(
false);
410 ThrowingObject::reset_counters();
415 std::vector<ThrowingObject*>
objs;
416 for (
int i = 0; i < 5; ++i)
423 EXPECT_EQ(ThrowingObject::constructions(), 5);
426 ThrowingObject::set_throw(
true);
433 for (
size_t i = 0; i <
objs.
size(); ++i)
437 ThrowingObject::set_throw(
false);
438 for (
auto it =
objs.rbegin(); it !=
objs.rend(); ++it)
452 for (
int i = 0; i < 10; ++i)
478 if ((*it)->get_type() ==
"Derived1")
494 : name(std::move(n)),
numbers(std::move(
nums)), id(i)
500 std::vector<ComplexObject*>
objects;
502 for (
int i = 0; i < 100; ++i)
504 std::string name =
"Object_" + std::to_string(i);
505 std::vector<int>
nums(i % 10 + 1, i);
533 std::vector<CacheLineAligned*>
objects;
535 for (
int i = 0; i < 50; ++i)
540 <<
"Object " << i <<
" not 64-byte aligned";
554 struct Align4 {
alignas(4)
char data[4]; };
555 struct Align8 {
alignas(8)
char data[8]; };
556 struct Align16 {
alignas(16)
char data[16]; };
557 struct Align32 {
alignas(32)
char data[32]; };
602 const size_t SIZE = 1000;
606 void* p1 = arena.
alloc(400);
607 void* p2 = arena.
alloc(300);
608 void* p3 = arena.
alloc(300);
619 void* p4 = arena.
alloc(1);
625 const size_t SIZE = 100;
628 std::vector<void*>
ptrs;
630 for (
size_t i = 0; i <
SIZE; ++i)
632 void* ptr = arena.
alloc(1);
633 ASSERT_NE(ptr,
nullptr) <<
"Byte " << i <<
" failed";
640 for (
size_t i = 1; i <
ptrs.
size(); ++i)
643 static_cast<char*
>(
ptrs[i]),
644 static_cast<char*
>(
ptrs[i-1]) + 1
651 const size_t SIZE = 100;
655 void* p1 = arena.
alloc(90);
690 std::vector<Level> stack;
695 for (
int i = 0; i < 100; ++i)
698 const size_t size =
static_cast<size_t>(i + 1) * 10;
708 while (!stack.empty())
710 Level level = stack.back();
714 arena.
dealloc(level.ptr, level.actual_size);
732 for (
int i = 0; i < 50; ++i)
770 auto start = std::chrono::high_resolution_clock::now();
772 std::vector<MediumObject*>
objects;
778 auto end = std::chrono::high_resolution_clock::now();
779 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
791 std::cout <<
" [Allocated " <<
NUM_OBJECTS <<
" objects in "
792 <<
duration.count() <<
"ms]" << std::endl;
801 auto start = std::chrono::high_resolution_clock::now();
811 auto end = std::chrono::high_resolution_clock::now();
812 auto malloc_duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
815 start = std::chrono::high_resolution_clock::now();
823 end = std::chrono::high_resolution_clock::now();
824 auto arena_duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
844 std::mt19937
rng(12345);
845 std::uniform_int_distribution<size_t>
size_dist(1, 1000);
857 for (
int op = 0; op < 1000; ++op)
902 const size_t MAX = std::numeric_limits<size_t>::max();
911 ptr = arena.
alloc(100);
936 const char buffer[1024] = {};
944 void* ptr = arena.
alloc(100);
958 void* ptr = arena.
alloc(1);
972 std::vector<ASTNode*> children;
975 ASTNode(std::string t,
int line)
976 :
token(std::move(t)), line_number(line)
983 std::vector<ASTNode*> all_nodes;
986 for (
int i = 0; i < 500; ++i)
990 all_nodes.push_back(node);
993 if (i > 0 && i % 10 == 0)
995 for (
int j = 0; j < 3 && !all_nodes.empty(); ++j)
996 node->children.push_back(all_nodes[all_nodes.size() - j - 1]);
1002 for (
ASTNode* node : all_nodes)
1006 if (!node->children.empty())
1013 for (
auto it = all_nodes.rbegin(); it != all_nodes.rend(); ++it)
1021 ::testing::InitGoogleTest(&
argc,
argv);
Memory arena for fast bulk allocations.
Arena allocator for fast bump-pointer allocation.
bool is_valid() const noexcept
Returns true if the arena is valid (has memory).
void * alloc(const size_t size) noexcept
Allocate raw memory from the arena.
void * alloc_aligned(const size_t size, const size_t alignment) noexcept
Allocate aligned memory from the arena.
void reset() noexcept
Reset arena, making all memory available again.
void dealloc(const void *addr, const size_t size) noexcept
Deallocate memory (only effective for LIFO pattern).
bool owns_memory() const noexcept
Returns true if the arena owns its memory.
size_t capacity() const noexcept
Get total arena capacity.
size_t allocated_size() const noexcept
Get total bytes currently allocated.
bool full() const noexcept
Returns true if the arena is full (no space left).
bool empty() const noexcept
Returns true if the arena is empty (no allocations).
size_t available_size() const noexcept
Get remaining bytes available.
void empty() noexcept
empty the list
size_t size() const noexcept
Count the number of elements of the list.
iterator end() noexcept
Return an STL-compatible end iterator.
iterator begin() noexcept
Return an STL-compatible iterator to the first element.
Main namespace for Aleph-w library functions.
size_t size(Node *root) noexcept
std::decay_t< typename HeadC::Item_Type > T
Matrix< Trow, Tcol, NumType > operator*(const NumType &scalar, const Matrix< Trow, Tcol, NumType > &m)
Scalar-matrix multiplication (scalar * matrix).
void deallocate(AhArenaAllocator &arena, T *ptr) noexcept
Destruct and deallocate an object from an arena.
DynList< T > maps(const C &c, Op op)
Classic map operation.