summaryrefslogtreecommitdiff
path: root/src/memory/include
diff options
context:
space:
mode:
Diffstat (limited to 'src/memory/include')
-rw-r--r--src/memory/include/arena.hpp85
1 files changed, 85 insertions, 0 deletions
diff --git a/src/memory/include/arena.hpp b/src/memory/include/arena.hpp
new file mode 100644
index 00000000..26d49d27
--- /dev/null
+++ b/src/memory/include/arena.hpp
@@ -0,0 +1,85 @@
+#pragma once
+
+#include <cstdint>
+#include <optional>
+#include <utility>
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/queue.h"
+#include "span.hpp"
+#include "sys/_stdint.h"
+
+namespace memory {
+
+class Arena;
+
+/*
+ * A pointer to data that has been given out by an Arena, plus extra accounting
+ * information so that it can be returned properly.
+ */
+struct ArenaPtr {
+ Arena* owner;
+ std::byte* start;
+ std::size_t size;
+ // A convenience for keeping track of the subset of the block that has had
+ // data placed within it.
+ std::size_t used_size;
+};
+
+/*
+ * A basic memory arena. This class mediates access to fixed-size blocks of
+ * memory within a larger contiguous block. This is faster than re-allocating
+ * smaller blocks every time they're needed, and lets us easily limit the
+ * maximum size of the memory used.
+ *
+ * A single arena instance is safe to be used concurrently by multiple tasks,
+ * however there is no built in synchronisation of the underlying memory.
+ */
+class Arena {
+ public:
+ Arena(std::size_t block_size, std::size_t num_blocks, uint32_t alloc_flags);
+ ~Arena();
+
+ /*
+ * Attempts to receive an allocation from this arena. Returns absent if
+ * there are no blocks left.
+ */
+ auto Acquire() -> std::optional<ArenaPtr>;
+
+ /* Returns a previously allocated block to this arena. */
+ auto Return(ArenaPtr) -> void;
+
+ /* Returns the number of blocks that are currently free. */
+ auto BlocksFree() -> std::size_t;
+
+ Arena(const Arena&) = delete;
+ Arena& operator=(const Arena&) = delete;
+
+ private:
+ std::size_t block_size_;
+ // The large memory allocation that is divided into blocks.
+ std::byte* pool_;
+ // A FreeRTOS queue containing the blocks that are currently unused.
+ QueueHandle_t free_blocks_;
+};
+
+/*
+ * Wrapper around an ArenaPtr that handles acquiring and returning the block
+ * through RAII.
+ */
+class ArenaRef {
+ public:
+ static auto Acquire(Arena* a) -> std::optional<ArenaRef>;
+ explicit ArenaRef(ArenaPtr ptr);
+ ~ArenaRef();
+
+ auto Release() -> ArenaPtr;
+
+ ArenaRef(ArenaRef&&);
+ ArenaRef(const ArenaRef&) = delete;
+ Arena& operator=(const Arena&) = delete;
+
+ ArenaPtr ptr;
+};
+
+} // namespace memory