.. _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 Size = 8 * 1024; // 128 KB Arena() : offset_(0) {} template< typename T, typename S, typename Fn, typename = std::enable_if_t && std::is_invocable_v>> T* map(const std::vector& src, Fn&& map_fn) { const size_t elements = src.size(); T* result = (elements > 0) ? alloc(elements) : nullptr; 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* map_one(const S& src, Fn&& map_fn) { T* result = alloc(1); 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(); 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; auto ptr = ::malloc(size_with_alignment); 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(aligned_ptr)); return reinterpret_cast(aligned_ptr); } // Calculate the new offset offset_ = Size - space_left + bytes_needed; return reinterpret_cast(aligned_ptr); } size_t used() const { return offset_; } size_t available() const { return Size - offset_; } private: struct Deleter { void operator()(char* ptr) const { free(ptr); } }; std::array buffer_; std::size_t offset_; std::vector> overflow_; }; } // namespace foxglove