38#include <gtest/gtest.h>
45#if !ALEPH_HAS_MAP_ARENA
49TEST(MapArena, NotAvailableOnThisPlatform)
52 <<
"MapArena requires Linux (mremap / MAP_POPULATE). "
53 "See ah-map-arena.H for the platform gate.";
56int main(
int argc,
char ** argv)
58 ::testing::InitGoogleTest(&argc, argv);
59 return RUN_ALL_TESTS();
65namespace fs = std::filesystem;
71class MapArenaTest :
public ::testing::Test
74 std::string test_file;
79 test_file =
"/tmp/map_arena_test_" + std::to_string(getpid()) +
".dat";
81 fs::remove(test_file);
84 void TearDown()
override
87 fs::remove(test_file);
95TEST_F(MapArenaTest, DefaultConstruction)
98 EXPECT_FALSE(arena.is_initialized());
99 EXPECT_EQ(arena.mapped_addr(),
nullptr);
100 EXPECT_EQ(arena.file_descriptor(), -1);
103TEST_F(MapArenaTest, ConstructWithFile)
105 MapArena arena(test_file);
107 EXPECT_TRUE(arena.is_initialized());
108 EXPECT_NE(arena.mapped_addr(),
nullptr);
109 EXPECT_GE(arena.file_descriptor(), 0);
110 EXPECT_EQ(arena.size(), 0u);
111 EXPECT_EQ(arena.capacity(), MapArena::initial_rgn_size);
112 EXPECT_TRUE(fs::exists(test_file));
115TEST_F(MapArenaTest, InitMethod)
118 arena.init(test_file);
120 EXPECT_TRUE(arena.is_initialized());
121 EXPECT_NE(arena.mapped_addr(),
nullptr);
122 EXPECT_EQ(arena.size(), 0u);
125TEST_F(MapArenaTest, InitAndErase)
129 MapArena arena(test_file);
130 char * ptr = arena.reserve(100);
131 ASSERT_NE(ptr,
nullptr);
132 std::memcpy(ptr,
"test data", 10);
139 arena.init_and_erase(test_file);
141 EXPECT_TRUE(arena.is_initialized());
142 EXPECT_EQ(arena.size(), 0u);
143 EXPECT_TRUE(arena.empty());
150TEST_F(MapArenaTest, MoveConstruction)
152 MapArena original(test_file);
153 char * ptr = original.reserve(50);
154 ASSERT_NE(ptr,
nullptr);
155 std::memcpy(ptr,
"hello", 6);
158 void * orig_addr = original.mapped_addr();
160 MapArena moved(std::move(original));
163 EXPECT_TRUE(moved.is_initialized());
164 EXPECT_EQ(moved.mapped_addr(), orig_addr);
165 EXPECT_EQ(moved.size(), 6u);
168 EXPECT_FALSE(original.is_initialized());
169 EXPECT_EQ(original.mapped_addr(),
nullptr);
170 EXPECT_EQ(original.file_descriptor(), -1);
173TEST_F(MapArenaTest, MoveAssignment)
175 MapArena original(test_file);
176 char * ptr = original.reserve(50);
177 ASSERT_NE(ptr,
nullptr);
178 std::memcpy(ptr,
"data", 5);
182 target = std::move(original);
184 EXPECT_TRUE(target.is_initialized());
185 EXPECT_EQ(target.size(), 5u);
186 EXPECT_FALSE(original.is_initialized());
189TEST_F(MapArenaTest, MoveAssignmentRoundtrip)
191 MapArena arena(test_file);
196 tmp = std::move(arena);
197 arena = std::move(tmp);
200 EXPECT_TRUE(arena.is_initialized());
201 EXPECT_EQ(arena.size(), 10u);
208TEST_F(MapArenaTest, BasicReserveCommit)
210 MapArena arena(test_file);
212 char * ptr = arena.reserve(100);
213 ASSERT_NE(ptr,
nullptr);
214 EXPECT_EQ(arena.size(), 0u);
217 EXPECT_EQ(arena.size(), 100u);
220TEST_F(MapArenaTest, MultipleReserveCommit)
222 MapArena arena(test_file);
224 for (
int i = 0; i < 10; ++i)
226 char * ptr = arena.reserve(50);
227 ASSERT_NE(ptr,
nullptr);
231 EXPECT_EQ(arena.size(), 500u);
234TEST_F(MapArenaTest, PartialCommit)
236 MapArena arena(test_file);
238 char * ptr = arena.reserve(1000);
239 ASSERT_NE(ptr,
nullptr);
243 EXPECT_EQ(arena.size(), 500u);
246TEST_F(MapArenaTest, ReserveWithData)
248 MapArena arena(test_file);
250 const char *
message =
"Hello, MapArena!";
251 size_t len = std::strlen(message) + 1;
253 char * ptr = arena.reserve(len);
254 ASSERT_NE(ptr,
nullptr);
256 std::memcpy(ptr, message, len);
260 EXPECT_STREQ(arena.base(), message);
263TEST_F(MapArenaTest, ReserveTriggersRemap)
265 MapArena arena(test_file);
267 size_t initial_capacity = arena.capacity();
270 char * ptr = arena.reserve(initial_capacity + 1000);
271 ASSERT_NE(ptr,
nullptr);
273 EXPECT_GT(arena.capacity(), initial_capacity);
274 arena.commit(initial_capacity + 1000);
275 EXPECT_EQ(arena.size(), initial_capacity + 1000);
278TEST_F(MapArenaTest, LargeReservation)
280 MapArena arena(test_file);
283 size_t large_size = 1024 * 1024;
284 char * ptr = arena.reserve(large_size);
285 ASSERT_NE(ptr,
nullptr);
288 std::memset(ptr,
'X', large_size);
289 arena.commit(large_size);
291 EXPECT_EQ(arena.size(), large_size);
292 EXPECT_GE(arena.capacity(), large_size);
299TEST_F(MapArenaTest, IteratorOnEmpty)
301 MapArena arena(test_file);
303 EXPECT_EQ(arena.begin(), arena.end());
306TEST_F(MapArenaTest, IteratorTraversal)
308 MapArena arena(test_file);
310 const char * data =
"ABCDEFGHIJ";
311 char * ptr = arena.reserve(10);
312 ASSERT_NE(ptr,
nullptr);
313 std::memcpy(ptr, data, 10);
318 for (
auto it = arena.begin(); it != arena.end(); ++it, ++i)
319 EXPECT_EQ(*it, data[i]);
324TEST_F(MapArenaTest, ConstIterators)
326 MapArena arena(test_file);
327 char * ptr = arena.reserve(5);
328 std::memcpy(ptr,
"test", 5);
331 const MapArena & const_arena = arena;
332 EXPECT_EQ(const_arena.end() - const_arena.begin(), 5);
335TEST_F(MapArenaTest, RangeBasedFor)
337 MapArena arena(test_file);
339 char * ptr = arena.reserve(26);
340 for (
int i = 0; i < 26; ++i)
348 EXPECT_EQ(result,
"abcdefghijklmnopqrstuvwxyz");
355TEST_F(MapArenaTest, InitialCapacity)
357 MapArena arena(test_file);
358 EXPECT_EQ(arena.capacity(), MapArena::initial_rgn_size);
361TEST_F(MapArenaTest, AvailableMemory)
363 MapArena arena(test_file);
365 EXPECT_EQ(arena.avail(), arena.capacity());
370 EXPECT_EQ(arena.avail(), arena.capacity() - 100);
373TEST_F(MapArenaTest, SizeAfterCommits)
375 MapArena arena(test_file);
377 EXPECT_EQ(arena.size(), 0u);
378 EXPECT_TRUE(arena.empty());
382 EXPECT_EQ(arena.size(), 50u);
383 EXPECT_FALSE(arena.empty());
387 EXPECT_EQ(arena.size(), 80u);
394TEST_F(MapArenaTest, DataPersistsAcrossInstances)
396 const char *
message =
"Persistent data!";
397 size_t len = std::strlen(message) + 1;
401 MapArena arena(test_file);
402 char * ptr = arena.reserve(len);
403 ASSERT_NE(ptr,
nullptr);
404 std::memcpy(ptr, message, len);
411 MapArena arena(test_file);
414 EXPECT_TRUE(arena.is_initialized());
418TEST_F(MapArenaTest, SyncMethod)
420 MapArena arena(test_file);
422 char * ptr = arena.reserve(100);
423 ASSERT_NE(ptr,
nullptr);
424 std::memset(ptr,
'A', 100);
428 EXPECT_NO_THROW(arena.sync());
435TEST_F(MapArenaTest, BaseMethod)
437 MapArena arena(test_file);
439 EXPECT_EQ(arena.base(), arena.begin());
440 EXPECT_EQ(arena.base(), arena.mapped_addr());
443TEST_F(MapArenaTest, EmptyMethod)
445 MapArena arena(test_file);
447 EXPECT_TRUE(arena.empty());
452 EXPECT_FALSE(arena.empty());
455TEST_F(MapArenaTest, IsInitializedMethod)
458 EXPECT_FALSE(arena.is_initialized());
460 arena.init(test_file);
461 EXPECT_TRUE(arena.is_initialized());
464TEST_F(MapArenaTest, FileDescriptor)
466 MapArena arena(test_file);
467 int fd = arena.file_descriptor();
472 int flags = fcntl(fd, F_GETFD);
473 EXPECT_NE(flags, -1);
480TEST_F(MapArenaTest, ZeroSizeReserve)
482 MapArena arena(test_file);
484 char * ptr = arena.reserve(0);
485 EXPECT_NE(ptr,
nullptr);
487 EXPECT_EQ(arena.size(), 0u);
490TEST_F(MapArenaTest, MultipleRemapGrowth)
492 MapArena arena(test_file);
495 size_t allocation_size = MapArena::initial_rgn_size / 2;
498 for (
int i = 0; i < 10; ++i)
500 char * ptr = arena.reserve(allocation_size);
501 ASSERT_NE(ptr,
nullptr) <<
"Failed at iteration " << i;
502 arena.commit(allocation_size);
503 total += allocation_size;
506 EXPECT_EQ(arena.size(), total);
507 EXPECT_GE(arena.capacity(), total);
514TEST_F(MapArenaTest, OutputOperator)
516 MapArena arena(test_file);
520 std::ostringstream oss;
523 std::string
output = oss.str();
524 EXPECT_NE(
output.find(
"MapArena"), std::string::npos);
525 EXPECT_NE(
output.find(
"size"), std::string::npos);
526 EXPECT_NE(
output.find(
"capacity"), std::string::npos);
533TEST_F(MapArenaTest, DestructorOnUninitialized)
540TEST_F(MapArenaTest, DestructorAfterMove)
542 MapArena arena(test_file);
543 MapArena other = std::move(arena);
551TEST_F(MapArenaTest, ManySmallAllocations)
553 MapArena arena(test_file);
555 constexpr int N = 10000;
556 for (
int i = 0; i <
N; ++i)
558 char * ptr = arena.reserve(8);
559 ASSERT_NE(ptr,
nullptr) <<
"Failed at allocation " << i;
563 EXPECT_EQ(arena.size(),
N * 8u);
566TEST_F(MapArenaTest, AlternatingAllocations)
568 MapArena arena(test_file);
571 for (
int i = 0; i < 100; ++i)
573 size_t sz = (i % 2 == 0) ? 16 : 256;
574 char * ptr = arena.reserve(sz);
575 ASSERT_NE(ptr,
nullptr);
580 EXPECT_EQ(arena.size(), total);
587TEST_F(MapArenaTest, TypeAliases)
589 static_assert(std::is_same_v<MapArena::iterator, char*>);
590 static_assert(std::is_same_v<MapArena::const_iterator, const char*>);
591 static_assert(std::is_same_v<MapArena::size_type, size_t>);
598TEST(MapArenaConstants, InitialRegionSize)
600 EXPECT_EQ(MapArena::initial_rgn_size, 4 * 1024u);
607int main(
int argc,
char ** argv)
609 ::testing::InitGoogleTest(&argc, argv);
610 return RUN_ALL_TESTS();
TEST_F(StaticArenaFixture, simple_fail)
Memory-mapped file arena allocator.
Main namespace for Aleph-w library functions.
void message(const char *file, int line, const char *format,...)
Print an informational message with file and line info.