Skip to content

Commit

Permalink
Fixed the alignment of variable_container
Browse files Browse the repository at this point in the history
  • Loading branch information
mikekazakov committed Jan 21, 2024
1 parent eea91c7 commit 2ebb295
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 44 deletions.
19 changes: 10 additions & 9 deletions Source/Base/include/Base/variable_container.h
Original file line number Diff line number Diff line change
@@ -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 <cassert>
#include <array>
#include <vector>
#include <robin_hood.h>
#include <stddef.h>

namespace nc::base {

Expand All @@ -22,7 +23,7 @@ struct variable_container_base {
} // namespace detail

template <class T = int>
class variable_container
class alignas(max_align_t) variable_container
{
public:
typedef T value_type;
Expand Down Expand Up @@ -116,10 +117,13 @@ class variable_container

private:
using common_type = value_type;
using sparse_type = robin_hood::unordered_map<size_t, T>;
using sparse_type = robin_hood::unordered_flat_map<size_t, T>;
using dense_type = std::vector<T>;
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;
Expand Down Expand Up @@ -152,8 +156,7 @@ variable_container<T>::variable_container(const variable_container<T> &_rhs) : m
}

template <class T>
variable_container<T>::variable_container(variable_container<T> &&_rhs) noexcept
: m_Type(_rhs.m_Type)
variable_container<T>::variable_container(variable_container<T> &&_rhs) noexcept : m_Type(_rhs.m_Type)
{
ConstructMove(std::move(_rhs));
}
Expand Down Expand Up @@ -405,8 +408,7 @@ void variable_container<T>::insert(size_t _at, T &&_value)
else { // if( m_Type == type::sparse )
auto i = Sparse().find(static_cast<unsigned>(_at));
if( i == std::end(Sparse()) )
Sparse().insert(
typename sparse_type::value_type(static_cast<unsigned>(_at), std::move(_value)));
Sparse().insert(typename sparse_type::value_type(static_cast<unsigned>(_at), std::move(_value)));
else
i->second = std::move(_value);
}
Expand Down Expand Up @@ -459,8 +461,7 @@ template <class T>
void variable_container<T>::compress_contiguous()
{
if( m_Type != type::sparse )
throw std::logic_error(
"variable_container<T>::compress_contiguous was called for a non-sparse container");
throw std::logic_error("variable_container<T>::compress_contiguous was called for a non-sparse container");

variable_container<T> new_dense(type::dense);

Expand Down
111 changes: 76 additions & 35 deletions Source/Base/tests/VariableContainer_UT.cpp
Original file line number Diff line number Diff line change
@@ -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 <string>
Expand All @@ -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<std::string>::type::common );
vc.at(0) = "Abra!!!";
CHECK( vc.at(0) == "Abra!!!" );
static_assert(sizeof(variable_container<std::string>) == 64);

TEST_CASE(PREFIX "Common storage")
{
variable_container<std::string> 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<std::string>::type::sparse );
variable_container<std::string> 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<std::string>::type::dense );
variable_container<std::string> 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<std::string> vc2(vc);
CHECK(vc2.at(5) == "abra!");

variable_container<std::string> vc3(std::move(vc2));
CHECK(vc3.at(6) == "kazam");
}

TEST_CASE(PREFIX "is_contiguous")
{
{
variable_container<std::string> vc(variable_container<>::type::common);
CHECK(vc.is_contiguous());
vc.insert(0, "Meow");
CHECK(vc.is_contiguous());
}
{
variable_container<std::string> 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<std::string> 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());
}
}

0 comments on commit 2ebb295

Please sign in to comment.