File: memory_stack.hpp

package info (click to toggle)
foonathan-memory 0.7.4-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,644 kB
  • sloc: cpp: 12,425; xml: 139; sh: 48; makefile: 25
file content (119 lines) | stat: -rw-r--r-- 4,435 bytes parent folder | download
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