diff --git a/include/flatmemory/details/types/bitset.hpp b/include/flatmemory/details/types/bitset.hpp index 2757135..34b90b6 100644 --- a/include/flatmemory/details/types/bitset.hpp +++ b/include/flatmemory/details/types/bitset.hpp @@ -111,6 +111,37 @@ namespace flatmemory assert(m_buf); } + [[nodiscard]] bool operator==(const View& other) const + { + // Fetch data + const auto &blocks = get_blocks(); + bool default_bit_value = get_default_bit_value(); + const auto &other_blocks = other.get_blocks(); + bool other_default_bit_value = other.get_default_bit_value(); + + std::size_t common_size = std::min(blocks.size(), other_blocks.size()); + if (std::memcmp(blocks.data(), other_blocks.data(), common_size * sizeof(Block)) != 0) return false; + + std::size_t max_size = std::max(blocks.size(), other_blocks.size()); + + for (std::size_t index = common_size; index < max_size; ++index) + { + Block this_value = index < blocks.size() ? blocks[index] : (default_bit_value ? block_ones : block_zeroes); + Block other_value = index < other_blocks.size() ? other_blocks[index] : (other_default_bit_value ? block_ones : block_zeroes); + + if (this_value != other_value) + { + return false; + } + } + + return true; + } + + [[nodiscard]] bool operator!=(const View& other) const { + return !(*this == other); + } + [[nodiscard]] size_t buffer_size() const { assert(m_buf); @@ -125,12 +156,25 @@ namespace flatmemory return read_value(m_buf + Layout>::default_bit_value_position); } + [[nodiscard]] const bool& get_default_bit_value() const + { + assert(m_buf); + assert(test_correct_alignment(m_buf + Layout>::default_bit_value_position)); + return read_value(m_buf + Layout>::default_bit_value_position); + } + [[nodiscard]] View> get_blocks() { assert(m_buf); return View>(m_buf + Layout>::blocks_position); } + [[nodiscard]] ConstView> get_blocks() const + { + assert(m_buf); + return ConstView>(m_buf + Layout>::blocks_position); + } + [[nodiscard]] size_t hash() const { const bool default_bit_value = get_default_bit_value(); @@ -184,6 +228,41 @@ namespace flatmemory assert(m_buf); } + /** + * Operators + */ + + [[nodiscard]] bool operator==(const ConstView& other) const + { + // Fetch data + const auto &blocks = get_blocks(); + bool default_bit_value = get_default_bit_value(); + const auto &other_blocks = other.get_blocks(); + bool other_default_bit_value = other.get_default_bit_value(); + + std::size_t common_size = std::min(blocks.size(), other_blocks.size()); + if (std::memcmp(blocks.data(), other_blocks.data(), common_size * sizeof(Block)) != 0) return false; + + std::size_t max_size = std::max(blocks.size(), other_blocks.size()); + + for (std::size_t index = common_size; index < max_size; ++index) + { + Block this_value = index < blocks.size() ? blocks[index] : (default_bit_value ? block_ones : block_zeroes); + Block other_value = index < other_blocks.size() ? other_blocks[index] : (other_default_bit_value ? block_ones : block_zeroes); + + if (this_value != other_value) + { + return false; + } + } + + return true; + } + + [[nodiscard]] bool operator!=(const ConstView& other) const { + return !(*this == other); + } + [[nodiscard]] size_t buffer_size() const { assert(m_buf); @@ -373,14 +452,7 @@ namespace flatmemory bool other_default_bit_value = other.get_default_bit_value(); std::size_t common_size = std::min(m_blocks.size(), other_blocks.size()); - - for (std::size_t index = 0; index < common_size; ++index) - { - if (m_blocks[index] != other_blocks[index]) - { - return false; - } - } + if (std::memcmp(m_blocks.data(), other_blocks.data(), common_size * sizeof(Block)) != 0) return false; std::size_t max_size = std::max(m_blocks.size(), other_blocks.size()); @@ -398,6 +470,11 @@ namespace flatmemory return true; } + template + [[nodiscard]] bool operator!=(const Other& other) const { + return !(*this == other); + } + /** * Modifiers diff --git a/include/flatmemory/details/types/tuple.hpp b/include/flatmemory/details/types/tuple.hpp index 45d94fb..32c7bbc 100644 --- a/include/flatmemory/details/types/tuple.hpp +++ b/include/flatmemory/details/types/tuple.hpp @@ -224,21 +224,9 @@ namespace flatmemory /** * Operators */ - template - [[nodiscard]] bool are_equal_helper(std::index_sequence, const Builder& other) const { - bool are_equal = true; - ([&] { - if (this->get() != other.get()) { - are_equal = false; - return; - } - }(), ...); - return are_equal; - } - [[nodiscard]] bool operator==(const Builder& other) const { if (this != &other) { - return are_equal_helper(std::make_index_sequence{}, other); + return m_data == other.m_data; } return true; } @@ -373,23 +361,11 @@ namespace flatmemory } } - - template - [[nodiscard]] size_t hash_helper(std::index_sequence) const { - size_t seed = Layout>::size; - ([&] { - constexpr bool is_trivial = IsTriviallyCopyable>; - if constexpr (is_trivial) { - hash_combine(seed, std::hash>()(get())); - } else { - hash_combine(seed, get().hash()); - } - }(), ...); - return seed; - } - [[nodiscard]] size_t hash() const { - return hash_helper(std::make_index_sequence{}); + size_t seed = Layout>::size; + int64_t hash[2]; + MurmurHash3_x64_128(m_buf, buffer_size(), seed, hash); + return static_cast(hash[0] + 0x9e3779b9 + (hash[1] << 6) + (hash[1] >> 2)); } }; @@ -474,23 +450,11 @@ namespace flatmemory return read_value(m_buf + Layout>::layout_data.buffer_size_position); } - - template - [[nodiscard]] size_t hash_helper(std::index_sequence) const { - size_t seed = Layout>::size; - ([&] { - constexpr bool is_trivial = IsTriviallyCopyable>; - if constexpr (is_trivial) { - hash_combine(seed, std::hash>()(get())); - } else { - hash_combine(seed, get().hash()); - } - }(), ...); - return seed; - } - [[nodiscard]] size_t hash() const { - return hash_helper(std::make_index_sequence{}); + size_t seed = Layout>::size; + int64_t hash[2]; + MurmurHash3_x64_128(m_buf, buffer_size(), seed, hash); + return static_cast(hash[0] + 0x9e3779b9 + (hash[1] << 6) + (hash[1] >> 2)); } }; } diff --git a/include/flatmemory/details/types/vector.hpp b/include/flatmemory/details/types/vector.hpp index 2cce817..d84a2d7 100644 --- a/include/flatmemory/details/types/vector.hpp +++ b/include/flatmemory/details/types/vector.hpp @@ -26,6 +26,7 @@ #include "../view_const.hpp" #include "../view.hpp" #include "../type_traits.hpp" +#include "../algorithms/hash.hpp" #include "../algorithms/murmurhash3.hpp" #include @@ -164,8 +165,7 @@ namespace flatmemory [[nodiscard]] bool operator==(const Builder& other) const { if (this != &other) { - if (m_buffer.size() != other.m_buffer.size()) return false; - return std::memcmp(m_buffer.data(), other.m_buffer.data(), m_buffer.size()) == 0; + return m_data == other.m_data; } return true; } @@ -189,12 +189,21 @@ namespace flatmemory } [[nodiscard]] size_t hash() const { - size_t seed = size(); - int64_t hash[2]; - MurmurHash3_x64_128(m_buffer.data(), m_buffer.size(), seed, hash); - return static_cast(hash[0] + 0x9e3779b9 + (hash[1] << 6) + (hash[1] >> 2)); + constexpr bool is_trivial = IsTriviallyCopyable; + if constexpr (is_trivial) { + return hash_combine(hash_container(m_data)); + } else { + size_t seed = size(); + for (const auto& builder : m_data) { + hash_combine(seed, builder.hash()); + } + return seed; + } } + [[nodiscard]] T_* data() { return m_data.data(); } + [[nodiscard]] const T_* data() const { return m_data.data(); } + /** * Iterators @@ -241,6 +250,8 @@ namespace flatmemory class View> { private: + using T_ = typename maybe_builder::type; + uint8_t* m_buf; /// @brief Default constructor to make view a trivial data type and serializable @@ -311,6 +322,9 @@ namespace flatmemory return static_cast(hash[0] + 0x9e3779b9 + (hash[1] << 6) + (hash[1] >> 2)); } + [[nodiscard]] T_* data() { return reinterpret_cast(m_buf + Layout>::vector_data_position); } + [[nodiscard]] const T_* data() const { return reinterpret_cast(m_buf + Layout>::vector_data_position); } + /** * Iterators @@ -426,6 +440,8 @@ namespace flatmemory class ConstView> { private: + using T_ = typename maybe_builder::type; + const uint8_t* m_buf; /// @brief Default constructor to make view a trivial data type and serializable @@ -483,6 +499,8 @@ namespace flatmemory return static_cast(hash[0] + 0x9e3779b9 + (hash[1] << 6) + (hash[1] >> 2)); } + [[nodiscard]] const T_* data() const { return reinterpret_cast(m_buf + Layout>::vector_data_position); } + /** * Iterators diff --git a/tests/unit/types/bitset.cpp b/tests/unit/types/bitset.cpp index 4d1dbca..709279b 100644 --- a/tests/unit/types/bitset.cpp +++ b/tests/unit/types/bitset.cpp @@ -163,5 +163,62 @@ TEST(FlatmemoryTests, TypesBitsetNotTest) { } + TEST(FlatmemoryTests, TypesBitsetEqualityTest) { + using BitsetLayout = Bitset; + + auto builder1 = Builder(3); + builder1.get_default_bit_value() = false; + builder1.set(1); + builder1.finish(); + + auto builder2 = Builder(3); + builder2.get_default_bit_value() = false; + builder2.set(1); + builder2.finish(); + + auto builder3 = Builder(3); + builder3.get_default_bit_value() = false; + builder3.finish(); + + EXPECT_TRUE((builder1 == builder2)); + EXPECT_EQ(builder1.hash(), builder2.hash()); + + EXPECT_FALSE((builder1 == builder3)); + EXPECT_NE(builder1.hash(), builder3.hash()); + + EXPECT_FALSE((builder2 == builder3)); + EXPECT_NE(builder2.hash(), builder3.hash()); + + + auto view1 = View(builder1.buffer().data()); + auto view2 = View(builder2.buffer().data()); + auto view3 = View(builder3.buffer().data()); + + EXPECT_TRUE((view1 == view2)); + EXPECT_EQ(view1.hash(), view2.hash()); + + EXPECT_FALSE((view1 == view3)); + EXPECT_NE(view1.hash(), view3.hash()); + + EXPECT_FALSE((view2 == view3)); + EXPECT_NE(view2.hash(), view3.hash()); + + + auto const_view1 = ConstView(builder1.buffer().data()); + auto const_view2 = ConstView(builder2.buffer().data()); + auto const_view3 = ConstView(builder3.buffer().data()); + + EXPECT_TRUE((const_view1 == const_view2)); + EXPECT_EQ(const_view1.hash(), const_view2.hash()); + + EXPECT_FALSE((const_view1 == const_view3)); + EXPECT_NE(const_view1.hash(), const_view3.hash()); + + EXPECT_FALSE((const_view2 == const_view3)); + EXPECT_NE(const_view2.hash(), const_view3.hash()); + + } + + } diff --git a/tests/unit/types/tuple.cpp b/tests/unit/types/tuple.cpp index 01a64ec..ed8a364 100644 --- a/tests/unit/types/tuple.cpp +++ b/tests/unit/types/tuple.cpp @@ -164,9 +164,6 @@ namespace flatmemory::tests TEST(FlatmemoryTests, TypesTupleEqualityTest) { using TupleLayout = Tuple; - EXPECT_EQ((Layout::final_alignment), 8); - EXPECT_EQ((IsTriviallyCopyable>), true); - EXPECT_EQ((IsTriviallyCopyable), false); auto builder1 = Builder(); builder1.get<0>() = 5; @@ -219,6 +216,5 @@ namespace flatmemory::tests EXPECT_FALSE((const_view2 == const_view3)); EXPECT_NE(const_view2.hash(), const_view3.hash()); - } } diff --git a/tests/unit/types/vector.cpp b/tests/unit/types/vector.cpp index d633646..0c2f129 100644 --- a/tests/unit/types/vector.cpp +++ b/tests/unit/types/vector.cpp @@ -90,9 +90,6 @@ TEST(FlatmemoryTests, TypesVectorViewTest) { TEST(FlatmemoryTests, TypesVectorEqualityTest) { using VectorLayout = Vector; - EXPECT_EQ((Layout::final_alignment), 8); - EXPECT_EQ((IsTriviallyCopyable>), true); - EXPECT_EQ((IsTriviallyCopyable), false); auto builder1 = Builder(); builder1.push_back(5);