diff --git a/Source/Base/include/Base/variable_container.h b/Source/Base/include/Base/variable_container.h index 71831c414..42037375a 100644 --- a/Source/Base/include/Base/variable_container.h +++ b/Source/Base/include/Base/variable_container.h @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2021 Michael Kazakov. Subject to GNU General Public License version 3. +// Copyright (C) 2015-2024 Michael Kazakov. Subject to GNU General Public License version 3. #pragma once #include #include #include #include +#include namespace nc::base { @@ -22,7 +23,7 @@ struct variable_container_base { } // namespace detail template -class variable_container +class alignas(max_align_t) variable_container { public: typedef T value_type; @@ -116,10 +117,13 @@ class variable_container private: using common_type = value_type; - using sparse_type = robin_hood::unordered_map; + using sparse_type = robin_hood::unordered_flat_map; using dense_type = std::vector; static constexpr std::size_t m_StorageSize = std::max({sizeof(common_type), sizeof(sparse_type), sizeof(dense_type)}); + static_assert(alignof(max_align_t) >= alignof(common_type)); + static_assert(alignof(max_align_t) >= alignof(sparse_type)); + static_assert(alignof(max_align_t) >= alignof(dense_type)); common_type &Common(); const common_type &Common() const; @@ -152,8 +156,7 @@ variable_container::variable_container(const variable_container &_rhs) : m } template -variable_container::variable_container(variable_container &&_rhs) noexcept - : m_Type(_rhs.m_Type) +variable_container::variable_container(variable_container &&_rhs) noexcept : m_Type(_rhs.m_Type) { ConstructMove(std::move(_rhs)); } @@ -405,8 +408,7 @@ void variable_container::insert(size_t _at, T &&_value) else { // if( m_Type == type::sparse ) auto i = Sparse().find(static_cast(_at)); if( i == std::end(Sparse()) ) - Sparse().insert( - typename sparse_type::value_type(static_cast(_at), std::move(_value))); + Sparse().insert(typename sparse_type::value_type(static_cast(_at), std::move(_value))); else i->second = std::move(_value); } @@ -459,8 +461,7 @@ template void variable_container::compress_contiguous() { if( m_Type != type::sparse ) - throw std::logic_error( - "variable_container::compress_contiguous was called for a non-sparse container"); + throw std::logic_error("variable_container::compress_contiguous was called for a non-sparse container"); variable_container new_dense(type::dense); diff --git a/Source/Base/tests/VariableContainer_UT.cpp b/Source/Base/tests/VariableContainer_UT.cpp index 7958cb0b6..1ba70fc2d 100644 --- a/Source/Base/tests/VariableContainer_UT.cpp +++ b/Source/Base/tests/VariableContainer_UT.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015-2023 Michael Kazakov. Subject to GNU General Public License version 3. +// Copyright (C) 2015-2024 Michael Kazakov. Subject to GNU General Public License version 3. #include "variable_container.h" #include "UnitTests_main.h" #include @@ -7,51 +7,92 @@ using nc::base::variable_container; #define PREFIX "variable_container " -TEST_CASE(PREFIX"test 1") -{ - variable_container< std::string > vc( variable_container::type::common ); - vc.at(0) = "Abra!!!"; - CHECK( vc.at(0) == "Abra!!!" ); +static_assert(sizeof(variable_container) == 64); + +TEST_CASE(PREFIX "Common storage") +{ + variable_container vc(variable_container<>::type::common); + CHECK(vc.size() == 1); + CHECK(vc.empty() == false); + CHECK(vc.at(0) == ""); // default-constructed + CHECK(vc[0] == ""); + + vc.at(0) = "Meow"; + CHECK(vc.at(0) == "Meow"); + CHECK(vc[0] == "Meow"); } -TEST_CASE(PREFIX"test 2") +TEST_CASE(PREFIX "Sparse storage") { - variable_container< std::string > vc( variable_container::type::sparse ); + variable_container vc(variable_container<>::type::sparse); + CHECK(vc.size() == 0); + CHECK(vc.empty() == true); vc.insert(5, "abra"); + CHECK(vc.size() == 1); vc.insert(6, "kazam"); - CHECK( vc.at(5) == "abra" ); - CHECK( vc.at(6) == "kazam" ); - + CHECK(vc.size() == 2); + CHECK(vc.at(5) == "abra"); + CHECK(vc.at(6) == "kazam"); + vc.insert(5, "abra!"); - CHECK( vc.at(5) == "abra!" ); - - CHECK( vc.has(5) ); - CHECK( vc.has(6) ); - CHECK(!vc.has(7) ); + CHECK(vc.size() == 2); + CHECK(vc.at(5) == "abra!"); + + CHECK(vc.has(5)); + CHECK(vc.has(6)); + CHECK(!vc.has(7)); } -TEST_CASE(PREFIX"test 3") +TEST_CASE(PREFIX "Dense storage") { - variable_container< std::string > vc( variable_container::type::dense ); - + variable_container vc(variable_container<>::type::dense); + vc.insert(5, "abra"); vc.insert(6, "kazam"); - CHECK( vc.at(5) == "abra" ); - CHECK( vc.at(6) == "kazam" ); - + CHECK(vc.at(5) == "abra"); + CHECK(vc.at(6) == "kazam"); + vc.insert(5, "abra!"); - CHECK( vc.at(5) == "abra!" ); - - CHECK( vc.has(5) ); - CHECK( vc.has(6) ); - CHECK(!vc.has(7) ); - - CHECK( vc.at(0) == "" ); - - variable_container< std::string > vc2( vc ); - CHECK( vc2.at(5) == "abra!" ); - - variable_container< std::string > vc3( std::move(vc2) ); - CHECK( vc3.at(6) == "kazam" ); + CHECK(vc.at(5) == "abra!"); + + CHECK(vc.has(5)); + CHECK(vc.has(6)); + CHECK(!vc.has(7)); + + CHECK(vc.at(0) == ""); + + variable_container vc2(vc); + CHECK(vc2.at(5) == "abra!"); + + variable_container vc3(std::move(vc2)); + CHECK(vc3.at(6) == "kazam"); +} + +TEST_CASE(PREFIX "is_contiguous") +{ + { + variable_container vc(variable_container<>::type::common); + CHECK(vc.is_contiguous()); + vc.insert(0, "Meow"); + CHECK(vc.is_contiguous()); + } + { + variable_container vc(variable_container<>::type::dense); + CHECK(vc.is_contiguous()); + vc.insert(0, "Meow"); + CHECK(vc.is_contiguous()); + vc.insert(5, "Woof"); + CHECK(vc.is_contiguous()); + } + { + variable_container vc(variable_container<>::type::sparse); + CHECK(vc.is_contiguous()); + vc.insert(0, "Meow"); + CHECK(vc.is_contiguous()); + vc.insert(1, "Woof"); + CHECK(vc.is_contiguous()); + vc.insert(5, "Hiss"); + CHECK(!vc.is_contiguous()); + } }