.. _program_listing_file_foxglove_include_foxglove_arena.hpp: Program Listing for File arena.hpp ================================== |exhale_lsh| :ref:`Return to documentation for file ` (``foxglove/include/foxglove/arena.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #pragma once #include #include #include #include #include #include #include #include #include namespace foxglove { class Arena { public: static constexpr std::size_t kSize = static_cast(8) * 1024; // 8 KB Arena() = default; template< typename T, typename S, typename Fn, typename = std::enable_if_t && std::is_invocable_v>> // NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward) T* map(const std::vector& src, Fn&& map_fn) { const size_t elements = src.size(); if (elements == 0) { return nullptr; } T* result = alloc(elements); T* current = result; // Convert the elements from S to T, placing them in the result array for (auto it = src.begin(); it != src.end(); ++it) { map_fn(*current++, *it, *this); } return result; } template< typename T, typename S, typename Fn, typename = std::enable_if_t && std::is_invocable_v>> T* mapOne(const S& src, Fn&& map_fn) { T* result = alloc(1); std::forward(map_fn)(*result, src, *this); return result; } template T* alloc(size_t elements) { assert(elements > 0); const size_t bytes_needed = elements * sizeof(T); const size_t alignment = alignof(T); // Calculate space available in the buffer size_t space_left = available(); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index) void* buffer_ptr = &buffer_[offset_]; // Align the pointer within the buffer void* aligned_ptr = std::align(alignment, bytes_needed, buffer_ptr, space_left); // Check if we have enough space if (aligned_ptr == nullptr) { // We don't use aligned_alloc because it fails on some platforms for larger alignments size_t size_with_alignment = alignment + bytes_needed; // NOLINTBEGIN(cppcoreguidelines-no-malloc,hicpp-no-malloc,cppcoreguidelines-owning-memory) auto* ptr = ::malloc(size_with_alignment); // NOLINTNEXTLINE(clang-analyzer-unix.Malloc) aligned_ptr = std::align(alignment, bytes_needed, ptr, size_with_alignment); if (aligned_ptr == nullptr) { #ifndef __wasm32__ throw std::bad_alloc(); #else std::terminate(); #endif } overflow_.emplace_back(static_cast(ptr)); // NOLINTEND(cppcoreguidelines-no-malloc,hicpp-no-malloc,cppcoreguidelines-owning-memory) return reinterpret_cast(aligned_ptr); } // Calculate the new offset offset_ = kSize - space_left + bytes_needed; return reinterpret_cast(aligned_ptr); } [[nodiscard]] size_t used() const { return offset_; } [[nodiscard]] size_t available() const { return kSize - offset_; } private: struct Deleter { void operator()(char* ptr) const { // NOLINTNEXTLINE(cppcoreguidelines-no-malloc,hicpp-no-malloc,cppcoreguidelines-owning-memory) free(ptr); } }; std::array buffer_{}; std::size_t offset_ = 0; std::vector> overflow_; }; } // namespace foxglove