diff --git a/app/gui/application.hpp b/app/gui/application.hpp index be31aae7..1bc4e77e 100644 --- a/app/gui/application.hpp +++ b/app/gui/application.hpp @@ -739,8 +739,9 @@ struct project_editor { ImVector selected_nodes; /** Number of column in the tree node observation. */ - constrained_value tree_node_observation = 1; - float tree_node_observation_height = 200.f; + using tree_node_observation_t = constrained_value; + tree_node_observation_t tree_node_observation{ 1 }; + float tree_node_observation_height = 200.f; //! Position of each node int automatic_layout_iteration = 0; diff --git a/app/gui/component-selector.cpp b/app/gui/component-selector.cpp index b9d149cf..8edd181b 100644 --- a/app/gui/component-selector.cpp +++ b/app/gui/component-selector.cpp @@ -155,7 +155,7 @@ bool component_selector::combobox(const char* label, if (std::shared_lock lock(m_mutex, std::try_to_lock); lock.owns_lock()) { const auto& app = container_of(this, &application::component_sel); - small_string<254> selected_name = "undefined"; + small_string<254> selected_name("undefined"); cs_select(app.mod, *new_selected, selected_name); @@ -194,7 +194,7 @@ bool component_selector::combobox(const char* label, if (std::shared_lock lock(m_mutex, std::try_to_lock); lock.owns_lock()) { const auto& app = container_of(this, &application::component_sel); - small_string<254> selected_name = "undefined"; + small_string<254> selected_name("undefined"); cs_select(app.mod, *new_selected, selected_name); @@ -242,7 +242,7 @@ bool component_selector::menu(const char* label, if (std::shared_lock lock(m_mutex, std::try_to_lock); lock.owns_lock()) { if (ImGui::BeginMenu(label)) { const auto& app = container_of(this, &application::component_sel); - small_string<254> selected_name = "undefined"; + small_string<254> selected_name("undefined"); cs_select(app.mod, *new_selected, selected_name); diff --git a/app/gui/project-editor.cpp b/app/gui/project-editor.cpp index a1a21987..e421f09b 100644 --- a/app/gui/project-editor.cpp +++ b/app/gui/project-editor.cpp @@ -904,16 +904,20 @@ static void show_component_observations_actions(project_editor& sim_ed) noexcept ImGui::TextUnformatted("Column: "); ImGui::SameLine(); if (ImGui::Button("1")) - sim_ed.tree_node_observation = 1; + sim_ed.tree_node_observation = + project_editor::tree_node_observation_t(1); ImGui::SameLine(); if (ImGui::Button("2")) - sim_ed.tree_node_observation = 2; + sim_ed.tree_node_observation = + project_editor::tree_node_observation_t(2); ImGui::SameLine(); if (ImGui::Button("3")) - sim_ed.tree_node_observation = 3; + sim_ed.tree_node_observation = + project_editor::tree_node_observation_t(3); ImGui::SameLine(); if (ImGui::Button("4")) - sim_ed.tree_node_observation = 4; + sim_ed.tree_node_observation = + project_editor::tree_node_observation_t(4); ImGui::SameLine(); ImGui::TextUnformatted("Height in pixel: "); diff --git a/app/gui/window-logger.cpp b/app/gui/window-logger.cpp index f7a6efe9..549e8fc4 100644 --- a/app/gui/window-logger.cpp +++ b/app/gui/window-logger.cpp @@ -4,8 +4,6 @@ #include "application.hpp" #include "imgui.h" -#include "internal.hpp" -#include "irritator/core.hpp" namespace irt { @@ -22,7 +20,7 @@ auto window_logger::enqueue() noexcept -> window_logger::string_t& if (entries.full()) entries.pop_head(); - entries.push_tail(""); + entries.push_tail(small_string("")); return entries.back(); } diff --git a/app/src/main.cpp b/app/src/main.cpp index 0e74312c..d2b18f37 100644 --- a/app/src/main.cpp +++ b/app/src/main.cpp @@ -191,9 +191,8 @@ static constexpr const option* get_from_long( class main_parameters { - irt::sz memory = default_memory_size; - irt::simulation_memory_requirement smr{ default_memory_size }; - irt::simulation sim; + irt::sz memory = 1024 * 1024 * 8; + irt::simulation sim; irt::modeling_initializer init; irt::modeling mod; @@ -208,8 +207,8 @@ class main_parameters public: main_parameters(int ac, const char* av[]) - : smr{ 1024 * 1024 * 8 } - , sim{ smr } + : sim(irt::simulation_memory_requirement(1024 * 1024 * 8), + irt::external_source_memory_requirement(8, 8, 8, 8, 256, 256)) , args{ av + 1, static_cast(ac - 1) } , r{ 0.0 } { @@ -516,10 +515,9 @@ class main_parameters bool read_memory() noexcept { if (parse_integer() and u > memory) { - memory = u; - irt::simulation_memory_requirement smr_two{ u }; - std::swap(smr, smr_two); - sim.realloc(smr); + sim.realloc(irt::simulation_memory_requirement(memory), + irt::external_source_memory_requirement( + 16, 16, 16, 16, 256, 256)); memory = u; return true; } diff --git a/lib/include/irritator/container.hpp b/lib/include/irritator/container.hpp index 4baec1b7..72d41004 100644 --- a/lib/include/irritator/container.hpp +++ b/lib/include/irritator/container.hpp @@ -12,8 +12,8 @@ #include #include #include +#include #include -#include #include #include @@ -95,9 +95,9 @@ inline constexpr auto left(std::unsigned_integral auto v) noexcept if constexpr (std::is_same_v) return static_cast(v >> 8); - if constexpr (std::is_same_v) + else if constexpr (std::is_same_v) return static_cast(v >> 16); - if constexpr (std::is_same_v) + else return static_cast(v >> 32); } @@ -110,17 +110,19 @@ inline constexpr auto right(std::unsigned_integral auto v) noexcept if constexpr (std::is_same_v) return static_cast(v & 0xff); - if constexpr (std::is_same_v) + else if constexpr (std::is_same_v) return static_cast(v & 0xffff); - if constexpr (std::is_same_v) + else return static_cast(v & 0xffffffff); } -//! Compute the best size to fit the small storage size. -//! -//! This function is used into @c small_string, @c small_vector and @c -//! small_ring_buffer to determine the @c capacity and/or @c size type -//! (unsigned, short unsigned, long unsigned, long long unsigned. +/** + Compute the best size to fit the small storage size. + + This function is used into @c small_string, @c small_vector and @c + small_ring_buffer to determine the @c capacity and/or @c size type + (unsigned, short unsigned, long unsigned, long long unsigned. +*/ template using small_storage_size_t = std::conditional_t< (N < std::numeric_limits::max()), @@ -136,680 +138,387 @@ using small_storage_size_t = std::conditional_t< size_t>>>>; template -constexpr std::ptrdiff_t offset_of(const M T::* member) +constexpr std::ptrdiff_t offset_of(const M T::*member) { return reinterpret_cast( &(reinterpret_cast(0)->*member)); } -//! A helper function to get a pointer to the parent container from a member. -//! @code -//! struct point { float x; float y; }; -//! struct line { point p1, p2; }; -//! ... -//! line l; -//! .. -//! -//! void fn(point& p) { -//! line& ptr = container_of(&p, &line::p1); -//! ... -//! } -//! @endcode +/** + A helper function to get a pointer to the parent container from a member: + + @code + struct point { float x; float y; }; + struct line { point p1, p2; }; + line l; + + void fn(point& p) { + line& ptr = container_of(&p, &line::p1); + ... + } + @endcode +*/ template -constexpr T& container_of(M* ptr, const M T::* member) noexcept +constexpr T& container_of(M* ptr, const M T::*member) noexcept { return *reinterpret_cast(reinterpret_cast(ptr) - offset_of(member)); } +/** + A helper function to get a constant pointer to the parent container from a + member: + + @code + struct point { float x; float y; }; + struct line { point p1, p2; }; + line l; + + void fn(const point& p) { + const line& ptr = container_of(&p, &line::p1); + ... + } + @endcode +*/ template -constexpr const T& container_of(const M* ptr, const M T::* member) noexcept +constexpr const T& container_of(const M* ptr, const M T::*member) noexcept { return *reinterpret_cast(reinterpret_cast(ptr) - offset_of(member)); } -//////////////////////////////////////////////////////////////////////// -// // -// Allocator: default menory_resource or specific................... // -// // -//////////////////////////////////////////////////////////////////////// - -class memory_resource +class new_delete_memory_resource { public: - memory_resource() noexcept = default; - virtual ~memory_resource() noexcept = default; - - [[gnu::malloc]] void* allocate( - std::size_t bytes, - std::size_t alignment = alignof(std::max_align_t)) noexcept - { - debug::ensure(bytes > 0); - debug::ensure(bytes % alignment == 0); - - return do_allocate(bytes, alignment); - } - - void deallocate(void* pointer, - std::size_t bytes, - std::size_t alignment = alignof(std::max_align_t)) noexcept + class data { - debug::ensure(bytes > 0u); + private: + std::size_t allocated = 0; + std::size_t deallocated = 0; - if (pointer) - do_deallocate(pointer, bytes, alignment); - } + public: + void* allocate(std::size_t bytes, + std::size_t alignment = alignof(std::max_align_t)) + { + if constexpr (debug::enable_memory_log == true and + debug::enable_ensure == true) { + return debug_allocate(bytes, alignment); + } else { + allocated += bytes; + return std::pmr::new_delete_resource()->allocate(bytes, + alignment); + } + } - bool can_alloc( - std::size_t bytes, - std::size_t alignment = alignof(std::max_align_t)) const noexcept - { - return do_can_alloc(bytes, alignment); - } + void deallocate( + void* p, + std::size_t bytes, + std::size_t alignment = alignof(std::max_align_t)) noexcept + { + if constexpr (debug::enable_memory_log == true and + debug::enable_ensure == true) { + debug_deallocate(p, bytes, alignment); + } else { + deallocated += bytes; + return std::pmr::new_delete_resource()->deallocate( + p, bytes, alignment); + } + } -protected: - virtual void* do_allocate(std::size_t bytes, - std::size_t alignment) noexcept = 0; + void release() noexcept {} - virtual void do_deallocate(void* pointer, + private: + void* debug_allocate(std::size_t bytes, std::size_t alignment) noexcept; + void debug_deallocate(void* p, std::size_t bytes, - std::size_t alignment) noexcept = 0; - - virtual bool do_can_alloc(std::size_t bytes, - std::size_t alignment) const noexcept = 0; -}; - -//! A dynamic heap `memory_resource` using `std::aligned_alloc` or -//! `std::align_memory` to allocate aligned memory . -//! -//! @note `malloc_memory_resource` is the default `memory_resource` provides by -//! the global function `get_malloc_memory_resource()`. -class malloc_memory_resource final : public memory_resource -{ -public: - malloc_memory_resource() noexcept = default; - ~malloc_memory_resource() noexcept = default; - -protected: - void* do_allocate(std::size_t bytes, - std::size_t alignment) noexcept override; - - void do_deallocate(void* pointer, - std::size_t bytes, - std::size_t alignment) noexcept override; + std::size_t alignment) noexcept; + }; - bool do_can_alloc(std::size_t /*bytes*/, - std::size_t /*alignment*/) const noexcept override + static data& instance() noexcept { - return true; + static data d; + return d; } }; -//! A stack `memory_resource` using an `std::array` to store aligned memory. -//! -//! @note `static_memory_resource` mainly used in unit tests. -template -class static_memory_resource final : public memory_resource +template +class synchronized_pool_resource { -private: - alignas(std::max_align_t) std::byte buffer[Bytes]; - std::size_t position{}; - public: - static_memory_resource() noexcept = default; - - ~static_memory_resource() noexcept = default; + class data + { + private: + std::pmr::synchronized_pool_resource mr{ std::pmr::pool_options{ + max_blocks_per_chunk, + largest_required_pool_block } }; - std::size_t capacity() const noexcept { return std::size(buffer); } + std::size_t allocated = 0; + std::size_t deallocated = 0; - void reset() noexcept { position = 0; } + public: + void* allocate(std::size_t bytes, + std::size_t alignment = alignof(std::max_align_t)) + { + allocated += bytes; + return mr.allocate(bytes, alignment); + } -protected: - void* do_allocate(std::size_t bytes, - std::size_t alignment) noexcept override - { - debug::mem_log("static_memory_resource<", - Bytes, - ">::need - allocate[", - bytes, - " ", - alignment, - "]\n"); - - debug::ensure(bytes > 0); - debug::ensure((bytes % alignment) == 0); - - if (Bytes < (position + bytes)) { - debug::log("Irritator shutdown: Unable to allocate memory ", - bytes, - " alignment ", - alignment, - "\n"); - std::abort(); + void deallocate( + void* p, + std::size_t bytes, + std::size_t alignment = alignof(std::max_align_t)) noexcept + { + deallocated += bytes; + return mr.deallocate(p, bytes, alignment); } - const auto old_position = position; - position += bytes; - auto* p = static_cast(std::data(buffer) + old_position); - - debug::mem_log("static_memory_resource<", - Bytes, - ">::allocate[", - p, - " ", - bytes, - " ", - alignment, - "]\n"); - - return p; - } + void release() noexcept {} - void do_deallocate([[maybe_unused]] void* pointer, - [[maybe_unused]] std::size_t bytes, - [[maybe_unused]] std::size_t alignment) noexcept override - { - debug::mem_log("static_memory_resource<", - Bytes, - ">::do_deallocate[", - pointer, - " ", - bytes, - " ", - alignment, - "]\n"); - - [[maybe_unused]] const auto pos = - reinterpret_cast(pointer); - [[maybe_unused]] const auto first = - reinterpret_cast(std::data(buffer)); - [[maybe_unused]] const auto last = reinterpret_cast( - std::data(buffer) + std::size(buffer)); - - debug::ensure(first <= pos and pos <= last); - } + private: + void* debug_allocate(std::size_t bytes, std::size_t alignment) noexcept; + void debug_deallocate(void* p, + std::size_t bytes, + std::size_t alignment) noexcept; + }; - bool do_can_alloc(std::size_t bytes, - std::size_t /*alignment*/) const noexcept override + static data& instance() noexcept { - return bytes < Bytes; + static data d; + return d; } }; -inline malloc_memory_resource* get_malloc_memory_resource() noexcept -{ - static malloc_memory_resource mem; - - return &mem; -} - -//! @brief A wrapper to the @c std::aligned_alloc and @c std::free cstdlib -//! function to (de)allocate memory. -//! -//! This allocator is @c std::is_empty and use the default memory resource. Use -//! this allocator in container to ensure allocator does not have size. -class default_allocator +template +class unsynchronized_pool_resource { public: - using size_type = std::size_t; - using difference_type = std::ptrdiff_t; - using memory_resource_t = void; - - template - T* allocate(size_type n) noexcept - { - const auto bytes = sizeof(T) * n; - const auto alignment = alignof(T); - - debug::ensure(bytes > 0); - debug::ensure((bytes % alignment) == 0); - - return reinterpret_cast( - get_malloc_memory_resource()->allocate(bytes, alignment)); - } - - template - void deallocate(T* p, size_type n) noexcept + class data { - debug::ensure(p); - debug::ensure(n > 0); - - get_malloc_memory_resource()->deallocate(p, n); - } -}; - -//! @brief Use a @c irt::memory_resource in member to (de)allocate memory. -//! -//! Use this allocator and a @c irt::memory_resource_t to (de)allocate memory in -//! container. -template -class mr_allocator -{ -public: - using memory_resource_t = MR; - using size_type = std::size_t; - using difference_type = std::ptrdiff_t; - -private: - memory_resource_t* m_mr; - -public: - mr_allocator() noexcept = default; - - mr_allocator(memory_resource_t* mr) noexcept - : m_mr(mr) - {} + private: + std::pmr::unsynchronized_pool_resource mr{ std::pmr::pool_options{ + max_blocks_per_chunk, + largest_required_pool_block } }; - template - T* allocate(size_type n) noexcept - { - return static_cast(m_mr->allocate(sizeof(T) * n, alignof(T))); - } + std::size_t allocated = 0; + std::size_t deallocated = 0; - template - void deallocate(T* p, size_type n) noexcept - { - m_mr->deallocate(p, sizeof(T) * n, alignof(T)); - } + public: + void* allocate(std::size_t bytes, + std::size_t alignment = alignof(std::max_align_t)) + { + allocated += bytes; + return mr.allocate(bytes, alignment); + } - std::byte* allocate_bytes( - size_type bytes, - size_type alignment = alignof(std::max_align_t)) noexcept - { - return static_cast( - m_mr->allocate(sizeof(std::byte) * bytes, alignment)); - } + void deallocate( + void* p, + std::size_t bytes, + std::size_t alignment = alignof(std::max_align_t)) noexcept + { + deallocated += bytes; + return mr.deallocate(p, bytes, alignment); + } - void deallocate_bytes( - std::byte* pointer, - size_type bytes, - size_type alignment = alignof(std::max_align_t)) noexcept - { - m_mr->deallocate(pointer, bytes, alignment); - } + void release() noexcept {} - bool can_alloc_bytes( - size_type bytes, - size_type alignment = alignof(std::max_align_t)) noexcept - { - return m_mr->can_alloc(bytes, alignment); - } + private: + void* debug_allocate(std::size_t bytes, std::size_t alignment) noexcept; + void debug_deallocate(void* p, + std::size_t bytes, + std::size_t alignment) noexcept; + }; - template - bool can_alloc(std::size_t element_count) const noexcept + static data& instance() noexcept { - return m_mr->can_alloc(sizeof(T) * element_count, alignof(T)); + static data d; + return d; } }; -//////////////////////////////////////////////////////////////////////// -// // -// Memory resource: linear, stack, stack-list........................ // -// // -//////////////////////////////////////////////////////////////////////// - -//! Return the smallest closest value of `v` divisible by `alignment`. -//! -//! ~~~{.cpp} -//! assert(make_divisible_to(123, 16) == 112); -//! assert(make_divisible_to(17, 16) == 16); -//! assert(make_divisible_to(161, 16) == 160); -//! assert(make_divisible_to(7, 16) == 0); -//! assert(make_divisible_to(15, 16) == 0); -//! assert(make_divisible_to(123, 8) == 120); -//! assert(make_divisible_to(17, 8) == 16); -//! assert(make_divisible_to(161, 8) == 160); -//! assert(make_divisible_to(7, 8) == 0); -//! assert(make_divisible_to(15, 8) == 8); -//! ~~~ -inline constexpr auto make_divisible_to( - const std::integral auto v, - const std::size_t alignment = alignof(std::max_align_t)) noexcept - -> decltype(v) -{ - using return_type = decltype(v); - - if constexpr (std::is_signed_v) - return static_cast( - static_cast(v) & - static_cast(~(alignment - 1))); - else - return static_cast(static_cast(v) & - ~(alignment - 1)); -} - -inline constexpr auto calculate_padding(const std::uintptr_t address, - const std::size_t alignment) noexcept - -> std::size_t -{ - const auto multiplier = (address / alignment) + 1u; - const auto aligned_address = multiplier * alignment; - const auto padding = aligned_address - address; - - return static_cast(padding); -} - -inline constexpr auto calculate_padding_with_header( - const std::uintptr_t address, - const std::size_t alignment, - const std::size_t header_size) noexcept -> std::size_t -{ - auto padding = calculate_padding(address, alignment); - auto needed_space = header_size; - - if (padding < needed_space) { - needed_space -= padding; - - if (needed_space % alignment > 0) { - padding += alignment * (1 + (needed_space / alignment)); - } else { - padding += alignment * (needed_space / alignment); - } - } - - return padding; -} - -//! A non-thread-safe allocator: allocation are linear, no de-allocation. -//! -//! This is a non-thread-safe, fast, special-purpose resource that gets -//! memory from a preallocated buffer, but doesn’t release it with -//! deallocation. It can only grow. The main idea is to keep a pointer at the -//! first memory address of your memory chunk and move it every time an -//! allocation is done. In this memory resource, the internal fragmentation is -//! kept to a minimum because all elements are sequentially (spatial locality) -//! inserted and the only fragmentation between them is the alignment. Due to -//! its simplicity, this allocator doesn't allow specific positions of memory to -//! be freed. Usually, all memory is freed together. -class fixed_linear_memory_resource +template +class monotonic_small_buffer { public: - static constexpr bool is_relocatable = false; - - fixed_linear_memory_resource() noexcept = default; - fixed_linear_memory_resource(std::byte* data, std::size_t size) noexcept; + static inline constexpr std::size_t size = Length; + static inline constexpr int id = ID; - void* allocate(size_t bytes, size_t alignment) noexcept; - void deallocate(void* /*p*/, - size_t /*bytes*/, - size_t /*alignment*/) noexcept - {} + static_assert(Length > 0); - /** Release memory provides in contructor or in release memory. */ - void destroy() noexcept; - - //! @brief Reset the use of the chunk of memory. - void reset() noexcept; - - //! @brief Assign a chunk of memory. - //! - //! @attention Use this function only when no chunk of memory are allocated - //! (ie the default constructor was called). - //! @param data The new buffer. Must be not null. - //! @param size The size of the buffer. Must be not null. - void reset(std::byte* data, std::size_t size) noexcept; - - //! Check if the resource can allocate @c bytes with @c alignment. - //! - //! @attention Use this function before using @c do_allocate to be sure - //! the @c memory_resource can allocate enough memory bcause @c - //! do_allocate will use @c std::quick_exit or @c std::terminate to stop - //! the application. - bool can_alloc(std::size_t bytes, std::size_t alignment) noexcept; - - std::byte* head() noexcept { return m_start; } - -private: - std::byte* m_start{}; - std::size_t m_total_size{}; - std::size_t m_offset{}; -}; + class data + { + private: + std::array buffer; -//! A non-thread-safe allocator: node specific memory resource. -//! -//! This pool allocator splits the big memory chunk in smaller chunks of the -//! same size and keeps track of which of them are free. When an allocation is -//! requested it returns the free chunk size. When a freed is done, it just -//! stores it to be used in the next allocation. This way, allocations work -//! super fast and the fragmentation is still very low. -class pool_memory_resource -{ -private: - template - struct list { - struct node { - T data; - node* next; + std::pmr::monotonic_buffer_resource mr{ + buffer.data(), + buffer.size(), + std::pmr::new_delete_resource() }; - node* head = {}; - - list() noexcept = default; + std::size_t allocated = 0; + std::size_t deallocated = 0; - void push(node* new_node) noexcept + public: + void* allocate(std::size_t bytes, + std::size_t alignment = alignof(std::max_align_t)) { - new_node->next = head; - head = new_node; + allocated += bytes; + return mr.allocate(bytes, alignment); } - node* pop() noexcept + void deallocate( + void* p, + std::size_t bytes, + std::size_t alignment = alignof(std::max_align_t)) noexcept { - node* top = head; - head = head->next; - return top; - } - }; - - struct header {}; - - using node = list
::node; - - list
m_free_list; - - std::byte* m_start_ptr = nullptr; - std::size_t m_total_size = {}; - std::size_t m_chunk_size = {}; - std::size_t m_total_allocated = {}; + deallocated += bytes; -public: - pool_memory_resource() noexcept = default; - - pool_memory_resource(std::byte* data, - std::size_t size, - std::size_t chunk_size) noexcept; - - void* allocate(size_t bytes, size_t /*alignment*/) noexcept; - - void deallocate(void* p, size_t /*bytes*/, size_t /*alignment*/) noexcept; + return mr.deallocate(p, bytes, alignment); + } - //! @brief Reset the use of the chunk of memory. - void reset() noexcept; + void release() noexcept { mr.release(); } - //! @brief Assign a chunk of memory. - //! - //! @attention Use this function only when no chunk of memory are allocated - //! (ie the default constructor was called). - //! @param data The new buffer. Must be not null. - //! @param size The size of the buffer. Must be not null. - //! @param chunk_size The size of the chun - void reset(std::byte* data, - std::size_t size, - std::size_t chunk_size) noexcept; - - //! Check if the resource can allocate @c bytes with @c alignment. - //! - //! @attention Use this function before using @c do_allocate to be sure - //! the @c memory_resource can allocate enough memory bcause @c - //! do_allocate will use @c std::quick_exit or @c std::terminate to stop - //! the application. - bool can_alloc(std::size_t bytes, std::size_t /*alignment*/) noexcept; + private: + void* debug_allocate(std::size_t bytes, std::size_t alignment) noexcept; + void debug_deallocate(void* p, + std::size_t bytes, + std::size_t alignment) noexcept; + }; - constexpr std::byte* head() noexcept; + static data& instance() noexcept + { + static data d; + return d; + } }; -//! A non-thread-safe allocator: a general purpose allocator. -//! -//! This memory resource doesn't impose any restriction. It allows -//! allocations and deallocations to be done in any order. For this reason, -//! its performance is not as good as its predecessors. -class freelist_memory_resource +template +class monotonic_buffer { public: - enum class find_policy { find_first, find_best }; - -private: - struct FreeHeader { - std::size_t block_size; - }; - - struct AllocationHeader { - std::size_t block_size; - std::uint8_t padding; - }; + static inline constexpr int id = ID; - template - class list + class data { - public: - struct node { - T data; - node* next; + private: + std::pmr::monotonic_buffer_resource mr{ + std::pmr::new_delete_resource() }; - node* head = nullptr; + std::size_t allocated = 0; + std::size_t deallocated = 0; - list() noexcept = default; - - void insert(node* previous, node* new_node) noexcept + public: + void* allocate(std::size_t bytes, + std::size_t alignment = alignof(std::max_align_t)) { - if (previous == nullptr) { - if (head != nullptr) { - new_node->next = head; - } else { - new_node->next = nullptr; - } - head = new_node; - } else { - if (previous->next == nullptr) { - previous->next = new_node; - new_node->next = nullptr; - } else { - new_node->next = previous->next; - previous->next = new_node; - } - } + allocated += bytes; + return mr.allocate(bytes, alignment); } - void remove(node* previous, node* to_delete) noexcept + void deallocate( + void* p, + std::size_t bytes, + std::size_t alignment = alignof(std::max_align_t)) noexcept { - if (previous == nullptr) { - if (to_delete->next == nullptr) { - head = nullptr; - } else { - head = to_delete->next; - } - } else { - previous->next = to_delete->next; - } - } - }; - - using node = list::node; + deallocated += bytes; - static constexpr auto allocation_header_size = sizeof(AllocationHeader); - static constexpr auto free_header_size = sizeof(FreeHeader); + return mr.deallocate(p, bytes, alignment); + } - list m_freeList; - std::byte* m_start_ptr = nullptr; - std::size_t m_total_size = 0; - std::size_t m_used = 0; - std::size_t m_peak = 0; - find_policy m_find_policy = find_policy::find_first; + void release() noexcept { mr.release(); } - struct find_t { - node* previous = nullptr; - node* allocated = nullptr; - std::size_t padding = 0u; + private: + void* debug_allocate(std::size_t bytes, std::size_t alignment) noexcept; + void debug_deallocate(void* p, + std::size_t bytes, + std::size_t alignment) noexcept; }; -public: - freelist_memory_resource() noexcept = default; - - freelist_memory_resource(std::byte* data, std::size_t size) noexcept; - - void* allocate(size_t size, size_t alignment) noexcept; - - void deallocate(void* ptr, size_t /*bytes*/, size_t /*alignment*/) noexcept; - - /** Release memory provides in contructor or in release memory. */ - void destroy() noexcept; + static data& instance() noexcept + { + static data d; + return d; + } +}; - /** Reset the use of the chunk of memory. If the chunk is undefined do - * nothing. - * @attention Release of all memory of container/memory_resource using old - * chunk. */ - void reset() noexcept; - - /** Assign a new chunk of memory to the memory resource. If the new chunk is - * undefined do nothing. - * @attention Release of all memory of container/memory_resource using old - * chunk. - * @param data The new buffer. Must be not null. - * @param size The size of the buffer. Must be not null. - */ - void reset(std::byte* data, std::size_t size) noexcept; - - //! Get the pointer to the allocated memory provided in `constructor` or in - //! `reset` functions. - //! - //! @return Can return `nullptr` or a valid pointer. - constexpr std::byte* head() const noexcept { return m_start_ptr; } +/** + A stateless allocator class to wrap static memory resource. + + @verbatim + +----------+ + |new-delete| + +----^-----+ + +-----------+ +---------+ | + |vector+------->|allocator+--------+ + +-----------+ static +---------+ static | + +----v-----+ + |fixed-size| + +----------+ + @endverbatim + + Enable the @c IRRITATOR_ENABLE_DEBUG preprocessor variable to enable a debug + for all allocation/deallocation for each memory resource. + */ +template +struct allocator { + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using memory_resource_type = MemoryResource; + + static void* allocate(std::size_t bytes, + std::size_t alignment = alignof(std::max_align_t)) + { + debug::ensure(bytes != 0); - //! Get the size of the allocated memory provided in `constructor` or in - //! `reset` functions. - //! - //! @return Can return `0` or a valid size. - constexpr std::size_t capacity() const noexcept { return m_total_size; } + return memory_resource_type::instance().allocate(bytes, alignment); + } -private: - void merge(node* previous, node* free_node) noexcept; + static void deallocate( + void* p, + std::size_t bytes, + std::size_t alignment = alignof(std::max_align_t)) noexcept + { + debug::ensure((p != nullptr and bytes > 0) or + (p == nullptr and bytes == 0)); - auto find_best(const std::size_t size, - const std::size_t alignment) const noexcept -> find_t; + return memory_resource_type::instance().deallocate(p, bytes, alignment); + } - auto find_first(const std::size_t size, - const std::size_t alignment) const noexcept -> find_t; + static void release() noexcept + { + return memory_resource_type::instance().release(); + } }; -using freelist_allocator = mr_allocator; -using pool_allocator = mr_allocator; -using fixed_allocator = mr_allocator; - //////////////////////////////////////////////////////////////////////// // // // Container: vector, data_array and list............................ // // // //////////////////////////////////////////////////////////////////////// -//! @brief A vector like class with dynamic allocation. -//! @tparam T Any type (trivial or not). -template +/** + @brief A vector like class with dynamic allocation. + + @tparam T Any type (trivial or not). + */ +template> class vector { public: - using value_type = T; - using size_type = std::uint32_t; - using index_type = std::make_signed_t; - using iterator = T*; - using const_iterator = const T*; - using reference = T&; - using const_reference = const T&; - using pointer = T*; - using const_pointer = const T*; - using allocator_type = A; - using memory_resource_t = typename A::memory_resource_t; - using this_container = vector; + using value_type = T; + using size_type = std::uint32_t; + using index_type = std::make_signed_t; + using iterator = T*; + using const_iterator = const T*; + using reference = T&; + using const_reference = const T&; + using pointer = T*; + using const_pointer = const T*; + using allocator_type = A; + using this_container = vector; private: static_assert(std::is_nothrow_destructible_v || @@ -817,34 +526,18 @@ class vector T* m_data = nullptr; - [[no_unique_address]] allocator_type m_alloc; - index_type m_size = 0; index_type m_capacity = 0; public: constexpr vector() noexcept; - vector(std::integral auto capacity) noexcept; + explicit vector(std::integral auto capacity) noexcept; + vector(std::integral auto capacity, std::integral auto size) noexcept; vector(std::integral auto capacity, std::integral auto size, const T& default_value) noexcept; - constexpr vector(memory_resource_t* mem) noexcept - requires(!std::is_empty_v); - - vector(memory_resource_t* mem, std::integral auto capacity) noexcept - requires(!std::is_empty_v); - vector(memory_resource_t* mem, - std::integral auto capacity, - std::integral auto size) noexcept - requires(!std::is_empty_v); - vector(memory_resource_t* mem, - std::integral auto capacity, - std::integral auto size, - const T& default_value) noexcept - requires(!std::is_empty_v); - ~vector() noexcept; constexpr vector(const vector& other) noexcept; @@ -855,8 +548,8 @@ class vector bool resize(std::integral auto size) noexcept; bool reserve(std::integral auto new_capacity) noexcept; - void destroy() noexcept; // clear all elements and free memory (size = - // 0, capacity = 0 after). + void destroy() noexcept; // clear all elements and free memory (size + // = 0, capacity = 0 after). constexpr void clear() noexcept; // clear all elements (size = 0 after). constexpr void swap(vector& other) noexcept; @@ -942,30 +635,33 @@ constexpr bool is_valid(Identifier id) noexcept return get_key(id) > 0; } -//! @brief An optimized array to store unique identifier. -//! -//! A container to handle only identifier. -//! - linear memory/iteration -//! - O(1) alloc/free -//! - stable indices -//! - weak references -//! - zero overhead dereferences -//! -//! @tparam Identifier A enum class identifier to store identifier unsigned -//! number. -//! @todo Make Identifier split key|id automatically for all unsigned. -template +template +concept is_identifier_type = + std::is_enum_v and + (std::is_same_v, std::uint32_t> or + std::is_same_v, std::uint64_t>); + +/** + An optimized array to store unique identifier. + + A container to handle only identifier. + - linear memory/iteration + - O(1) alloc/free + - stable indices + - weak references + - zero overhead dereferences + + @tparam Identifier A enum class identifier to store identifier unsigned + number. +*/ +template> class id_array { - static_assert(std::is_enum_v, + static_assert(is_identifier_type, "Identifier must be a enumeration: enum class id : " "std::uint32_t or std::uint64_t;"); - static_assert( - std::is_same_v, std::uint32_t> || - std::is_same_v, std::uint64_t>, - "Identifier underlying type must be std::uint32_t or std::uint64_t"); - using underlying_id_type = std::conditional_t< std::is_same_v>, std::uint32_t, @@ -976,11 +672,10 @@ class id_array std::uint16_t, std::uint32_t>; - using identifier_type = Identifier; - using value_type = Identifier; - using this_container = id_array; - using allocator_type = A; - using memory_resource_t = typename A::memory_resource_t; + using identifier_type = Identifier; + using value_type = Identifier; + using this_container = id_array; + using allocator_type = A; static constexpr index_type none = std::numeric_limits::max(); @@ -991,7 +686,8 @@ class id_array index_type m_next_key = 1; /**< [1..2^[16|32] - 1 (never == 0). */ index_type m_free_head = none; // index of first free entry - //! Build a new identifier merging m_next_key and the best free index. + //! Build a new identifier merging m_next_key and the best free + //! index. static constexpr identifier_type make_id(index_type key, index_type index) noexcept; @@ -1007,15 +703,7 @@ class id_array public: constexpr id_array() noexcept = default; - constexpr id_array(memory_resource_t* mem) noexcept - requires(!std::is_empty_v); - - constexpr id_array(std::integral auto capacity) noexcept - requires(std::is_empty_v); - - constexpr id_array(memory_resource_t* mem, - std::integral auto capacity) noexcept - requires(!std::is_empty_v); + constexpr id_array(std::integral auto capacity) noexcept; constexpr ~id_array() noexcept = default; @@ -1030,14 +718,16 @@ class id_array constexpr std::optional get(const Identifier id) const noexcept; constexpr bool exists(const Identifier id) const noexcept; - //! @brief Checks if a `id` exists in the underlying array at index `index`. + //! @brief Checks if a `id` exists in the underlying array at index + //! `index`. //! - //! @attention This function can check the version of the identifier only - //! the `is_defined` is used to detect the `Identifier`. + //! @attention This function can check the version of the identifier + //! only the `is_defined` is used to detect the + //! `Identifier`. //! //! @param index A integer. - //! @return The `Identifier` found at index `index` or `std::nullopt` - //! otherwise. + //! @return The `Identifier` found at index `index` or + //! `std::nullopt` otherwise. constexpr identifier_type get_from_index( std::integral auto index) const noexcept; @@ -1167,57 +857,57 @@ class id_array constexpr const_iterator end() const noexcept; }; -//! @brief An optimized SOA structure to store unique identifier and mutiples -//! vector. -//! -//! A container to handle only identifier. -//! - linear memory/iteration -//! - O(1) alloc/free -//! - stable indices -//! - weak references -//! - zero overhead dereferences -//! -//! @code -//! struct pos3d { -//! float x, y, z; -//! }; -//! -//! struct color { -//! std::uint32_t rgba; -//! }; -//! -//! using name = irt::small_string<15>; -//! -//! enum class ex1_id : uint32_t; -//! -//! irt::id_data_array -//! d; -//! d.reserve(1024); -//! expect(ge(d.capacity(), 1024u)); -//! expect(fatal(d.can_alloc(1))); -//! -//! const auto id = -//! d.alloc([](const auto /*id*/, auto& p, auto& c, auto& n) noexcept { -//! p = pos3d(1.f, 2.f, 3.f); -//! c = color{ 123u }; -//! n = "HelloWorld!"; -//! }); -//! @endcode -//! -//! @tparam Identifier A enum class identifier to store identifier unsigned -//! number. -template +/** + An optimized SOA structure to store unique identifier and mutiples vector. + + A container to handle only identifier. + - linear memory/iteration + - O(1) alloc/free + - stable indices + - weak references + - zero overhead dereferences + + @code + struct pos3d { + float x, y, z; + }; + + struct color { + std::uint32_t rgba; + }; + + using name = irt::small_string<15>; + + enum class ex1_id : uint32_t; + + irt::id_data_array, pos3d, color, name> + d; + d.reserve(1024); + expect(ge(d.capacity(), 1024u)); + expect(fatal(d.can_alloc(1))); + + const auto id = + d.alloc([](const auto id, auto& p, auto& c, auto& n) noexcept + { + p = pos3d(1.f, 2.f, 3.f); + c = color{ 123u }; + n = "HelloWorld!"; + }); + @endcode + + @tparam Identifier A enum class identifier to store identifier unsigned + number. +*/ +template, + class... Ts> class id_data_array { - static_assert(std::is_enum_v, + static_assert(is_identifier_type, "Identifier must be a enumeration: enum class id : " "std::uint32_t or std::uint64_t;"); - static_assert( - std::is_same_v, std::uint32_t> || - std::is_same_v, std::uint64_t>, - "Identifier underlying type must be std::uint32_t or std::uint64_t"); - using underlying_id_type = std::conditional_t< std::is_same_v>, std::uint32_t, @@ -1228,10 +918,9 @@ class id_data_array std::uint16_t, std::uint32_t>; - using identifier_type = Identifier; - using value_type = Identifier; - using allocator_type = A; - using memory_resource_t = typename A::memory_resource_t; + using identifier_type = Identifier; + using value_type = Identifier; + using allocator_type = A; id_array m_ids; std::tuple...> m_col; @@ -1283,28 +972,31 @@ class id_data_array template identifier_type alloc(Function&& fn) noexcept; - /** Return the identifier type at index `idx` if and only if `idx` is in - * range `[0, size()[` and if the value `is_defined` otherwise return - * `undefined()`. */ + /** Return the identifier type at index `idx` if and only if `idx` + * is in range `[0, size()[` and if the value `is_defined` otherwise + * return `undefined()`. */ identifier_type get_id(std::integral auto idx) const noexcept; - /** Release the @c identifier from the @c id_array. @attention To improve - * memory access, the destructors of underlying objects in @c std::tuple of - * @c vector are not called. If you need to realease memory use it before - * releasing the identifier but these objects can be reuse in future. In any - * case all destructor will free the memory in @c id_data_array destructor - * or during the @c reserve() operation. + /** Release the @c identifier from the @c id_array. @attention To + * improve memory access, the destructors of underlying objects in + * @c std::tuple of + * @c vector are not called. If you need to realease memory use it + * before releasing the identifier but these objects can be reuse in + * future. In any case all destructor will free the memory in @c + * id_data_array destructor or during the @c reserve() operation. * * @example - * id_data_array m; + * id_data_array m; * * if (m.exists(id)) - * std::swap(m.get()[get_index(id)], std::string{}); + * std::swap(m.get()[get_index(id)], + * std::string{}); * @endexample */ void free(const identifier_type id) noexcept; - /** Get the underlying @c vector in @c tuple using an index. (read @c - * std::get). */ + /** Get the underlying @c vector in @c tuple using an index. (read + * @c std::get). */ template auto& get() noexcept; @@ -1314,19 +1006,19 @@ class id_data_array auto& get() noexcept requires(not std::is_integral_v); - /** Get the underlying object at position @c id @c vector in @c tuple using - * an index. (read @c std::get). */ + /** Get the underlying object at position @c id @c vector in @c + * tuple using an index. (read @c std::get). */ template auto& get(const identifier_type id) noexcept; - /** Get the underlying object at position @c id in @c vector in @c tuple - * using a type (read @c std::get). */ + /** Get the underlying object at position @c id in @c vector in @c + * tuple using a type (read @c std::get). */ template auto& get(const identifier_type id) noexcept requires(not std::is_integral_v); - /** Get the underlying @c vector in @c tuple using an index. (read @c - * std::get). */ + /** Get the underlying @c vector in @c tuple using an index. (read + * @c std::get). */ template auto& get() const noexcept; @@ -1336,13 +1028,13 @@ class id_data_array auto& get() const noexcept requires(not std::is_integral_v); - /** Get the underlying object at position @c id @c vector in @c tuple using - * an index. (read @c std::get). */ + /** Get the underlying object at position @c id @c vector in @c + * tuple using an index. (read @c std::get). */ template auto& get(const identifier_type id) const noexcept; - /** Get the underlying object at position @c id in @c vector in @c tuple - * using a type (read @c std::get). */ + /** Get the underlying object at position @c id in @c vector in @c + * tuple using a type (read @c std::get). */ template auto& get(const identifier_type id) const noexcept requires(not std::is_integral_v); @@ -1417,10 +1109,13 @@ class id_data_array //! - zero overhead dereferences //! //! @tparam T The type of object the data_array holds. -//! @tparam Identifier A enum class identifier to store identifier unsigned +//! @tparam Identifier A enum class identifier to store identifier +//! unsigned //! number. //! @todo Make Identifier split key|id automatically for all unsigned. -template +template> class data_array { public: @@ -1431,7 +1126,8 @@ class data_array static_assert( std::is_same_v, std::uint32_t> || std::is_same_v, std::uint64_t>, - "Identifier underlying type must be std::uint32_t or std::uint64_t"); + "Identifier underlying type must be std::uint32_t or " + "std::uint64_t"); using underlying_id_type = std::conditional_t< std::is_same_v>, @@ -1443,11 +1139,10 @@ class data_array std::uint16_t, std::uint32_t>; - using identifier_type = Identifier; - using value_type = T; - using this_container = data_array; - using allocator_type = A; - using memory_resource_t = typename A::memory_resource_t; + using identifier_type = Identifier; + using value_type = T; + using this_container = data_array; + using allocator_type = A; private: struct item { @@ -1460,15 +1155,14 @@ class data_array item* m_items = nullptr; // items array - [[no_unique_address]] allocator_type m_alloc; - index_type m_max_size = 0; // number of valid item index_type m_max_used = 0; // highest index ever allocated index_type m_capacity = 0; // capacity of the array index_type m_next_key = 1; // [1..2^32-64] (never == 0) index_type m_free_head = none; // index of first free entry - //! Build a new identifier merging m_next_key and the best free index. + //! Build a new identifier merging m_next_key and the best free + //! index. static constexpr identifier_type make_id(index_type key, index_type index) noexcept; @@ -1486,15 +1180,7 @@ class data_array constexpr data_array() noexcept = default; - constexpr data_array(memory_resource_t* mem) noexcept - requires(!std::is_empty_v); - - constexpr data_array(std::integral auto capacity) noexcept - requires(std::is_empty_v); - - constexpr data_array(memory_resource_t* mem, - std::integral auto capacity) noexcept - requires(!std::is_empty_v); + constexpr data_array(std::integral auto capacity) noexcept; constexpr ~data_array() noexcept; @@ -1504,8 +1190,8 @@ class data_array //! parameter is less or equal than the current @c capacity(). //! //! @attention If the `reserve()` succedded a reallocation takes - //! place, in which case all iterators (including the end() iterator) - //! and all references to the elements are invalidated. + //! place, in which case all iterators (including the end() + //! iterator) and all references to the elements are invalidated. //! //! @attention Use `can_alloc()` to be sure `reserve()` succeed. void reserve(std::integral auto capacity) noexcept; @@ -1513,13 +1199,14 @@ class data_array //! Try to grow the capacity of memory. //! //! - current capacity equals 0 then tries to reserve 8 elements. - //! - current capacity equals size then tries to reserve capacity * 2 + //! - current capacity equals size then tries to reserve capacity * + //! 2 //! elements. //! - else tries to reserve capacity * 3 / 2 elements. //! //! @attention If the `grow()` succedded a reallocation takes - //! place, in which case all iterators (including the end() iterator) - //! and all references to the elements are invalidated. + //! place, in which case all iterators (including the end() + //! iterator) and all references to the elements are invalidated. //! //! @attention Use `can_alloc()` to be sure `grow()` succeed. void grow() noexcept; @@ -1527,25 +1214,27 @@ class data_array //! @brief Destroy all items in the data_array but keep memory //! allocation. //! - //! @details Run the destructor if @c T is not trivial on outstanding + //! @details Run the destructor if @c T is not trivial on + //! outstanding //! items and re-initialize the size. void clear() noexcept; //! @brief Destroy all items in the data_array and release memory. //! - //! @details Run the destructor if @c T is not trivial on outstanding + //! @details Run the destructor if @c T is not trivial on + //! outstanding //! items and re-initialize the size. void destroy() noexcept; //! @brief Alloc a new element. //! - //! If m_max_size == m_capacity then this function will abort. Before - //! using this function, tries @c !can_alloc() for example otherwise use - //! the @c try_alloc function. + //! If m_max_size == m_capacity then this function will abort. + //! Before using this function, tries @c !can_alloc() for example + //! otherwise use the @c try_alloc function. //! //! Use @c m_free_head if not empty or use a new items from buffer - //! (@m_item[max_used++]). The id is set to from @c next_key++ << 32) | - //! index to build unique identifier. + //! (@m_item[max_used++]). The id is set to from @c next_key++ << + //! 32) | index to build unique identifier. //! //! @return A reference to the newly allocated element. template @@ -1554,8 +1243,8 @@ class data_array //! @brief Alloc a new element. //! //! Use @c m_free_head if not empty or use a new items from buffer - //! (@m_item[max_used++]). The id is set to from @c next_key++ << 32) | - //! index to build unique identifier. + //! (@m_item[max_used++]). The id is set to from @c next_key++ << + //! 32) | index to build unique identifier. //! //! @return A pair with a boolean if the allocation success and a //! pointer to the newly element. @@ -1564,14 +1253,14 @@ class data_array //! @brief Free the element @c t. //! - //! Internally, puts the elelent @c t entry on free list and use id to - //! store next. + //! Internally, puts the elelent @c t entry on free list and use id + //! to store next. void free(T& t) noexcept; //! @brief Free the element pointer by @c id. //! - //! Internally, puts the element @c id entry on free list and use id to - //! store next. + //! Internally, puts the element @c id entry on free list and use id + //! to store next. void free(Identifier id) noexcept; //! @brief Accessor to the id part of the item @@ -1596,9 +1285,9 @@ class data_array //! @brief Get a T from an ID. //! - //! @details Validates ID, then returns item, returns null if invalid. - //! For cases like AI references and others where 'the thing might have - //! been deleted out from under me. + //! @details Validates ID, then returns item, returns null if + //! invalid. For cases like AI references and others where 'the + //! thing might have been deleted out from under me. //! //! @param id Identifier to get. //! @return T or nullptr @@ -1620,8 +1309,8 @@ class data_array //! } //! @endcode //! - //! Loop item where @c id & 0xffffffff00000000 != 0 (i.e. items not on - //! free list). + //! Loop item where @c id & 0xffffffff00000000 != 0 (i.e. items not + //! on free list). //! //! @return true if the paramter @c t is valid false otherwise. bool next(T*& t) noexcept; @@ -1636,8 +1325,8 @@ class data_array //! } //! @endcode //! - //! Loop item where @c id & 0xffffffff00000000 != 0 (i.e. items not on - //! free list). + //! Loop item where @c id & 0xffffffff00000000 != 0 (i.e. items not + //! on free list). //! //! @return true if the paramter @c t is valid false otherwise. bool next(const T*& t) const noexcept; @@ -1674,9 +1363,9 @@ class data_array iterator_base& operator++() noexcept { - pointer next = self->try_to_get(id); - bool success = self->next(next); - id = success ? self->get_id(*next) : identifier_type{}; + pointer ptr = self->try_to_get(id); + bool success = self->next(ptr); + id = success ? self->get_id(*ptr) : identifier_type{}; return *this; } @@ -1684,9 +1373,9 @@ class data_array iterator_base operator++(int) noexcept { auto old_id = id; - pointer next = self->try_to_get(id); - bool success = self->next(next); - id = success ? self->get_id(*next) : identifier_type{}; + pointer ptr = self->try_to_get(id); + bool success = self->next(ptr); + id = success ? self->get_id(*ptr) : identifier_type{}; return iterator_base{ .self = self, .id = old_id }; } @@ -1733,31 +1422,29 @@ class data_array //! dequeue() enqueue() //! //! @tparam T Any type (trivial or not). -template +template> class ring_buffer { public: - using value_type = T; - using size_type = std::uint32_t; - using index_type = std::make_signed_t; - using reference = T&; - using const_reference = const T&; - using pointer = T*; - using const_pointer = const T*; - using this_container = ring_buffer; - using allocator_type = A; - using memory_resource_t = typename A::memory_resource_t; + using value_type = T; + using size_type = std::uint32_t; + using index_type = std::make_signed_t; + using reference = T&; + using const_reference = const T&; + using pointer = T*; + using const_pointer = const T*; + using this_container = ring_buffer; + using allocator_type = A; static_assert((std::is_nothrow_constructible_v || std::is_nothrow_move_constructible_v) && std::is_nothrow_destructible_v); private: - T* buffer = nullptr; - [[no_unique_address]] allocator_type m_alloc; - index_type m_head = 0; - index_type m_tail = 0; - index_type m_capacity = 0; + T* buffer = nullptr; + index_type m_head = 0; + index_type m_tail = 0; + index_type m_capacity = 0; constexpr index_type advance(index_type position) const noexcept; constexpr index_type back(index_type position) const noexcept; @@ -1812,13 +1499,7 @@ class ring_buffer using const_iterator = iterator_base; constexpr ring_buffer() noexcept = default; - constexpr ring_buffer(std::integral auto capacity) noexcept; - constexpr ring_buffer(memory_resource_t* mem) noexcept - requires(!std::is_empty_v); - - constexpr ring_buffer(memory_resource_t* mem, - std::integral auto capacity) noexcept - requires(!std::is_empty_v); + explicit constexpr ring_buffer(std::integral auto capacity) noexcept; constexpr ~ring_buffer() noexcept; @@ -1986,8 +1667,8 @@ class small_vector using index_type = std::make_signed_t; private: - alignas(8) std::byte m_buffer[length * sizeof(T)]; - size_type m_size; // number of T element in the m_buffer. + alignas(std::max_align_t) std::byte m_buffer[length * sizeof(T)]; + size_type m_size = 0; public: using iterator = T*; @@ -1997,7 +1678,7 @@ class small_vector using pointer = T*; using const_pointer = const T*; - constexpr small_vector() noexcept; + constexpr small_vector() noexcept = default; constexpr ~small_vector() noexcept; constexpr small_vector(const small_vector& other) noexcept; @@ -2046,21 +1727,23 @@ class small_vector constexpr iterator erase(iterator to_del) noexcept; }; -//! A ring-buffer based on a fixed size container. m_head point to -//! the first element can be dequeue while m_tail point to the first -//! constructible element in the ring. -//! -//! --+----+----+----+----+----+-- -//! | | | | | | -//! | | | | | | -//! | | | | | | -//! --+----+----+----+----+----+-- -//! head tail -//! -//! -----> -----> -//! dequeue() enqueue() -//! -//! @tparam T Any type (trivial or not). +/** + A ring-buffer based on a fixed size container. m_head point to + the first element can be dequeue while m_tail point to the first + constructible element in the ring. + + --+----+----+----+----+----+-- + | | | | | | + | | | | | | + | | | | | | + --+----+----+----+----+----+-- + head tail + + -----> -----> + dequeue() enqueue() + + @tparam T Any type (trivial or not). + */ template class small_ring_buffer { @@ -2217,9 +1900,9 @@ class bitflags typename std::underlying_type_t>; constexpr bitflags() noexcept = default; - constexpr bitflags(unsigned long long val) noexcept; + explicit constexpr bitflags(unsigned long long val) noexcept; - constexpr bitflags(std::same_as auto... args) noexcept; + explicit constexpr bitflags(std::same_as auto... args) noexcept; constexpr bitflags& set(value_type e, bool value = true) noexcept; constexpr bitflags& reset(value_type e) noexcept; @@ -2292,32 +1975,16 @@ id_array::get_index(Identifier id) noexcept 0xffffffff); } -template -constexpr id_array::id_array(memory_resource_t* mem) noexcept - requires(!std::is_empty_v) - : m_items{ mem } -{} - template constexpr id_array::id_array( std::integral auto capacity) noexcept - requires(std::is_empty_v) : m_items{ capacity } {} -template -constexpr id_array::id_array( - memory_resource_t* mem, - std::integral auto capacity) noexcept - requires(!std::is_empty_v) - : m_items{ mem, capacity } -{} - template constexpr Identifier id_array::alloc() noexcept { - debug::ensure(can_alloc(1) && - "check alloc() with full() before using use."); + debug::ensure(can_alloc(1)); if (m_free_head != none) { index_type new_index = m_free_head; @@ -2874,40 +2541,13 @@ data_array::get_index(Identifier id) noexcept template constexpr data_array::data_array( - memory_resource_t* mem) noexcept - requires(!std::is_empty_v) - : m_alloc{ mem } -{} - -template -constexpr data_array::data_array( - std::integral auto capacity) noexcept - requires(std::is_empty_v) -{ - debug::ensure(std::cmp_greater(capacity, 0)); - debug::ensure( - std::cmp_less(capacity, std::numeric_limits::max())); - - m_items = m_alloc.template allocate(capacity); - m_max_size = 0; - m_max_used = 0; - m_capacity = static_cast(capacity); - m_next_key = 1; - m_free_head = none; -} - -template -constexpr data_array::data_array( - memory_resource_t* mem, std::integral auto capacity) noexcept - requires(!std::is_empty_v) - : m_alloc(mem) { debug::ensure(std::cmp_greater(capacity, 0)); debug::ensure( std::cmp_less(capacity, std::numeric_limits::max())); - m_items = m_alloc.template allocate(capacity); + m_items = reinterpret_cast(A::allocate(sizeof(item) * capacity)); m_max_size = 0; m_max_used = 0; m_capacity = static_cast(capacity); @@ -2921,7 +2561,7 @@ constexpr data_array::~data_array() noexcept clear(); if (m_items) - m_alloc.deallocate(m_items, m_capacity); + A::deallocate(m_items, sizeof(item) * m_capacity); } template @@ -2937,7 +2577,8 @@ void data_array::reserve(std::integral auto capacity) noexcept std::cmp_less_equal(capacity, m_capacity)) return; - item* new_buffer = m_alloc.template allocate(capacity); + item* new_buffer = + reinterpret_cast(A::allocate(sizeof(item) * capacity)); if (new_buffer == nullptr) return; @@ -2973,7 +2614,7 @@ void data_array::reserve(std::integral auto capacity) noexcept } if (m_items) - m_alloc.template deallocate(m_items, m_capacity); + A::deallocate(m_items, sizeof(item) * m_capacity); m_items = new_buffer; m_capacity = static_cast(capacity); @@ -3025,7 +2666,7 @@ void data_array::destroy() noexcept clear(); if (m_items) - m_alloc.deallocate(m_items, m_capacity); + A::deallocate(m_items, sizeof(item) * m_capacity); m_items = nullptr; m_capacity = 0; @@ -3036,8 +2677,7 @@ template typename data_array::value_type& data_array::alloc(Args&&... args) noexcept { - debug::ensure(can_alloc(1) && - "check alloc() with full() before using use."); + debug::ensure(can_alloc(1)); index_type new_index; @@ -3347,12 +2987,6 @@ template constexpr vector::vector() noexcept {} -template -constexpr vector::vector(memory_resource_t* mem) noexcept - requires(!std::is_empty_v) - : m_alloc(mem) -{} - template constexpr bool vector::make(std::integral auto capacity) noexcept { @@ -3361,9 +2995,8 @@ constexpr bool vector::make(std::integral auto capacity) noexcept std::numeric_limits::max())); if (std::cmp_greater(capacity, 0)) { - m_data = m_alloc.template allocate(capacity); - - if (m_data) { + if (auto* ret = A::allocate(sizeof(T) * capacity)) { + m_data = reinterpret_cast(ret); m_size = static_cast(0); m_capacity = static_cast(capacity); } @@ -3452,36 +3085,6 @@ inline vector::vector(std::integral auto capacity, make(capacity, size, default_value); } -template -inline vector::vector(memory_resource_t* mem, - std::integral auto capacity) noexcept - requires(!std::is_empty_v) - : m_alloc(mem) -{ - make(capacity); -} - -template -inline vector::vector(memory_resource_t* mem, - std::integral auto capacity, - std::integral auto size) noexcept - requires(!std::is_empty_v) - : m_alloc(mem) -{ - make(capacity, size); -} - -template -inline vector::vector(memory_resource_t* mem, - std::integral auto capacity, - std::integral auto size, - const T& default_value) noexcept - requires(!std::is_empty_v) - : m_alloc(mem) -{ - make(capacity, size, default_value); -} - template inline vector::~vector() noexcept { @@ -3542,7 +3145,7 @@ inline void vector::destroy() noexcept clear(); if (m_data) - m_alloc.template deallocate(m_data, m_capacity); + A::deallocate(m_data, m_capacity * sizeof(T)); m_data = nullptr; m_size = 0; @@ -3595,7 +3198,8 @@ bool vector::reserve(std::integral auto new_capacity) noexcept std::cmp_less(new_capacity, std::numeric_limits::max())); if (std::cmp_greater(new_capacity, m_capacity)) { - T* new_data = m_alloc.template allocate(new_capacity); + T* new_data = + reinterpret_cast(A::allocate(sizeof(T) * new_capacity)); if (!new_data) return false; @@ -3605,7 +3209,7 @@ bool vector::reserve(std::integral auto new_capacity) noexcept std::uninitialized_copy_n(data(), m_size, new_data); if (m_data) - m_alloc.template deallocate(m_data, m_capacity); + A::deallocate(m_data, sizeof(T) * m_capacity); m_data = new_data; m_capacity = static_cast(new_capacity); @@ -3754,7 +3358,7 @@ template inline constexpr typename vector::reference vector::emplace_back( Args&&... args) noexcept { - static_assert(std::is_trivially_constructible_v || + static_assert(std::is_constructible_v || std::is_nothrow_constructible_v, "T must but trivially or nothrow constructible from this " "argument(s)"); @@ -3909,12 +3513,6 @@ int vector::compute_new_capacity(int size) const // class small_vector; // -template -constexpr small_vector::small_vector() noexcept -{ - m_size = 0; -} - template constexpr small_vector::small_vector( const small_vector& other) noexcept @@ -4175,8 +3773,7 @@ small_vector::emplace_back(Args&&... args) noexcept "T must but trivially constructible from this " "argument(s)"); - debug::ensure(can_alloc(1) && - "check alloc() with full() before using use."); + debug::ensure(can_alloc(1)); std::construct_at(&(data()[m_size]), std::forward(args)...); ++m_size; @@ -4188,8 +3785,7 @@ template constexpr typename small_vector::reference small_vector::push_back(const T& arg) noexcept { - debug::ensure(can_alloc(1) && - "check alloc() with full() before using use."); + debug::ensure(can_alloc(1)); std::construct_at(&(data()[m_size]), arg); ++m_size; @@ -4768,28 +4364,16 @@ template constexpr bool ring_buffer::make(std::integral auto capacity) noexcept { if (std::cmp_greater(capacity, 0)) { - buffer = m_alloc.template allocate(capacity); - m_capacity = static_cast(capacity); + auto* ptr = reinterpret_cast(A::allocate(sizeof(T) * capacity)); + if (ptr) { + buffer = ptr; + m_capacity = static_cast(capacity); + } } return buffer != nullptr; } -template -constexpr ring_buffer::ring_buffer(memory_resource_t* mem) noexcept - requires(!std::is_empty_v) - : m_alloc(mem) -{} - -template -constexpr ring_buffer::ring_buffer(memory_resource_t* mem, - std::integral auto capacity) noexcept - requires(!std::is_empty_v) - : m_alloc(mem) -{ - make(capacity); -} - template constexpr ring_buffer::ring_buffer(std::integral auto capacity) noexcept { @@ -4803,12 +4387,16 @@ constexpr ring_buffer::ring_buffer(const ring_buffer& rhs) noexcept clear(); if (m_capacity != rhs.m_capacity) { - if (buffer) - m_alloc.template deallocate(buffer, m_capacity); - - if (rhs.m_capacity) { - buffer = m_alloc.template allocate(rhs.m_capacity); - m_capacity = rhs.m_capacity; + auto* ptr = + reinterpret_cast(A::allocate(sizeof(T) * rhs.m_capacity)); + if (ptr) { + if (buffer) + A::deallocate(buffer, sizeof(T) * m_capacity); + + if (rhs.m_capacity) { + buffer = ptr; + m_capacity = rhs.m_capacity; + } } } @@ -4825,12 +4413,16 @@ constexpr ring_buffer& ring_buffer::operator=( clear(); if (m_capacity != rhs.m_capacity) { - if (buffer) - m_alloc.template deallocate(buffer, m_capacity); - - if (rhs.m_capacity > 0) { - buffer = m_alloc.template allocate(rhs.m_capacity); - m_capacity = rhs.m_capacity; + auto* ptr = + reinterpret_cast(A::allocate(sizeof(T) * rhs.m_capacity)); + if (ptr) { + if (buffer) + A::deallocate(buffer, sizeof(T) * m_capacity); + + if (rhs.m_capacity > 0) { + buffer = ptr; + m_capacity = rhs.m_capacity; + } } } @@ -4843,17 +4435,11 @@ constexpr ring_buffer& ring_buffer::operator=( template constexpr ring_buffer::ring_buffer(ring_buffer&& rhs) noexcept -{ - buffer = rhs.buffer; - m_head = rhs.m_head; - m_tail = rhs.m_tail; - m_capacity = rhs.m_capacity; - - rhs.buffer = nullptr; - rhs.m_head = 0; - rhs.m_tail = 0; - rhs.m_capacity = 0; -} + : buffer{ std::exchange(rhs.buffer, nullptr) } + , m_head{ std::exchange(rhs.m_head, 0) } + , m_tail{ std::exchange(rhs.m_tail, 0) } + , m_capacity{ std::exchange(rhs.m_capacity, 0) } +{} template constexpr ring_buffer& ring_buffer::operator=( @@ -4862,15 +4448,10 @@ constexpr ring_buffer& ring_buffer::operator=( if (this != &rhs) { clear(); - buffer = rhs.buffer; - m_head = rhs.m_head; - m_tail = rhs.m_tail; - m_capacity = rhs.m_capacity; - - rhs.buffer = nullptr; - rhs.m_head = 0; - rhs.m_tail = 0; - rhs.m_capacity = 0; + buffer = std::exchange(rhs.buffer, nullptr); + m_head = std::exchange(rhs.m_head, 0); + m_tail = std::exchange(rhs.m_tail, 0); + m_capacity = std::exchange(rhs.m_capacity, 0); } return *this; @@ -4907,9 +4488,11 @@ template constexpr void ring_buffer::destroy() noexcept { clear(); - if (buffer) - m_alloc.template deallocate(buffer, m_capacity); - buffer = nullptr; + + if (buffer) { + A::deallocate(buffer, sizeof(T) * m_capacity); + buffer = nullptr; + } } template @@ -5862,9 +5445,8 @@ void small_ring_buffer::iterator_base::reset() noexcept template constexpr bitflags::bitflags(unsigned long long val) noexcept -{ - m_bits = val; -} + : m_bits{ val } +{} template constexpr bitflags::bitflags(std::same_as auto... args) noexcept diff --git a/lib/include/irritator/core.hpp b/lib/include/irritator/core.hpp index 2fbde415..12237f46 100644 --- a/lib/include/irritator/core.hpp +++ b/lib/include/irritator/core.hpp @@ -251,7 +251,7 @@ class constrained_value T m_value; public: - constexpr constrained_value(const T value_) noexcept + explicit constexpr constrained_value(const T value_) noexcept : m_value(value_ < Lower ? Lower : value_ < Upper ? value_ : Upper) @@ -355,12 +355,12 @@ enum class binary_file_source_id : u64; enum class text_file_source_id : u64; enum class random_source_id : u64; -//! Helps to calculate the sizes of the `vectors` and `data_array` from a -//! number of bytes. Compute for each `source` the same number and adjust -//! the `max_client` variables for both random and binary source. +/** + Helps to calculate the sizes of the `vectors` and `data_array` from a + number of bytes. Compute for each `source` the same number and adjust + the `max_client` variables for both random and binary source. + */ struct external_source_memory_requirement { - std::size_t bytes = 0; - unsigned constant_nb = 4u; unsigned text_file_nb = 4u; unsigned binary_file_nb = 4u; @@ -370,17 +370,6 @@ struct external_source_memory_requirement { constexpr external_source_memory_requirement() noexcept = default; - //! Compute the size of each source. - //! - //! @param bytes The numbers of bytes availables. - //! @param source_client_ratio A integer in the range `[0..100]` defines - //! the ratio between `source` and `max_client` variables. `50` mean 50% - //! sources and 50% max_clients, `0` means no source, `100` means no - //! max-client. - constexpr external_source_memory_requirement( - const std::size_t bytes, - const constrained_value source_client_ratio) noexcept; - constexpr external_source_memory_requirement( const unsigned constant, const unsigned text_f, @@ -390,77 +379,47 @@ struct external_source_memory_requirement { const unsigned random_max_client) noexcept; }; -//! Helps to calculate the sizes of the `vectors` and `data_array` from a -//! number of bytes. -class simulation_memory_requirement -{ -public: - constexpr static inline auto default_simulation_model_number = 256u; - constexpr static inline auto default_simulation_connection_number = 1024u; - - std::size_t connections_b = 0; - std::size_t dated_messages_b = 0; - std::size_t external_source_b = 0; - std::size_t simulation_b = 0; - std::size_t global_b = 0; +constexpr external_source_memory_requirement:: + external_source_memory_requirement(const unsigned constant, + const unsigned text_f, + const unsigned bin_f, + const unsigned random, + const unsigned bin_f_max_client, + const unsigned random_max_client) noexcept + : constant_nb(constant) + , text_file_nb(text_f) + , binary_file_nb(bin_f) + , random_nb(random) + , binary_file_max_client(bin_f_max_client) + , random_max_client(random_max_client) +{} - int model_nb = 0; - int hsm_nb = 0; +/** + Helps to calculate the sizes of the `vectors` and `data_array` from a number + of bytes. + */ +struct simulation_memory_requirement { + unsigned models = 256u; + unsigned connections = models * 8; + unsigned hsms = models * 1 / 10; + unsigned dated_messages = models * 1 / 10; - external_source_memory_requirement srcs; + constexpr simulation_memory_requirement() noexcept = default; - /** Computes the required memory to build the simulation that can run at - * least @c model_nb models and @c connection_nb connections. - * - * @param bytes The numbers of bytes availables. - * @param external_source Percentage of memory to use in external source. - * @param source_client_ratio - * @param connections Percentage of simulation memory dedicated to - * connections. - * @param dated_messages Percentage of siulation memory dedicated to fifo, - * lifo history. - */ - constexpr simulation_memory_requirement( - const std::size_t model_nb, - const std::size_t connection_nb, - const constrained_value connections = 5, - const constrained_value hsms = 1, - const constrained_value dated_messages = 5, - const constrained_value external_source = 10, - const constrained_value source_client = 50) noexcept; - - /** Computes the required memory to build the simulation and splits - * available memory in memory resource, free list and container. - * - * @param bytes The numbers of bytes availables. - * @param external_source Percentage of memory to use in external source. - * @param source_client_ratio - * @param connections Percentage of simulation memory dedicated to - * connections. - * @param dated_messages Percentage of siulation memory dedicated to fifo, - * lifo history. + /** + Computes the required memory to build the simulation that can run at + least @c model_nb models and @c connection_nb connections. + + @param bytes The numbers of bytes availables. + @param external_source Percentage of memory to use in external source. + @param source_client_ratio + @param connections Percentage of simulation memory dedicated to + connections. + @param dated_messages Percentage of siulation memory dedicated to fifo, + lifo history. */ - constexpr simulation_memory_requirement( - const std::size_t bytes, - const constrained_value connections = 5, - const constrained_value hsms = 10, - const constrained_value dated_messages = 5, - const constrained_value external_source = 10, - const constrained_value source_client = 50) noexcept; - - constexpr bool valid() const noexcept; - - //! Compute an estimate to store a model in simulation memory. - constexpr static size_t estimate_model() noexcept; - -private: - constexpr void compute_buffer_size( - const std::size_t bytes, - const constrained_value connections, - const constrained_value hsms, - const constrained_value dated_messages, - const constrained_value external_source, - const constrained_value source_client) noexcept; + explicit constexpr simulation_memory_requirement( + unsigned model_nb) noexcept; }; /***************************************************************************** @@ -721,7 +680,8 @@ class external_source /** Build data-array according to the @c init structure. Use the @c realloc * function after this constructor to allocate memory. */ - external_source(const external_source_memory_requirement& init) noexcept; + explicit external_source( + const external_source_memory_requirement& init) noexcept; ~external_source() noexcept; @@ -847,10 +807,10 @@ struct parameter { //! Import values from the model @c mdl according to the underlying @c //! irt::dynamics_type. - parameter(const model& mdl) noexcept; + explicit parameter(const model& mdl) noexcept; //! Initialize values from the default dynamics type. - parameter(const dynamics_type type) noexcept; + explicit parameter(const dynamics_type type) noexcept; //! Copy data from the vectors to the simulation model. void copy_to(model& mdl) const noexcept; @@ -974,14 +934,13 @@ static inline constexpr u32 invalid_heap_handle = 0xffffffff; implementation and excellent practical amortized performance, introduced by Michael Fredman, Robert Sedgewick, Daniel Sleator, and Robert Tarjan in 1986. */ -template +template> class heap { public: - using this_container = heap; - using allocator_type = A; - using memory_resource = typename A::memory_resource_t; - using index_type = u32; + using this_container = heap; + using allocator_type = A; + using index_type = u32; struct node { time tn; @@ -1007,9 +966,6 @@ class heap constexpr heap() noexcept = default; - constexpr heap(memory_resource* mem) noexcept - requires(!std::is_empty_v); - constexpr ~heap() noexcept; /** Clear and free the allocated buffer. */ @@ -1084,13 +1040,12 @@ class heap and `node::prev` are null (`irt::invalid_heap_handle`). To detach a node, you can use the `heap::pop()` or `heap::remove()` functions. */ -template +template> class scheduller { public: - using this_container = heap; - using allocator_type = A; - using memory_resource = typename A::memory_resource_t; + using this_container = heap; + using allocator_type = A; private: heap m_heap; @@ -1112,7 +1067,7 @@ class scheduller This function @c abort if the scheduller fail to allocate more nodes. Use the @c can_alloc() before use. - */ + */ void alloc(model& mdl, model_id id, time tn) noexcept; /** @@ -1200,7 +1155,7 @@ class simulation data_array, dated_message_id> dated_messages; - scheduller<> sched; + scheduller> sched; external_source srcs; @@ -1222,19 +1177,31 @@ class simulation /** Allocate new buffers for all memory resource and container. Do not call * destroy before. This function is used in `constructors` or in `realloc()` * function after the call to `destroy()`. */ - void do_realloc(const simulation_memory_requirement& init) noexcept; + void do_realloc( + const simulation_memory_requirement& init, + const external_source_memory_requirement& srcs_init) noexcept; public: + //! Use the default malloc memory resource to allocate all memory need + //! by sub-containers. + simulation() noexcept; + //! Use the default malloc memory resource to allocate all memory need //! by sub-containers. simulation(const simulation_memory_requirement& init) noexcept; + //! Use the default malloc memory resource to allocate all memory need + //! by sub-containers. + simulation(const simulation_memory_requirement& init, + const external_source_memory_requirement& srcs_init) noexcept; + /** Call the @C destroy function to free allocated memory */ ~simulation() noexcept; /** Call the @c destroy() function then allocate new buffers according to @c * init parameter. */ - void realloc(const simulation_memory_requirement& init) noexcept; + void realloc(const simulation_memory_requirement& init, + const external_source_memory_requirement& srcs_init) noexcept; /** Clear, delete or destroy any buffer allocated in constructor or in @c * realloc() function. Use the @c realloc() function to allocate new buffer @@ -3405,8 +3372,8 @@ struct logical_invert { status transition(simulation& sim, time, time, time) noexcept { - auto value_changed = false; - auto* lst = sim.messages.try_to_get(x[0]); + value_changed = false; + auto* lst = sim.messages.try_to_get(x[0]); if (lst and not lst->empty()) { const auto& msg = lst->front(); @@ -5137,12 +5104,6 @@ inline auto get_hierarchical_state_machine(simulation& sim, // heap // -template -constexpr heap::heap(memory_resource* mem) noexcept - requires(!std::is_empty_v) - : m_alloc{ mem } -{} - template constexpr heap::~heap() noexcept { @@ -5153,7 +5114,7 @@ template constexpr void heap::destroy() noexcept { if (nodes) - m_alloc.template deallocate(nodes, capacity); + A::deallocate(nodes, sizeof(node) * capacity); nodes = nullptr; m_size = 0; @@ -5189,16 +5150,17 @@ constexpr bool heap::reserve(std::integral auto new_capacity) noexcept if (std::cmp_less_equal(new_capacity, max_size)) return false; - auto* new_data = m_alloc.template allocate(new_capacity); + auto* new_data = + reinterpret_cast(A::allocate(sizeof(node) * new_capacity)); if (not new_data) return false; if (nodes) { std::uninitialized_copy_n(nodes, max_size, new_data); - m_alloc.template deallocate(nodes, capacity); + A::deallocate(nodes, sizeof(node) * capacity); } - nodes = new_data; + nodes = reinterpret_cast(new_data); capacity = static_cast(new_capacity); return true; @@ -5640,44 +5602,59 @@ inline int scheduller::ssize() const noexcept // simulation // +inline simulation::simulation() noexcept +{ + do_realloc(simulation_memory_requirement{}, + external_source_memory_requirement{}); +} + inline simulation::simulation( const simulation_memory_requirement& init) noexcept { - do_realloc(init); + do_realloc(init, external_source_memory_requirement{}); +} + +inline simulation::simulation( + const simulation_memory_requirement& init, + const external_source_memory_requirement& srcs_init) noexcept +{ + do_realloc(init, srcs_init); } inline void simulation::do_realloc( - const simulation_memory_requirement& init) noexcept + const simulation_memory_requirement& init, + const external_source_memory_requirement& srcs_init) noexcept { - debug::ensure(init.valid()); destroy(); - if (init.model_nb > 0) { - models.reserve(init.model_nb); - parameters.resize(init.model_nb); - observers.reserve(init.model_nb); - nodes.reserve(init.model_nb * 4); // Max 4 output port by models - messages.reserve(init.model_nb * 4); - dated_messages.reserve(init.model_nb); + if (init.models > 0) { + models.reserve(init.models); + parameters.resize(init.models); + observers.reserve(init.models); + emitting_output_ports.reserve(init.models); + immediate_models.reserve(init.models); + immediate_observers.reserve(init.models); + + nodes.reserve(init.connections); + messages.reserve(init.connections); - emitting_output_ports.reserve(init.model_nb); - immediate_models.reserve(init.model_nb); - immediate_observers.reserve(init.model_nb); + dated_messages.reserve(init.dated_messages); - sched.reserve(init.model_nb); + sched.reserve(init.models); } - if (init.hsm_nb > 0) - hsms.reserve(init.hsm_nb); + if (init.hsms > 0) + hsms.reserve(init.hsms); - srcs.realloc(init.srcs); + srcs.realloc(srcs_init); } inline void simulation::realloc( - const simulation_memory_requirement& init) noexcept + const simulation_memory_requirement& init, + const external_source_memory_requirement& srcs_init) noexcept { destroy(); - do_realloc(init); + do_realloc(init, srcs_init); } inline void simulation::destroy() noexcept @@ -6257,9 +6234,7 @@ Dynamics& simulation::alloc() noexcept dyn.y[i] = undefined(); if constexpr (std::is_same_v) { - auto& hsm = hsms.alloc(); - auto id = hsms.get_id(hsm); - dyn.id = id; + dyn.id = undefined(); } return dyn; @@ -6619,163 +6594,13 @@ inline status priority_queue::transition(simulation& sim, return success(); } -// simulation memory requirement - -inline constexpr simulation_memory_requirement::simulation_memory_requirement( - const std::size_t model_nb, - const std::size_t hsm_nb, - const constrained_value connections, - const constrained_value hsms_model, - const constrained_value dated_messages, - const constrained_value external_source, - const constrained_value source_client) noexcept -{ - const auto model_size = estimate_model(); - const auto base_size = model_size * model_nb; - auto size = base_size; - - size += sizeof(hierarchical_state_machine) * hsm_nb * 2; - size += (*connections * base_size) / 100; - size += (*dated_messages * base_size) / 100; - size += (*hsms_model * base_size) / 100; - size += (*external_source * base_size) / 100; - size += (*source_client * base_size) / 100; - size = make_divisible_to(size * 2, alignof(std::max_align_t)); - - compute_buffer_size(size, - connections, - hsms_model, - dated_messages, - external_source, - source_client); -} - inline constexpr simulation_memory_requirement::simulation_memory_requirement( - const std::size_t bytes, - const constrained_value connections, - const constrained_value hsms_model, - const constrained_value dated_messages, - const constrained_value external_source, - const constrained_value source_client) noexcept -{ - compute_buffer_size(bytes, - connections, - hsms_model, - dated_messages, - external_source, - source_client); -} - -inline constexpr void simulation_memory_requirement::compute_buffer_size( - const std::size_t bytes, - const constrained_value connections, - const constrained_value hsms, - const constrained_value dated_messages, - const constrained_value external_source, - const constrained_value source_client) noexcept -{ - constexpr size_t alg = alignof(std::max_align_t); - - global_b = bytes; - const auto margin = bytes - ((bytes * 10) / 100); - connections_b = make_divisible_to(margin * *connections / 100, alg); - dated_messages_b = make_divisible_to(margin * *dated_messages / 100, alg); - external_source_b = make_divisible_to(margin * *external_source / 100, alg); - simulation_b = make_divisible_to( - margin - (connections_b + dated_messages_b + external_source_b), alg); - - debug::ensure(connections_b + dated_messages_b + external_source_b + - simulation_b <= - bytes); - - const auto model_size = estimate_model(); - const auto max_model_nb = static_cast(simulation_b / model_size); - - hsm_nb = max_model_nb * *hsms / 100; - model_nb = max_model_nb - hsm_nb; - srcs = - external_source_memory_requirement(external_source_b, *source_client); -} - -inline constexpr bool simulation_memory_requirement::valid() const noexcept -{ - return model_nb > 0 and hsm_nb >= 0; -} - -inline constexpr size_t simulation_memory_requirement::estimate_model() noexcept -{ - return sizeof(output_message) + sizeof(model_id) + sizeof(observer_id) + - sizeof(data_array::internal_value_type) + - sizeof(data_array::internal_value_type) + - sizeof(data_array, node_id, freelist_allocator>:: - internal_value_type) + - sizeof(node) * 8 + - sizeof(data_array, - message_id, - freelist_allocator>::internal_value_type) * - 4 + - sizeof(data_array, - dated_message_id, - freelist_allocator>::internal_value_type) + - sizeof(heap>::node); -} - -inline constexpr external_source_memory_requirement:: - external_source_memory_requirement( - const std::size_t bytes_, - const constrained_value source_client_ratio) noexcept - : bytes{ bytes_ } -{ - const auto srcs = make_divisible_to(bytes * *source_client_ratio / 100); - const auto max_client = make_divisible_to(bytes - srcs); - const auto block_size = sizeof(chunk_type) + sizeof(u64); - const auto client = static_cast((max_client / 2) / block_size); - - const auto sources = static_cast(srcs / block_size); - const auto source = sources / 4; - - constant_nb = source; - text_file_nb = source; - binary_file_nb = source; - random_nb = source; - binary_file_max_client = client; - random_max_client = client; -} - -inline constexpr external_source_memory_requirement:: - external_source_memory_requirement(const unsigned constant, - const unsigned text_f, - const unsigned bin_f, - const unsigned random, - const unsigned bin_f_max_client, - const unsigned random_max_client) noexcept - : constant_nb{ constant } - , text_file_nb{ text_f } - , binary_file_nb{ bin_f } - , random_nb{ random } - , binary_file_max_client{ bin_f_max_client } - , random_max_client{ random_max_client } -{ - const auto estimation = - sizeof(data_array::internal_value_type) * - constant + - sizeof(data_array::internal_value_type) * - text_f + - (sizeof(data_array::internal_value_type) + - (sizeof(chunk_type) + sizeof(u64)) * bin_f_max_client) * - bin_f + - (sizeof( - data_array::internal_value_type) + - (sizeof(chunk_type) + sizeof(u64) * 4) * random_max_client) * - random; - - bytes = make_divisible_to(estimation << 2); + unsigned model_nb) noexcept +{ + model_nb = model_nb == 0 ? 256u : model_nb; + connections = models * 10; + hsms = models / 10; + dated_messages = models / 20; } } // namespace irt diff --git a/lib/include/irritator/ext.hpp b/lib/include/irritator/ext.hpp index 97ad3388..f78100f3 100644 --- a/lib/include/irritator/ext.hpp +++ b/lib/include/irritator/ext.hpp @@ -110,7 +110,7 @@ class small_function Ret operator()(Params... args) noexcept { - debug::ensure(invoker && "Bad small_function call"); + debug::ensure(invoker); return invoker(&data, std::forward(args)...); } @@ -189,7 +189,7 @@ class function_ref Ret operator()(Params... params) const { - debug::ensure(callable && "Bad function_ref call"); + debug::ensure(callable); return callback(callable, std::forward(params)...); } @@ -199,7 +199,9 @@ class function_ref //! @brief A helper container to store Identifier -> T relation. //! @tparam Identifier Any integer or enum type. //! @tparam T Any type (trivial or not). -template +template> requires(std::three_way_comparable) class table { @@ -208,6 +210,13 @@ class table value_type() noexcept = default; value_type(Identifier id, const T& value) noexcept; + template + value_type(std::is_constructible id_, + const T& value_) noexcept + : id{ id_ } + , value{ value_ } + {} + Identifier id; T value; @@ -216,7 +225,7 @@ class table auto operator<=>(const Identifier& other) const { return id <=> other; } }; - using container_type = vector; + using container_type = vector; using size_type = typename container_type::size_type; using iterator = typename container_type::iterator; using const_iterator = typename container_type::const_iterator; @@ -233,8 +242,15 @@ class table constexpr void set(Identifier id, const T& value) noexcept; constexpr T* get(Identifier id) noexcept; constexpr const T* get(Identifier id) const noexcept; - constexpr void erase(Identifier id) noexcept; - constexpr void sort() noexcept; + + template + constexpr T* get(U id) noexcept; + + template + constexpr const T* get(U id) const noexcept; + + constexpr void erase(Identifier id) noexcept; + constexpr void sort() noexcept; constexpr unsigned size() const noexcept; constexpr int ssize() const noexcept; @@ -348,18 +364,18 @@ inline void string_buffer::do_alloc() noexcept * ****************************************************************************/ -template +template requires(std::three_way_comparable) -table::value_type::value_type(Identifier id_, - const T& value_) noexcept +table::value_type::value_type(Identifier id_, + const T& value_) noexcept : id(id_) , value(value_) {} -template +template requires(std::three_way_comparable) -constexpr void table::set(const Identifier id, - const T& value) noexcept +constexpr void table::set(const Identifier id, + const T& value) noexcept { if (auto* value_found = get(id); value_found) { *value_found = value; @@ -369,9 +385,9 @@ constexpr void table::set(const Identifier id, } } -template +template requires(std::three_way_comparable) -constexpr T* table::get(Identifier id) noexcept +constexpr T* table::get(Identifier id) noexcept { auto it = binary_find( data.begin(), data.end(), id, [](auto left, auto right) noexcept -> bool { @@ -384,9 +400,9 @@ constexpr T* table::get(Identifier id) noexcept return it == data.end() ? nullptr : &it->value; } -template +template requires(std::three_way_comparable) -constexpr const T* table::get(Identifier id) const noexcept +constexpr const T* table::get(Identifier id) const noexcept { auto it = binary_find( data.begin(), data.end(), id, [](auto left, auto right) noexcept -> bool { @@ -399,14 +415,46 @@ constexpr const T* table::get(Identifier id) const noexcept return it == data.end() ? nullptr : &it->value; } -template +template requires(std::three_way_comparable) -constexpr void table::erase(Identifier id) noexcept +template +constexpr T* table::get(U id) noexcept +{ + auto it = binary_find( + data.begin(), data.end(), id, [](auto left, auto right) noexcept -> bool { + if constexpr (std::is_same_v) + return left.id < right; + else + return left < right.id.sv(); + }); + + return it == data.end() ? nullptr : &it->value; +} + +template + requires(std::three_way_comparable) +template +constexpr const T* table::get(U id) const noexcept +{ + auto it = binary_find( + data.begin(), data.end(), id, [](auto left, auto right) noexcept -> bool { + if constexpr (std::is_same_v) + return left.id < right; + else + return left < right.id.sv(); + }); + + return it == data.end() ? nullptr : &it->value; +} + +template + requires(std::three_way_comparable) +constexpr void table::erase(Identifier id) noexcept { auto it = binary_find( data.begin(), data.end(), id, [](auto left, auto right) noexcept -> bool { if constexpr (std::is_same_v) - return left < right.id; + return left < right.id.sv(); else return left.id < right; }); @@ -417,9 +465,9 @@ constexpr void table::erase(Identifier id) noexcept } } -template +template requires(std::three_way_comparable) -constexpr void table::sort() noexcept +constexpr void table::sort() noexcept { if (data.size() > 1) std::sort(data.begin(), @@ -429,16 +477,16 @@ constexpr void table::sort() noexcept }); } -template +template requires(std::three_way_comparable) -constexpr unsigned table::size() const noexcept +constexpr unsigned table::size() const noexcept { return data.size(); } -template +template requires(std::three_way_comparable) -constexpr int table::ssize() const noexcept +constexpr int table::ssize() const noexcept { return data.ssize(); } diff --git a/lib/include/irritator/macros.hpp b/lib/include/irritator/macros.hpp index dad68634..3e41fe8e 100644 --- a/lib/include/irritator/macros.hpp +++ b/lib/include/irritator/macros.hpp @@ -104,7 +104,7 @@ irt_force_inline_attribute constexpr void ensure( //! and only if @c NDEBUG is not defined and @c IRRITATOR_ENABLE_DEBUG is //! defined. This function can be use with the @c on_error_callback to stop the //! application when a @c new_error function is called. - void breakpoint() noexcept; +void breakpoint() noexcept; } // namespace debug diff --git a/lib/include/irritator/modeling.hpp b/lib/include/irritator/modeling.hpp index 67b83891..f4423e18 100644 --- a/lib/include/irritator/modeling.hpp +++ b/lib/include/irritator/modeling.hpp @@ -151,8 +151,8 @@ struct child { component_id compo_id; } id; - child_type type = child_type::model; - bitflags flags = child_flags::none; + child_type type{ child_type::model }; + bitflags flags{ child_flags::none }; }; struct position { @@ -606,8 +606,8 @@ class graph_component small_world_param small; }; - id_array nodes; - id_array edges; + id_array> nodes; + id_array> edges; vector node_names; vector node_ids; @@ -697,8 +697,16 @@ class graph_component struct component { component() noexcept; - id_data_array x; - id_data_array y; + id_data_array, + port_str, + position> + x; + id_data_array, + port_str, + position> + y; port_id get_x(std::string_view str) const noexcept { @@ -808,8 +816,8 @@ struct registred_path { configuration file. */ vector children; - state status = state::unread; - bitflags flags = reg_flags::none; + state status = state::unread; + bitflags flags{ reg_flags::none }; i8 priority = 0; spin_mutex mutex; }; @@ -839,7 +847,7 @@ class dir_path vector children; state status = state::unread; - bitflags flags = dir_flags::none; + bitflags flags{ dir_flags::none }; spin_mutex mutex; /** @@ -881,7 +889,7 @@ struct file_path { file_type type{ file_type::undefined_file }; state status = state::unread; - bitflags flags = file_flags::none; + bitflags flags{ file_flags::none }; spin_mutex mutex; }; @@ -1201,8 +1209,10 @@ struct log_entry { class log_manager { public: - constexpr log_manager(constrained_value value = 8) - : m_data(value.value()) + using value_p = constrained_value; + + constexpr log_manager(const value_p v) + : m_data(v.value()) {} log_manager(const log_manager& other) noexcept = delete; @@ -1299,7 +1309,7 @@ class modeling * description is the same than the component except the extension ".desc". * @attention The size of the buffer is static for now. */ id_data_array, description_str, description_status> descriptions; @@ -1591,7 +1601,8 @@ class project }; project() noexcept - : sim{ simulation_memory_requirement{ 1024 * 1024 * 8 } } + : sim{ simulation_memory_requirement(1024 * 1024 * 8), + irt::external_source_memory_requirement{} } {} status init(const modeling_initializer& init) noexcept; @@ -1705,7 +1716,7 @@ class project file_observers file_obs; id_data_array, name_str, tree_node_id, model_id, diff --git a/lib/src/dot-parser.cpp b/lib/src/dot-parser.cpp index 86140906..ef0ece15 100644 --- a/lib/src/dot-parser.cpp +++ b/lib/src/dot-parser.cpp @@ -263,15 +263,15 @@ class input_stream_buffer using token_ring_t = irt::small_ring_buffer; - irt::id_array strings_ids; - irt::vector strings; + irt::id_array strings_ids; + irt::vector strings; token_ring_t tokens; std::istream& is; irt::i64 line = 0; - irt::id_array nodes; - irt::id_array edges; + irt::id_array nodes; + irt::id_array edges; irt::vector node_names; irt::vector node_ids; diff --git a/lib/src/dot-parser.hpp b/lib/src/dot-parser.hpp index 46ee2dc7..ee33c0e9 100644 --- a/lib/src/dot-parser.hpp +++ b/lib/src/dot-parser.hpp @@ -12,8 +12,8 @@ namespace irt { struct dot_graph { - id_array nodes; - id_array edges; + id_array nodes; + id_array edges; vector node_names; vector node_ids; diff --git a/lib/src/grid-observer.cpp b/lib/src/grid-observer.cpp index 2cc2a8df..7f7fa3f0 100644 --- a/lib/src/grid-observer.cpp +++ b/lib/src/grid-observer.cpp @@ -25,11 +25,15 @@ static auto init_or_reuse_observer(simulation& sim, const auto time_step = std::clamp( obs->time_step, std::numeric_limits::epsilon(), 0.01f); - obs->init(raw_buffer_size, linerized_buffer_size, time_step); + obs->init(observer::buffer_size_t(raw_buffer_size), + observer::linearized_buffer_size_t(linerized_buffer_size), + time_step); sim.observe(mdl, *obs); } else { auto& new_obs = sim.observers.alloc(); - new_obs.init(16, 32, 0.01f); + new_obs.init(observer::buffer_size_t(16), + observer::linearized_buffer_size_t(32), + 0.01f); mdl.obs_id = sim.observers.get_id(new_obs); sim.observe(mdl, new_obs); } diff --git a/lib/src/json.cpp b/lib/src/json.cpp index 36523706..aad3c989 100644 --- a/lib/src/json.cpp +++ b/lib/src/json.cpp @@ -3881,10 +3881,11 @@ struct json_dearchiver::impl { report_json_error(error_id::missing_component_type); } - bool read_port( - const rapidjson::Value& val, - id_data_array& - port) noexcept + bool read_port(const rapidjson::Value& val, + id_data_array, + port_str, + position>& port) noexcept { port_str port_name; double x = 0, y = 0; @@ -3914,10 +3915,11 @@ struct json_dearchiver::impl { return true; } - bool read_ports( - const rapidjson::Value& val, - id_data_array& - port) noexcept + bool read_ports(const rapidjson::Value& val, + id_data_array, + port_str, + position>& port) noexcept { auto_stack s(this, stack_id::component_ports); diff --git a/lib/src/memory-resource.cpp b/lib/src/memory-resource.cpp index 778bc941..31948786 100644 --- a/lib/src/memory-resource.cpp +++ b/lib/src/memory-resource.cpp @@ -4,34 +4,29 @@ #include -#include - -#if defined(_MSC_VER) -#include -#endif +#include +#include +#include namespace irt { struct human_readable_length_t { - human_readable_length_t(double size_, std::string_view type_) noexcept + constexpr human_readable_length_t(double size_, + std::string_view type_) noexcept : size(size_) , type(type_) {} - friend std::ostream& operator<<(std::ostream& os, - const human_readable_length_t& hr) noexcept - { - return os << hr.size << ' ' << hr.type; - } - double size; std::string_view type; }; -/** Print a human readable version of number of bytes. It shows xxx bytes, xxx - * mb, xxx gb etc. using the std::fprintf stream. */ -static auto make_human_readable_bytes(const std::size_t bytes) noexcept - -> human_readable_length_t +/** + Print a human readable version of number of bytes. It shows xxx B, xxx + MB, xxx GB etc. using the std::fprintf stream. + */ +static constexpr auto make_human_readable_bytes( + const std::size_t bytes) noexcept -> human_readable_length_t { const auto b = static_cast(bytes); const auto kb = b / 1024.0; @@ -48,455 +43,297 @@ static auto make_human_readable_bytes(const std::size_t bytes) noexcept return human_readable_length_t(b, "B"); } -constexpr inline bool is_alignment(std::size_t value) noexcept -{ - return (value > 0) && ((value & (value - 1)) == 0); -} - -#if defined(_MSC_VER) -void* malloc_memory_resource_allocate_win32(std::size_t bytes, - std::size_t alignment) noexcept -{ - debug::ensure(is_alignment(alignment)); - debug::ensure((bytes % alignment) == 0); - - using fn = void* (*)(std::size_t, std::size_t) noexcept; - fn call = reinterpret_cast(::_aligned_malloc); - - return call(bytes, alignment); -} -#elif defined(__APPLE__) -void* malloc_memory_resource_allocate_apple(std::size_t bytes, - std::size_t alignment) noexcept -{ - alignment = alignment < sizeof(void*) ? sizeof(void*) : alignment; - - debug::ensure(is_alignment(alignment)); - - void* p; - if (auto ret = ::posix_memalign(&p, alignment, bytes); ret != 0) { - p = nullptr; - - if (ret == EINVAL) - std::fprintf(stderr, - "The value of the alignment parameter is not a power " - "of two or a multiple of sizeof(void *).\n"); - if (ret == ENOMEM) - std::fprintf(stderr, - "There is insufficient memory available with the " - "requested alignment.\n"); - } - - return p; -} -#else -void* malloc_memory_resource_allocate_posix(std::size_t bytes, - std::size_t alignment) noexcept -{ - debug::ensure(is_alignment(alignment)); - debug::ensure((bytes % alignment) == 0); - - using fn = void* (*)(std::size_t, std::size_t) noexcept; - fn call = reinterpret_cast(std::aligned_alloc); +} // namespace irt - return call(alignment, bytes); -} -#endif +template<> +struct fmt::formatter<::irt::human_readable_length_t> { -void* malloc_memory_resource::do_allocate(std::size_t bytes, - std::size_t alignment) noexcept -{ - debug::mem_log("malloc_memory_resource::need-allocate [", - make_human_readable_bytes(bytes), - " ", - alignment, - "]\n"); - -#if defined(_MSC_VER) - auto* p = malloc_memory_resource_allocate_win32(bytes, alignment); -#elif defined(__APPLE__) - auto* p = malloc_memory_resource_allocate_apple(bytes, alignment); -#else - auto* p = malloc_memory_resource_allocate_posix(bytes, alignment); -#endif - - if (not p) { - debug::log("Irritator shutdown: Unable to allocate memory ", - make_human_readable_bytes(bytes), - " alignment ", - alignment, - "\n"); - std::abort(); + constexpr auto parse(format_parse_context& ctx) noexcept + -> format_parse_context::iterator + { + return ctx.begin(); } - debug::log("malloc_memory_resource::allocate [", - p, - " ", - make_human_readable_bytes(bytes), - " ", - alignment, - "]\n"); - return p; -} - -void malloc_memory_resource::do_deallocate( - void* pointer, - [[maybe_unused]] std::size_t bytes, - [[maybe_unused]] std::size_t alignment) noexcept -{ - debug::mem_log("malloc_memory_resource::do_deallocate [", - pointer, - " ", - make_human_readable_bytes(bytes), - " ", - alignment, - "]\n"); - -#if defined(_WIN32) - if (pointer) - ::_aligned_free(pointer); -#else - if (pointer) - std::free(pointer); -#endif -} - -fixed_linear_memory_resource::fixed_linear_memory_resource( - std::byte* data, - std::size_t size) noexcept - : m_start{ data } - , m_total_size{ size } -{ - debug::ensure(m_start); - debug::ensure(m_total_size); -} - -void* fixed_linear_memory_resource::allocate(size_t bytes, - size_t alignment) noexcept -{ - std::size_t padding = 0; - - const auto current_address = - reinterpret_cast(m_start) + m_offset; - - if (alignment != 0 && m_offset % alignment != 0) - padding = calculate_padding(current_address, alignment); - - if (m_offset + padding + bytes > m_total_size) { - std::abort(); + auto format(const ::irt::human_readable_length_t& hr, + format_context& ctx) const noexcept -> format_context::iterator + { + return format_to(ctx.out(), "{}{}", hr.size, hr.type); } +}; - m_offset += padding; - const auto next_address = current_address + padding; - m_offset += bytes; - - return reinterpret_cast(next_address); -} - -void fixed_linear_memory_resource::destroy() noexcept -{ - m_start = nullptr; - m_total_size = 0; - m_offset = 0; -} - -void fixed_linear_memory_resource::reset() noexcept { m_offset = { 0 }; } - -void fixed_linear_memory_resource::reset(std::byte* data, - std::size_t size) noexcept -{ - debug::ensure(data != nullptr); - debug::ensure(size != 0u); - debug::ensure(m_start == nullptr); - debug::ensure(m_total_size == 0u); - - m_start = data; - m_total_size = size; - - reset(); -} +namespace irt { -bool fixed_linear_memory_resource::can_alloc(std::size_t bytes, - std::size_t alignment) noexcept +void* new_delete_memory_resource::data::debug_allocate( + std::size_t bytes, + std::size_t alignment) noexcept { - std::size_t padding = 0; + fmt::print(debug::mem_file(), + "new-delete::allocate {},{} {},{}\n", + make_human_readable_bytes(bytes), + make_human_readable_bytes(alignment), + make_human_readable_bytes(allocated), + make_human_readable_bytes(deallocated)); - const auto current_address = - reinterpret_cast(m_start) + m_offset; + auto ptr = std::pmr::new_delete_resource()->allocate(bytes, alignment); + if (ptr) + allocated += bytes; - if (alignment != 0 && m_offset % alignment != 0) - padding = calculate_padding(current_address, alignment); + fmt::print(debug::mem_file(), + " {},{} {},{} = {}\n", + make_human_readable_bytes(bytes), + make_human_readable_bytes(alignment), + make_human_readable_bytes(allocated), + make_human_readable_bytes(deallocated), + ptr); - return m_offset + padding + bytes <= m_total_size; + return ptr; } -pool_memory_resource::pool_memory_resource(std::byte* data, - std::size_t size, - std::size_t chunk_size) noexcept - : m_start_ptr{ data } - , m_total_size{ size } - , m_chunk_size{ chunk_size } - , m_total_allocated{ 0 } +void new_delete_memory_resource::data::debug_deallocate( + void* ptr, + std::size_t bytes, + std::size_t alignment) noexcept { - debug::ensure(chunk_size >= std::alignment_of_v); - debug::ensure(size % chunk_size == 0); + fmt::print(debug::mem_file(), + "new-delete::deallocate {},{} {},{} {}\n", + make_human_readable_bytes(bytes), + make_human_readable_bytes(alignment), + make_human_readable_bytes(allocated), + make_human_readable_bytes(deallocated), + ptr); + + if (ptr) { + deallocated += bytes; + std::pmr::new_delete_resource()->deallocate(ptr, bytes, alignment); + } - reset(); + fmt::print(debug::mem_file(), + " {},{} {},{}\n", + make_human_readable_bytes(bytes), + make_human_readable_bytes(alignment), + make_human_readable_bytes(allocated), + make_human_readable_bytes(deallocated)); } -void* pool_memory_resource::allocate(size_t bytes, - size_t /*alignment*/) noexcept +template +void* synchronized_pool_resource::data:: + debug_allocate(std::size_t bytes, std::size_t alignment) noexcept { - debug::ensure(bytes == m_chunk_size && - "Allocation size must be equal to chunk size"); + fmt::print(debug::mem_file(), + "sync-pools::allocate {},{} {},{}\n", + make_human_readable_bytes(bytes), + make_human_readable_bytes(alignment), + make_human_readable_bytes(allocated), + make_human_readable_bytes(deallocated)); - node* free_position = m_free_list.pop(); - m_total_allocated += m_chunk_size; + auto ptr = mr.allocate(bytes, alignment); + if (ptr) + allocated += bytes; - if (free_position == nullptr) - std::abort(); + fmt::print(debug::mem_file(), + " {},{} {},{} = {}\n", + make_human_readable_bytes(bytes), + make_human_readable_bytes(alignment), + make_human_readable_bytes(allocated), + make_human_readable_bytes(deallocated), + ptr); - return reinterpret_cast(free_position); + return ptr; } -void pool_memory_resource::deallocate(void* p, - size_t /*bytes*/, - size_t /*alignment*/) noexcept +template +void synchronized_pool_resource::data:: + debug_deallocate(void* ptr, std::size_t bytes, std::size_t alignment) noexcept { - m_total_allocated -= m_chunk_size; - m_free_list.push(reinterpret_cast(p)); -} - -void pool_memory_resource::reset() noexcept -{ - const auto start = reinterpret_cast(m_start_ptr); - - for (auto n = m_total_size / m_chunk_size; n > 0; --n) { - auto address = start + ((n - 1) * m_chunk_size); - m_free_list.push(reinterpret_cast(address)); + fmt::print(debug::mem_file(), + "sync-pools::deallocate {},{} {},{} {}\n", + make_human_readable_bytes(bytes), + make_human_readable_bytes(alignment), + make_human_readable_bytes(allocated), + make_human_readable_bytes(deallocated), + ptr); + + if (ptr) { + deallocated += bytes; + mr.deallocate(ptr, bytes, alignment); } -} -void pool_memory_resource::reset(std::byte* data, - std::size_t size, - std::size_t chunk_size) noexcept -{ - debug::ensure(m_start_ptr == nullptr); - debug::ensure(m_total_size == 0u); - debug::ensure(data); - debug::ensure(chunk_size >= std::alignment_of_v); - debug::ensure(size % chunk_size == 0); - - m_start_ptr = data; - m_total_size = size; - m_chunk_size = chunk_size; - m_total_allocated = 0; - - reset(); + fmt::print(debug::mem_file(), + " {},{} {},{}\n", + make_human_readable_bytes(bytes), + make_human_readable_bytes(alignment), + make_human_readable_bytes(allocated), + make_human_readable_bytes(deallocated)); } -bool pool_memory_resource::can_alloc(std::size_t bytes, - std::size_t /*alignment*/) noexcept +template +void* unsynchronized_pool_resource::data:: + debug_allocate(std::size_t bytes, std::size_t alignment) noexcept { - debug::ensure((bytes % m_chunk_size) == 0 && - "Allocation size must be equal to chunk size"); + fmt::print(debug::mem_file(), + "unsync-pools::allocate {},{} {},{}\n", + make_human_readable_bytes(bytes), + make_human_readable_bytes(alignment), + make_human_readable_bytes(allocated), + make_human_readable_bytes(deallocated)); - return (m_total_size - m_total_allocated) > bytes; -} + auto ptr = mr.allocate(bytes, alignment); + if (ptr) + allocated += bytes; -freelist_memory_resource::freelist_memory_resource(std::byte* data, - std::size_t size) noexcept - : m_start_ptr{ data } - , m_total_size{ size } -{ - reset(); + fmt::print(debug::mem_file(), + " {},{} {},{} = {}\n", + make_human_readable_bytes(bytes), + make_human_readable_bytes(alignment), + make_human_readable_bytes(allocated), + make_human_readable_bytes(deallocated), + ptr); + + return ptr; } -void* freelist_memory_resource::allocate(size_t size, size_t alignment) noexcept +template +void unsynchronized_pool_resource::data:: + debug_deallocate(void* ptr, std::size_t bytes, std::size_t alignment) noexcept { - // debug::ensure("Allocation size must be bigger" && size >= - // sizeof(Node)); debug::ensure("Alignment must be 8 at least" && - // alignment >= 8); - - auto found = find_policy::find_first == m_find_policy - ? find_first(size, alignment) - : find_best(size, alignment); - - if (found.allocated == nullptr) - std::abort(); - - const auto alignmentPadding = found.padding - allocation_header_size; - const auto requiredSize = size + found.padding; - const auto rest = found.allocated->data.block_size - requiredSize; - - if (rest > 0) { - node* newFreeNode = - (node*)((std::size_t)found.allocated + requiredSize); - newFreeNode->data.block_size = rest; - m_freeList.insert(found.allocated, newFreeNode); + fmt::print(debug::mem_file(), + "unsync-pools::deallocate {},{} {},{} {}\n", + make_human_readable_bytes(bytes), + make_human_readable_bytes(alignment), + make_human_readable_bytes(allocated), + make_human_readable_bytes(deallocated), + ptr); + + if (ptr) { + deallocated += bytes; + mr.deallocate(ptr, bytes, alignment); } - m_freeList.remove(found.previous, found.allocated); - - const std::size_t headerAddress = - (std::size_t)found.allocated + alignmentPadding; - const std::size_t dataAddress = headerAddress + allocation_header_size; - ((freelist_memory_resource::AllocationHeader*)headerAddress)->block_size = - requiredSize; - ((freelist_memory_resource::AllocationHeader*)headerAddress)->padding = - static_cast(alignmentPadding); - - m_used += requiredSize; - m_peak = std::max(m_peak, m_used); - - return (void*)dataAddress; + fmt::print(debug::mem_file(), + " {},{} {},{}\n", + make_human_readable_bytes(bytes), + make_human_readable_bytes(alignment), + make_human_readable_bytes(allocated), + make_human_readable_bytes(deallocated)); } -void freelist_memory_resource::deallocate(void* ptr, - size_t /*bytes*/, - size_t /*alignment*/) noexcept +template +void* monotonic_small_buffer::data::debug_allocate( + std::size_t bytes, + std::size_t alignment) noexcept { - const auto currentAddress = (std::size_t)ptr; - const auto headerAddress = currentAddress - allocation_header_size; - - const freelist_memory_resource::AllocationHeader* allocationHeader{ ( - freelist_memory_resource::AllocationHeader*)headerAddress }; - - node* freeNode = (node*)(headerAddress); - freeNode->data.block_size = - allocationHeader->block_size + allocationHeader->padding; - freeNode->next = nullptr; - - node* it = m_freeList.head; - node* prev = nullptr; - while (it != nullptr) { - if (ptr < it) { - m_freeList.insert(prev, freeNode); - break; - } - prev = it; - it = it->next; - } + fmt::print(debug::mem_file(), + "mono-small-size-{}::allocate {},{} {},{}\n", + id, + make_human_readable_bytes(bytes), + make_human_readable_bytes(alignment), + make_human_readable_bytes(allocated), + make_human_readable_bytes(deallocated)); - m_used -= freeNode->data.block_size; + auto ptr = mr.allocate(bytes, alignment); + if (ptr) + allocated += bytes; - merge(prev, freeNode); -} + fmt::print(debug::mem_file(), + " {},{} {},{} = {}\n", + make_human_readable_bytes(bytes), + make_human_readable_bytes(alignment), + make_human_readable_bytes(allocated), + make_human_readable_bytes(deallocated), + ptr); -void freelist_memory_resource::destroy() noexcept -{ - m_start_ptr = nullptr; - m_total_size = 0; - m_used = 0; - m_peak = 0; - m_find_policy = find_policy::find_first; + return ptr; } -void freelist_memory_resource::reset() noexcept +template +void monotonic_small_buffer::data::debug_deallocate( + void* ptr, + std::size_t bytes, + std::size_t alignment) noexcept { - m_used = 0u; - m_peak = 0u; - - if (not m_start_ptr) { - destroy(); - } else { - node* first = reinterpret_cast(m_start_ptr); - first->data.block_size = m_total_size; - first->next = nullptr; - - m_freeList.head = nullptr; - m_freeList.insert(nullptr, first); + fmt::print(debug::mem_file(), + "mono-small-size-{}::deallocate {},{} {},{} {}\n", + id, + make_human_readable_bytes(bytes), + make_human_readable_bytes(alignment), + make_human_readable_bytes(allocated), + make_human_readable_bytes(deallocated), + ptr); + + if (ptr) { + deallocated += bytes; + mr.deallocate(ptr, bytes, alignment); } -} - -void freelist_memory_resource::reset(std::byte* data, std::size_t size) noexcept -{ - debug::ensure(data != nullptr); - debug::ensure(size != 0u); - - if (data == nullptr or size == 0) - return; - - destroy(); - m_start_ptr = data; - m_total_size = size; - - node* first = reinterpret_cast(m_start_ptr); - first->data.block_size = m_total_size; - first->next = nullptr; - - m_freeList.head = nullptr; - m_freeList.insert(nullptr, first); + fmt::print(debug::mem_file(), + " {},{} {},{}\n", + make_human_readable_bytes(bytes), + make_human_readable_bytes(alignment), + make_human_readable_bytes(allocated), + make_human_readable_bytes(deallocated)); } -void freelist_memory_resource::merge(node* previous, node* free_node) noexcept +template +void* monotonic_buffer::data::debug_allocate(std::size_t bytes, + std::size_t alignment) noexcept { - if (free_node->next != nullptr && - (std::size_t)free_node + free_node->data.block_size == - (std::size_t)free_node->next) { - free_node->data.block_size += free_node->next->data.block_size; - m_freeList.remove(free_node, free_node->next); - } + fmt::print(debug::mem_file(), + "mono-size-{}::allocate {},{} {},{}\n", + id, + make_human_readable_bytes(bytes), + make_human_readable_bytes(alignment), + make_human_readable_bytes(allocated), + make_human_readable_bytes(deallocated)); - if (previous != nullptr && - (std::size_t)previous + previous->data.block_size == - (std::size_t)free_node) { - previous->data.block_size += free_node->data.block_size; - m_freeList.remove(previous, free_node); - } -} + auto ptr = mr.allocate(bytes, alignment); + if (ptr) + allocated += bytes; -auto freelist_memory_resource::find_best( - const std::size_t size, - const std::size_t alignment) const noexcept -> find_t -{ - node* best = nullptr; - node* it = m_freeList.head; - node* prev = nullptr; - std::size_t best_padding = 0; - std::size_t diff = std::numeric_limits::max(); - - while (it != nullptr) { - const auto padding = calculate_padding_with_header( - (std::size_t)it, alignment, allocation_header_size); - - const std::size_t required = size + padding; - if (it->data.block_size >= required && - (it->data.block_size - required < diff)) { - best = it; - best_padding = padding; - diff = it->data.block_size - required; - } - - prev = it; - it = it->next; - } + fmt::print(debug::mem_file(), + " {},{} {},{} = {}\n", + make_human_readable_bytes(bytes), + make_human_readable_bytes(alignment), + make_human_readable_bytes(allocated), + make_human_readable_bytes(deallocated), + ptr); - return { prev, best, best_padding }; + return ptr; } -auto freelist_memory_resource::find_first( - const std::size_t size, - const std::size_t alignment) const noexcept -> find_t +template +void monotonic_buffer::data::debug_deallocate( + void* ptr, + std::size_t bytes, + std::size_t alignment) noexcept { - node* it = m_freeList.head; - node* prev = nullptr; - std::size_t padding = 0; - - while (it != nullptr) { - padding = calculate_padding_with_header( - (std::size_t)it, alignment, allocation_header_size); - - const std::size_t requiredSpace = size + padding; - if (it->data.block_size >= requiredSpace) - break; - - prev = it; - it = it->next; + fmt::print(debug::mem_file(), + "mono-size-{}::deallocate {},{} {},{} {}\n", + id, + make_human_readable_bytes(bytes), + make_human_readable_bytes(alignment), + make_human_readable_bytes(allocated), + make_human_readable_bytes(deallocated), + ptr); + + if (ptr) { + deallocated += bytes; + mr.deallocate(ptr, bytes, alignment); } - return { prev, it, padding }; + fmt::print(debug::mem_file(), + " {},{} {},{}\n", + make_human_readable_bytes(bytes), + make_human_readable_bytes(alignment), + make_human_readable_bytes(allocated), + make_human_readable_bytes(deallocated)); } } // namespace irt diff --git a/lib/src/modeling-generic.cpp b/lib/src/modeling-generic.cpp index c7690f42..02f45f40 100644 --- a/lib/src/modeling-generic.cpp +++ b/lib/src/modeling-generic.cpp @@ -245,7 +245,7 @@ status generic_component::import( children_names[dst_idx] = exists_child(names[src_idx].sv()) ? make_unique_name_id(pair.value) - : names[src_idx].sv(); + : names[src_idx]; } } } diff --git a/lib/src/modeling-internal.cpp b/lib/src/modeling-internal.cpp index ce56edf6..09b0f3bc 100644 --- a/lib/src/modeling-internal.cpp +++ b/lib/src/modeling-internal.cpp @@ -2,7 +2,6 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#include "irritator/core.hpp" #include namespace irt { @@ -10,8 +9,9 @@ namespace irt { template static child_id alloc(modeling& mod, generic_component& parent, - const std::string_view name = {}, - bitflags param = child_flags::none) noexcept + const std::string_view name = {}, + bitflags param = + bitflags(child_flags::none)) noexcept { auto& child = mod.alloc(parent, dynamics_typeof()); const auto id = parent.children.get_id(child); diff --git a/lib/src/modeling.cpp b/lib/src/modeling.cpp index dfaeb878..0e30ee2b 100644 --- a/lib/src/modeling.cpp +++ b/lib/src/modeling.cpp @@ -19,7 +19,7 @@ namespace irt { modeling::modeling() noexcept - : log_entries{ 16 } + : log_entries(log_manager::value_p(16)) {} status modeling::init(modeling_initializer& p) noexcept diff --git a/lib/src/project.cpp b/lib/src/project.cpp index dfe611bc..e5d5b1bb 100644 --- a/lib/src/project.cpp +++ b/lib/src/project.cpp @@ -448,7 +448,8 @@ static auto make_tree_leaf(simulation_copy& sc, if (is_public) { debug::ensure(not uid.empty()); - parent.unique_id_to_model_id.data.emplace_back(uid, new_mdl_id); + parent.unique_id_to_model_id.data.emplace_back(name_str(uid), + new_mdl_id); } return new_mdl_id; @@ -682,21 +683,24 @@ static auto make_tree_recursive(simulation_copy& sc, auto s_id = compo.id.generic_id; if (auto* s = sc.mod.generic_components.try_to_get(s_id); s) irt_check(make_tree_recursive(sc, new_tree, *s)); - parent.unique_id_to_tree_node_id.data.emplace_back(unique_id, tn_id); + parent.unique_id_to_tree_node_id.data.emplace_back(name_str(unique_id), + tn_id); } break; case component_type::grid: { auto g_id = compo.id.grid_id; if (auto* g = sc.mod.grid_components.try_to_get(g_id); g) irt_check(make_tree_recursive(sc, new_tree, *g)); - parent.unique_id_to_tree_node_id.data.emplace_back(unique_id, tn_id); + parent.unique_id_to_tree_node_id.data.emplace_back(name_str(unique_id), + tn_id); } break; case component_type::graph: { auto g_id = compo.id.graph_id; if (auto* g = sc.mod.graph_components.try_to_get(g_id); g) irt_check(make_tree_recursive(sc, new_tree, *g)); - parent.unique_id_to_tree_node_id.data.emplace_back(unique_id, tn_id); + parent.unique_id_to_tree_node_id.data.emplace_back(name_str(unique_id), + tn_id); } break; case component_type::internal: @@ -1308,14 +1312,11 @@ status project::set(modeling& mod, component& compo) noexcept irt_check(make_component_cache(*this, mod)); - simulation_memory_requirement smr(numbers.model_nb, numbers.hsm_nb); + simulation_memory_requirement smr(numbers.model_nb); + // smr.hsms = std::max(numbers.hsm_nb, smr.hsms); + smr.hsms = numbers.hsm_nb; sim.destroy(); - - if (smr.global_b < 1024u * 1024u * 8u) { - sim.realloc(simulation_memory_requirement(1024u * 1024u * 8u)); - } else { - sim.realloc(smr); - } + sim.realloc(smr, external_source_memory_requirement{}); simulation_copy sc(*this, mod, tree_nodes); @@ -1344,6 +1345,9 @@ status project::rebuild(modeling& mod) noexcept void project::clear() noexcept { + name.clear(); + sim.clear(); + tree_nodes.clear(); m_head = undefined(); diff --git a/lib/src/variable-observer.cpp b/lib/src/variable-observer.cpp index 95581460..614f443b 100644 --- a/lib/src/variable-observer.cpp +++ b/lib/src/variable-observer.cpp @@ -34,15 +34,18 @@ status variable_observer::init(project& pj, simulation& sim) noexcept if (obs) { obs_id = mdl->obs_id; - obs->init(raw_buffer_size.value(), - linearized_buffer_size.value(), + obs->init(observer::buffer_size_t(raw_buffer_size.value()), + observer::linearized_buffer_size_t( + linearized_buffer_size.value()), time_step.value()); } else { if (sim.observers.can_alloc()) { auto& new_obs = sim.observers.alloc(); - new_obs.init(raw_buffer_size.value(), - linearized_buffer_size.value(), - time_step.value()); + new_obs.init( + observer::buffer_size_t(raw_buffer_size.value()), + observer::linearized_buffer_size_t( + linearized_buffer_size.value()), + time_step.value()); obs_id = sim.observers.get_id(new_obs); sim.observe(*mdl, new_obs); @@ -63,8 +66,8 @@ void variable_observer::clear() noexcept std::fill_n(m_obs_ids.data(), m_obs_ids.size(), undefined()); } -auto variable_observer::find(const tree_node_id tn, - const model_id mdl) noexcept -> sub_id +auto variable_observer::find(const tree_node_id tn, const model_id mdl) noexcept + -> sub_id { for (const auto id : m_ids) { const auto idx = get_index(id); diff --git a/lib/test/containers.cpp b/lib/test/containers.cpp index 1fb1a793..56c1af11 100644 --- a/lib/test/containers.cpp +++ b/lib/test/containers.cpp @@ -144,18 +144,50 @@ int main() { using namespace boost::ut; - "make-divisible"_test = [] { - expect(eq(irt::make_divisible_to(123u, 16u), 112u)); - expect(eq(irt::make_divisible_to(17l, 16u), 16l)); - expect(eq(irt::make_divisible_to(161llu, 16u), 160llu)); - expect(eq(irt::make_divisible_to(7, 16u), 0)); - expect(eq(irt::make_divisible_to(15, 16u), 0)); - - expect(eq(irt::make_divisible_to(123u, 8u), 120u)); - expect(eq(irt::make_divisible_to(17l, 8u), 16l)); - expect(eq(irt::make_divisible_to(161llu, 8u), 160llu)); - expect(eq(irt::make_divisible_to(7, 8u), 0)); - expect(eq(irt::make_divisible_to(15, 8u), 8)); + "allocator"_test = [] { + using a1 = irt::allocator>; + using a2 = irt::allocator>; + using b1 = irt::allocator>; + using b2 = irt::allocator>; + + using sub_1 = a1::memory_resource_type; + using sub_2 = a2::memory_resource_type; + using sub_3 = b1::memory_resource_type; + using sub_4 = b2::memory_resource_type; + + auto* ptr_2 = static_cast(&sub_2::instance()); + auto* ptr_3 = static_cast(&sub_3::instance()); + auto* ptr_4 = static_cast(&sub_4::instance()); + auto* ptr_1 = static_cast(&sub_1::instance()); + + expect(eq(ptr_1, ptr_2)); + expect(eq(ptr_3, ptr_4)); + expect(neq(ptr_1, ptr_3)); + expect(neq(ptr_1, ptr_4)); + expect(neq(ptr_2, ptr_3)); + expect(neq(ptr_2, ptr_4)); + + using id_a1 = irt::allocator>; + using id_a2 = irt::allocator>; + using id_b1 = irt::allocator>; + using id_b2 = irt::allocator>; + + using id_sub_1 = id_a1::memory_resource_type; + using id_sub_2 = id_a2::memory_resource_type; + using id_sub_3 = id_b1::memory_resource_type; + using id_sub_4 = id_b2::memory_resource_type; + + auto* id_ptr_2 = static_cast(&id_sub_2::instance()); + auto* id_ptr_3 = static_cast(&id_sub_3::instance()); + auto* id_ptr_4 = static_cast(&id_sub_4::instance()); + auto* id_ptr_1 = static_cast(&id_sub_1::instance()); + + expect(eq(id_ptr_1, id_ptr_2)); + expect(eq(id_ptr_3, id_ptr_4)); + expect(neq(id_ptr_1, id_ptr_3)); + expect(neq(id_ptr_1, id_ptr_4)); + expect(neq(id_ptr_2, id_ptr_3)); + expect(neq(id_ptr_2, id_ptr_4)); }; "small-vector"_test = [] { @@ -292,10 +324,9 @@ int main() }; "vector-default_allocator"_test = [] { - std::array buffer; - irt::fixed_linear_memory_resource mbr{ buffer.data(), buffer.size() }; + using fixed_alloc = irt::allocator>; - irt::vector v(&mbr, 8); + irt::vector v(8); expect(v.empty()); expect(v.capacity() == 8); v.emplace_back(0); @@ -339,7 +370,7 @@ int main() expect(v[4] == 4); expect(v[5] == 5); - irt::vector v2(&mbr, 8); + irt::vector v2(8); v2 = v; v2[0] *= 2; expect(v2[0] == 14); diff --git a/lib/test/dot-parser-test.cpp b/lib/test/dot-parser-test.cpp index b04ec3a2..f4a2f59a 100644 --- a/lib/test/dot-parser-test.cpp +++ b/lib/test/dot-parser-test.cpp @@ -6,13 +6,12 @@ #include -#include - using namespace std::literals; int main() { using namespace boost::ut; + using namespace std::literals::string_view_literals; #if defined(IRRITATOR_ENABLE_DEBUG) irt::on_error_callback = irt::debug::breakpoint; @@ -69,12 +68,12 @@ int main() const auto table = ret->make_toc(); expect(eq(table.ssize(), 4)); - expect(table.get("A") >> fatal); - expect(table.get("B") >> fatal); - expect(table.get("C") >> fatal); - const auto id_A = *table.get("A"); - const auto id_B = *table.get("B"); - const auto id_C = *table.get("C"); + expect(table.get("A"sv) >> fatal); + expect(table.get("B"sv) >> fatal); + expect(table.get("C"sv) >> fatal); + const auto id_A = *table.get("A"sv); + const auto id_B = *table.get("B"sv); + const auto id_C = *table.get("C"sv); const auto idx_A = irt::get_index(id_A); const auto idx_B = irt::get_index(id_B); const auto idx_C = irt::get_index(id_C); diff --git a/lib/test/public-api.cpp b/lib/test/public-api.cpp index 217908c3..a90ca238 100644 --- a/lib/test/public-api.cpp +++ b/lib/test/public-api.cpp @@ -1359,7 +1359,11 @@ int main() enum class ex1_id : uint32_t; - irt::id_data_array + irt::id_data_array, + pos3d, + color, + name> d; d.reserve(1024); expect(ge(d.capacity(), 1024u)); @@ -1645,7 +1649,7 @@ int main() "heap-middle-decrease"_test = [] { using namespace irt::literals; - irt::heap h; + irt::heap> h; expect(h.reserve(256u)); @@ -1709,7 +1713,7 @@ int main() }; "simulation-dispatch"_test = [] { - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); auto& dyn1 = sim.alloc(); (void)sim.alloc(); @@ -1735,7 +1739,7 @@ int main() irt::vector out; { - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); sim.alloc(); sim.alloc(); @@ -1810,7 +1814,7 @@ int main() } { - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); auto in = std::span(out.data(), out.size()); @@ -1823,7 +1827,7 @@ int main() "constant_simulation"_test = [] { irt::on_error_callback = irt::debug::breakpoint; fmt::print("constant_simulation\n"); - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(sim.can_alloc(3)); @@ -1849,7 +1853,7 @@ int main() "cross_simulation"_test = [] { fmt::print("cross_simulation\n"); - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(sim.can_alloc(3)); @@ -1953,7 +1957,7 @@ int main() }; "hsm_simulation"_test = [] { - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect((sim.can_alloc(3)) >> fatal); expect((sim.hsms.can_alloc(1)) >> fatal); @@ -1992,24 +1996,26 @@ int main() expect(sim.hsms.can_alloc()); expect(sim.models.can_alloc()); - auto& hsm = sim.alloc(); - auto* hsmw = sim.hsms.try_to_get(hsm.id); - expect((hsmw != nullptr) >> fatal); + auto& hsmw = sim.alloc(); + auto& hsm = sim.hsms.alloc(); + hsmw.id = sim.hsms.get_id(hsm); - expect(!!hsmw->set_state( + expect((sim.hsms.try_to_get(hsmw.id) != nullptr) >> fatal); + + expect(!!hsm.set_state( 0u, irt::hierarchical_state_machine::invalid_state_id, 1u)); - expect(!!hsmw->set_state(1u, 0u)); - hsmw->states[1u].condition.set(0b0011u, 0b0011u); - hsmw->states[1u].if_transition = 2u; + expect(!!hsm.set_state(1u, 0u)); + hsm.states[1u].condition.set(0b0011u, 0b0011u); + hsm.states[1u].if_transition = 2u; - expect(!!hsmw->set_state(2u, 0u)); - hsmw->states[2u].enter_action.set_output( + expect(!!hsm.set_state(2u, 0u)); + hsm.states[2u].enter_action.set_output( irt::hierarchical_state_machine::variable::port_0, 1.0f); - expect(!!sim.connect(gen, 0, hsm, 0)); - expect(!!sim.connect(gen, 0, hsm, 1)); - expect(!!sim.connect(hsm, 0, cnt, 0)); + expect(!!sim.connect(gen, 0, hsmw, 0)); + expect(!!sim.connect(gen, 0, hsmw, 1)); + expect(!!sim.connect(hsmw, 0, cnt, 0)); sim.t = 0.0; expect(!!sim.srcs.prepare()); @@ -2026,7 +2032,7 @@ int main() }; "hsm_enter_exit_simulation"_test = [] { - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect((sim.can_alloc(3)) >> fatal); expect((sim.hsms.can_alloc(1)) >> fatal); @@ -2063,29 +2069,29 @@ int main() expect(sim.hsms.can_alloc()); expect(sim.models.can_alloc()); - auto& hsm = sim.alloc(); - auto* hsmw = sim.hsms.try_to_get(hsm.id); - expect((hsmw != nullptr) >> fatal); + auto& hsmw = sim.alloc(); + hsmw.id = sim.hsms.get_id(sim.hsms.alloc()); + auto& hsm = sim.hsms.get(hsmw.id); - expect(!!hsmw->set_state( + expect(!!hsm.set_state( 0u, irt::hierarchical_state_machine::invalid_state_id, 1u)); - expect(!!hsmw->set_state(1u, 0u)); - hsmw->states[1u].enter_action.set_affect( + expect(!!hsm.set_state(1u, 0u)); + hsm.states[1u].enter_action.set_affect( irt::hierarchical_state_machine::variable::var_i1, 1.0f); - hsmw->states[1u].exit_action.set_plus( + hsm.states[1u].exit_action.set_plus( irt::hierarchical_state_machine::variable::var_i1, 10.0f); - hsmw->states[1u].condition.set(0b0011u, 0b0011u); - hsmw->states[1u].if_transition = 2u; + hsm.states[1u].condition.set(0b0011u, 0b0011u); + hsm.states[1u].if_transition = 2u; - expect(!!hsmw->set_state(2u, 0u)); - hsmw->states[2u].enter_action.set_output( + expect(!!hsm.set_state(2u, 0u)); + hsm.states[2u].enter_action.set_output( irt::hierarchical_state_machine::variable::port_0, 1.0f); - expect(!!sim.connect(gen, 0, hsm, 0)); - expect(!!sim.connect(gen, 0, hsm, 1)); - expect(!!sim.connect(hsm, 0, cnt, 0)); + expect(!!sim.connect(gen, 0, hsmw, 0)); + expect(!!sim.connect(gen, 0, hsmw, 1)); + expect(!!sim.connect(hsmw, 0, cnt, 0)); sim.t = 0.0; expect(!!sim.srcs.prepare()); @@ -2098,13 +2104,13 @@ int main() expect(!!st); } while (sim.t < 10); - expect(eq(hsm.exec.i1, 11)); + expect(eq(hsmw.exec.i1, 11)); expect(eq(cnt.number, static_cast(1))); }; "hsm_timer_simulation"_test = [] { - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect((sim.can_alloc(3)) >> fatal); expect((sim.hsms.can_alloc(1)) >> fatal); @@ -2120,30 +2126,30 @@ int main() expect(sim.hsms.can_alloc()); expect(sim.models.can_alloc()); - auto& hsm = sim.alloc(); - auto* hsmw = sim.hsms.try_to_get(hsm.id); - expect((hsmw != nullptr) >> fatal); + auto& hsmw = sim.alloc(); + auto& hsm = sim.hsms.alloc(); + hsmw.id = sim.hsms.get_id(hsm); - expect(!!hsmw->set_state( + expect(!!hsm.set_state( 0u, irt::hierarchical_state_machine::invalid_state_id, 1u)); - expect(!!hsmw->set_state(1u, 0u)); - hsmw->states[1u].condition.set(0b0011u, 0b0011u); - hsmw->states[1u].if_transition = 2u; + expect(!!hsm.set_state(1u, 0u)); + hsm.states[1u].condition.set(0b0011u, 0b0011u); + hsm.states[1u].if_transition = 2u; - expect(!!hsmw->set_state(2u, 0u)); - hsmw->states[2u].enter_action.set_affect( + expect(!!hsm.set_state(2u, 0u)); + hsm.states[2u].enter_action.set_affect( irt::hierarchical_state_machine::variable::var_timer, 10.f); - hsmw->states[2u].condition.set_timer(); - hsmw->states[2u].if_transition = 3u; + hsm.states[2u].condition.set_timer(); + hsm.states[2u].if_transition = 3u; - expect(!!hsmw->set_state(3u, 0u)); - hsmw->states[3u].enter_action.set_output( + expect(!!hsm.set_state(3u, 0u)); + hsm.states[3u].enter_action.set_output( irt::hierarchical_state_machine::variable::port_0, 1.f); - expect(!!sim.connect(gen, 0, hsm, 0)); - expect(!!sim.connect(gen, 0, hsm, 1)); - expect(!!sim.connect(hsm, 0, cnt, 0)); + expect(!!sim.connect(gen, 0, hsmw, 0)); + expect(!!sim.connect(gen, 0, hsmw, 1)); + expect(!!sim.connect(hsmw, 0, cnt, 0)); sim.t = 0.0; expect(!!sim.srcs.prepare()); @@ -2160,7 +2166,7 @@ int main() }; "hsm_timer_stop_and_restart_simulation"_test = [] { - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect((sim.can_alloc(3)) >> fatal); expect((sim.hsms.can_alloc(1)) >> fatal); @@ -2180,30 +2186,30 @@ int main() expect(sim.hsms.can_alloc()); expect(sim.models.can_alloc()); - auto& hsm = sim.alloc(); - auto* hsmw = sim.hsms.try_to_get(hsm.id); - expect((hsmw != nullptr) >> fatal); + auto& hsmw = sim.alloc(); + auto& hsm = sim.hsms.alloc(); + hsmw.id = sim.hsms.get_id(hsm); - expect(!!hsmw->set_state( + expect(!!hsm.set_state( 0u, irt::hierarchical_state_machine::invalid_state_id, 1u)); - expect(!!hsmw->set_state(1u, 0u)); - hsmw->states[1u].condition.set(0b0011u, 0b0011u); - hsmw->states[1u].if_transition = 2u; + expect(!!hsm.set_state(1u, 0u)); + hsm.states[1u].condition.set(0b0011u, 0b0011u); + hsm.states[1u].if_transition = 2u; - expect(!!hsmw->set_state(2u, 0u)); - hsmw->states[2u].enter_action.set_affect( + expect(!!hsm.set_state(2u, 0u)); + hsm.states[2u].enter_action.set_affect( irt::hierarchical_state_machine::variable::var_timer, 10.f); - hsmw->states[2u].condition.set_timer(); - hsmw->states[2u].if_transition = 3u; + hsm.states[2u].condition.set_timer(); + hsm.states[2u].if_transition = 3u; - expect(!!hsmw->set_state(3u, 0u)); - hsmw->states[3u].enter_action.set_output( + expect(!!hsm.set_state(3u, 0u)); + hsm.states[3u].enter_action.set_output( irt::hierarchical_state_machine::variable::port_0, 1.f); - expect(!!sim.connect(gen1, 0, hsm, 0)); - expect(!!sim.connect(gen2, 0, hsm, 1)); - expect(!!sim.connect(hsm, 0, cnt, 0)); + expect(!!sim.connect(gen1, 0, hsmw, 0)); + expect(!!sim.connect(gen2, 0, hsmw, 1)); + expect(!!sim.connect(hsmw, 0, cnt, 0)); sim.t = 0.0; expect(!!sim.srcs.prepare()); @@ -2220,7 +2226,7 @@ int main() }; "hsm_timer_stop_simulation"_test = [] { - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect((sim.can_alloc(3)) >> fatal); expect((sim.hsms.can_alloc(1)) >> fatal); @@ -2240,33 +2246,33 @@ int main() expect(sim.hsms.can_alloc()); expect(sim.models.can_alloc()); - auto& hsm = sim.alloc(); - auto* hsmw = sim.hsms.try_to_get(hsm.id); - expect((hsmw != nullptr) >> fatal); + auto& hsmw = sim.alloc(); + auto& hsm = sim.hsms.alloc(); + hsmw.id = sim.hsms.get_id(hsm); - expect(!!hsmw->set_state( + expect(!!hsm.set_state( 0u, irt::hierarchical_state_machine::invalid_state_id, 1u)); - expect(!!hsmw->set_state(1u, 0u)); - hsmw->states[1u].condition.set(0b0011u, 0b0011u); - hsmw->states[1u].if_transition = 2u; + expect(!!hsm.set_state(1u, 0u)); + hsm.states[1u].condition.set(0b0011u, 0b0011u); + hsm.states[1u].if_transition = 2u; - expect(!!hsmw->set_state(2u, 0u)); - hsmw->states[2u].enter_action.set_affect( + expect(!!hsm.set_state(2u, 0u)); + hsm.states[2u].enter_action.set_affect( irt::hierarchical_state_machine::variable::var_timer, 10.f); - hsmw->states[2u].condition.set_timer(); - hsmw->states[2u].if_transition = 3u; - hsmw->states[2u].if_transition = 4u; + hsm.states[2u].condition.set_timer(); + hsm.states[2u].if_transition = 3u; + hsm.states[2u].if_transition = 4u; - expect(!!hsmw->set_state(3u, 0u)); - hsmw->states[3u].enter_action.set_output( + expect(!!hsm.set_state(3u, 0u)); + hsm.states[3u].enter_action.set_output( irt::hierarchical_state_machine::variable::port_0, 1.0f); - expect(!!hsmw->set_state(4u, 0u)); + expect(!!hsm.set_state(4u, 0u)); - expect(!!sim.connect(gen1, 0, hsm, 0)); - expect(!!sim.connect(gen2, 0, hsm, 1)); - expect(!!sim.connect(hsm, 0, cnt, 0)); + expect(!!sim.connect(gen1, 0, hsmw, 0)); + expect(!!sim.connect(gen2, 0, hsmw, 1)); + expect(!!sim.connect(hsmw, 0, cnt, 0)); sim.t = 0.0; expect(!!sim.srcs.prepare()); @@ -2284,7 +2290,7 @@ int main() "generator_counter_simluation"_test = [] { fmt::print("generator_counter_simluation\n"); - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(sim.can_alloc(2)); @@ -2333,7 +2339,7 @@ int main() }; "boolean_simulation"_test = [] { - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(sim.srcs.constant_sources.can_alloc(2u)); auto& cst_value = sim.srcs.constant_sources.alloc(); @@ -2392,7 +2398,7 @@ int main() "time_func"_test = [] { fmt::print("time_func\n"); - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); constexpr irt::real duration{ 30 }; constexpr irt::real timestep{ 0.1 }; @@ -2428,7 +2434,7 @@ int main() constexpr irt::real duration = 30; constexpr irt::real timestep = 0.1; - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(sim.can_alloc(2)); @@ -2454,7 +2460,7 @@ int main() "lotka_volterra_simulation_qss1"_test = [] { fmt::print("lotka_volterra_simulation_qss1\n"); - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(sim.can_alloc(5)); @@ -2512,7 +2518,7 @@ int main() "lotka_volterra_simulation_qss2"_test = [] { fmt::print("lotka_volterra_simulation_qss2\n"); - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(sim.can_alloc(5)); @@ -2570,7 +2576,7 @@ int main() "lif_simulation_qss1"_test = [] { fmt::print("lif_simulation_qss1\n"); - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(sim.can_alloc(5)); @@ -2626,7 +2632,7 @@ int main() "lif_simulation_qss2"_test = [] { fmt::print("lif_simulation_qss2\n"); - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(sim.can_alloc(5)); @@ -2686,7 +2692,7 @@ int main() "izhikevich_simulation_qss1"_test = [] { fmt::print("izhikevich_simulation_qss1\n"); - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(sim.can_alloc(12)); @@ -2789,7 +2795,7 @@ int main() "izhikevich_simulation_qss2"_test = [] { fmt::print("izhikevich_simulation_qss2\n"); - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(sim.can_alloc(12)); @@ -2892,7 +2898,7 @@ int main() "lotka_volterra_simulation_qss3"_test = [] { fmt::print("lotka_volterra_simulation_qss3\n"); - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(sim.can_alloc(5)); @@ -2950,7 +2956,7 @@ int main() "lif_simulation_qss3"_test = [] { fmt::print("lif_simulation_qss3\n"); - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(sim.can_alloc(5)); @@ -3009,7 +3015,7 @@ int main() "izhikevich_simulation_qss3"_test = [] { fmt::print("izhikevich_simulation_qss3\n"); - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(sim.can_alloc(12)); @@ -3112,7 +3118,7 @@ int main() "van_der_pol_simulation_qss3"_test = [] { fmt::print("van_der_pol_simulation_qss3\n"); - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(sim.can_alloc(5)); @@ -3171,7 +3177,7 @@ int main() "neg_lif_simulation_qss1"_test = [] { fmt::print("neg_lif_simulation_qss1\n"); - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(sim.can_alloc(5)); @@ -3228,7 +3234,7 @@ int main() "neg_lif_simulation_qss2"_test = [] { fmt::print("neg_lif_simulation_qss2\n"); - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(sim.can_alloc(5)); @@ -3286,7 +3292,7 @@ int main() "neg_lif_simulation_qss3"_test = [] { fmt::print("neg_lif_simulation_qss3\n"); - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(sim.can_alloc(5)); @@ -3343,94 +3349,94 @@ int main() "all"_test = [] { { - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(!!irt::example_qss_lotka_volterra<1>(sim, empty_fun)); expect(!!run_simulation(sim, 30.)); } { - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(!!irt::example_qss_negative_lif<1>(sim, empty_fun)); expect(!!run_simulation(sim, 30.)); } { - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(!!irt::example_qss_lif<1>(sim, empty_fun)); expect(!!run_simulation(sim, 30.)); } { - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(!!irt::example_qss_van_der_pol<1>(sim, empty_fun)); expect(!!run_simulation(sim, 30.)); } { - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(!!irt::example_qss_izhikevich<1>(sim, empty_fun)); expect(!!run_simulation(sim, 30.)); } { - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(!!irt::example_qss_lotka_volterra<2>(sim, empty_fun)); expect(!!run_simulation(sim, 30.)); } { - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(!!irt::example_qss_negative_lif<2>(sim, empty_fun)); expect(!!run_simulation(sim, 30.)); } { - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(!!irt::example_qss_lif<2>(sim, empty_fun)); expect(!!run_simulation(sim, 30.)); } { - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(!!irt::example_qss_van_der_pol<2>(sim, empty_fun)); expect(!!run_simulation(sim, 30.)); } { - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(!!irt::example_qss_izhikevich<2>(sim, empty_fun)); expect(!!run_simulation(sim, 30.)); } { - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(!!irt::example_qss_lotka_volterra<3>(sim, empty_fun)); expect(!!run_simulation(sim, 30.)); } { - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(!!irt::example_qss_negative_lif<3>(sim, empty_fun)); expect(!!run_simulation(sim, 30.)); } { - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(!!irt::example_qss_lif<3>(sim, empty_fun)); expect(!!run_simulation(sim, 30.)); } { - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(!!irt::example_qss_van_der_pol<3>(sim, empty_fun)); expect(!!run_simulation(sim, 30.)); } { - irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + irt::simulation sim(irt::simulation_memory_requirement(256)); expect(!!irt::example_qss_izhikevich<3>(sim, empty_fun)); expect(!!run_simulation(sim, 30.)); @@ -3443,7 +3449,7 @@ int main() // irt::g_free_fn = global_free; // - // irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + // irt::simulation sim(irt::simulation_memory_requirement(256)); // } @@ -3469,7 +3475,7 @@ int main() // irt::g_free_fn = null_free; // - // irt::simulation sim(irt::simulation_memory_requirement(256, 16)); + // irt::simulation sim(irt::simulation_memory_requirement(256)); // irt::g_alloc_fn = irt::malloc_wrapper; // irt::g_free_fn = irt::free_wrapper; diff --git a/lib/test/simulations.cpp b/lib/test/simulations.cpp index 223ff8b2..7cd61596 100644 --- a/lib/test/simulations.cpp +++ b/lib/test/simulations.cpp @@ -196,8 +196,9 @@ int main() using namespace boost::ut; "song_1_simulation"_test = [] { - irt::simulation sim(1024 * 1024 * 8); const auto N = 4u; + irt::simulation sim(irt::simulation_memory_requirement(N * N * 8), + irt::external_source_memory_requirement{}); expect(sim.can_alloc(N + 2u * N * N + 2u * N * N + 4u * N * N + N + 2u * N * N)); diff --git a/lib/test/threading.cpp b/lib/test/threading.cpp index 154ea968..d802812a 100644 --- a/lib/test/threading.cpp +++ b/lib/test/threading.cpp @@ -11,9 +11,7 @@ #include -using heap_mr = irt::static_memory_resource<256 * 256 * 16>; - -static heap_mr mem; +using heap_mr = irt::allocator>; static void function_1(std::atomic_int& counter) noexcept { counter += 1; } static void function_100(std::atomic_int& counter) noexcept { counter += 100; } @@ -28,8 +26,7 @@ int main() using namespace boost::ut; "data-task-copy-capture"_test = [] { - irt::data_array> d( - &mem, 32); + irt::data_array d(32); int a = 16; int b = 32; @@ -49,8 +46,7 @@ int main() }; "data-task-reference-capture"_test = [] { - irt::data_array> - d(&mem, 32); + irt::data_array d(32); int a = 16; int b = 32;