1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
|
// Copyright (C) 2015-2025 Jonathan Müller and foonathan/memory contributors
// SPDX-License-Identifier: Zlib
#ifndef FOONATHAN_MEMORY_DETAIL_MEMORY_STACK_HPP_INCLUDED
#define FOONATHAN_MEMORY_DETAIL_MEMORY_STACK_HPP_INCLUDED
#include <cstddef>
#include "../config.hpp"
#include "align.hpp"
#include "debug_helpers.hpp"
#include "../debugging.hpp"
namespace foonathan
{
namespace memory
{
namespace detail
{
// simple memory stack implementation that does not support growing
class fixed_memory_stack
{
public:
fixed_memory_stack() noexcept : fixed_memory_stack(nullptr) {}
// gives it the current pointer, the end pointer must be maintained seperataly
explicit fixed_memory_stack(void* memory) noexcept
: cur_(static_cast<char*>(memory))
{
}
fixed_memory_stack(fixed_memory_stack&& other) noexcept : cur_(other.cur_)
{
other.cur_ = nullptr;
}
~fixed_memory_stack() noexcept = default;
fixed_memory_stack& operator=(fixed_memory_stack&& other) noexcept
{
cur_ = other.cur_;
other.cur_ = nullptr;
return *this;
}
// bumps the top pointer without filling it
void bump(std::size_t offset) noexcept
{
cur_ += offset;
}
// bumps the top pointer by offset and fills
void bump(std::size_t offset, debug_magic m) noexcept
{
detail::debug_fill(cur_, offset, m);
bump(offset);
}
// same as bump(offset, m) but returns old value
void* bump_return(std::size_t offset,
debug_magic m = debug_magic::new_memory) noexcept
{
auto memory = cur_;
detail::debug_fill(memory, offset, m);
cur_ += offset;
return memory;
}
// allocates memory by advancing the stack, returns nullptr if insufficient
// debug: mark memory as new_memory, put fence in front and back
void* allocate(const char* end, std::size_t size, std::size_t alignment,
std::size_t fence_size = debug_fence_size) noexcept
{
if (cur_ == nullptr)
return nullptr;
auto remaining = std::size_t(end - cur_);
auto offset = align_offset(cur_ + fence_size, alignment);
if (fence_size + offset + size + fence_size > remaining)
return nullptr;
return allocate_unchecked(size, offset, fence_size);
}
// same as allocate() but does not check the size
// note: pass it the align OFFSET, not the alignment
void* allocate_unchecked(std::size_t size, std::size_t align_offset,
std::size_t fence_size = debug_fence_size) noexcept
{
bump(fence_size, debug_magic::fence_memory);
bump(align_offset, debug_magic::alignment_memory);
auto mem = bump_return(size);
bump(fence_size, debug_magic::fence_memory);
return mem;
}
// unwindws the stack to a certain older position
// debug: marks memory from new top to old top as freed
// doesn't check for invalid pointer
void unwind(char* top) noexcept
{
debug_fill(top, std::size_t(cur_ - top), debug_magic::freed_memory);
cur_ = top;
}
// returns the current top
char* top() const noexcept
{
return cur_;
}
private:
char* cur_;
};
} // namespace detail
} // namespace memory
} // namespace foonathan
#endif // FOONATHAN_MEMORY_DETAIL_MEMORY_STACK_HPP_INCLUDED
|