diff --git a/include/sparrow/data_traits.hpp b/include/sparrow/data_traits.hpp index 1e7bbd3a4..6bef8870d 100644 --- a/include/sparrow/data_traits.hpp +++ b/include/sparrow/data_traits.hpp @@ -120,7 +120,7 @@ namespace sparrow { static constexpr data_type type_id = data_type::STRING; using value_type = std::string; - using default_layout = variable_size_binary_layout; // FIXME: this is incorrect, change when we have the right types + using default_layout = variable_size_binary_layout; // FIXME: this is incorrect, change when we have the right types }; template <> @@ -128,7 +128,7 @@ namespace sparrow { static constexpr data_type type_id = data_type::STRING; using value_type = std::vector; - using default_layout = variable_size_binary_layout, const std::span>; // FIXME: this is incorrect, change when we have the right types + using default_layout = variable_size_binary_layout>; // FIXME: this is incorrect, change when we have the right types }; template <> diff --git a/include/sparrow/dictionary_encoded_layout.hpp b/include/sparrow/dictionary_encoded_layout.hpp index 66d7f41f1..d2876d039 100644 --- a/include/sparrow/dictionary_encoded_layout.hpp +++ b/include/sparrow/dictionary_encoded_layout.hpp @@ -221,7 +221,11 @@ namespace sparrow private: - const indexes_layout& get_const_indexes_layout() const; + indexes_layout& get_indexes_layout(); + const indexes_layout& get_indexes_layout() const; + + sub_layout& get_sub_layout(); + const sub_layout& get_sub_layout() const; const_value_iterator value_cbegin() const; const_value_iterator value_cend() const; @@ -355,10 +359,10 @@ namespace sparrow auto dictionary_encoded_layout::operator[](size_type i) const -> const_reference { SPARROW_ASSERT_TRUE(i < size()); - const auto index = (*m_indexes_layout)[i]; + const auto index = get_indexes_layout()[i]; if (index.has_value()) { - return (*m_sub_layout)[index.value()]; + return get_sub_layout()[index.value()]; } else { @@ -390,34 +394,55 @@ namespace sparrow return const_value_range(value_cbegin(), value_cend()); } + template + typename dictionary_encoded_layout::indexes_layout& + dictionary_encoded_layout::get_indexes_layout() + { + return *(m_indexes_layout.get()); + } + template const typename dictionary_encoded_layout::indexes_layout& - dictionary_encoded_layout::get_const_indexes_layout() const + dictionary_encoded_layout::get_indexes_layout() const { return *const_cast(m_indexes_layout.get()); } + template + typename dictionary_encoded_layout::sub_layout& + dictionary_encoded_layout::get_sub_layout() + { + return *(m_sub_layout.get()); + } + + template + const typename dictionary_encoded_layout::sub_layout& + dictionary_encoded_layout::get_sub_layout() const + { + return *const_cast(m_sub_layout.get()); + } + template auto dictionary_encoded_layout::value_cbegin() const -> const_value_iterator { - return const_value_iterator(get_const_indexes_layout().cbegin(), *m_sub_layout); + return const_value_iterator(get_indexes_layout().cbegin(), *m_sub_layout); } template auto dictionary_encoded_layout::value_cend() const -> const_value_iterator { - return const_value_iterator(get_const_indexes_layout().cend(), *m_sub_layout); + return const_value_iterator(get_indexes_layout().cend(), *m_sub_layout); } template auto dictionary_encoded_layout::bitmap_cbegin() const -> const_bitmap_iterator { - return const_bitmap_iterator(get_const_indexes_layout().cbegin(), *m_sub_layout); + return const_bitmap_iterator(get_indexes_layout().cbegin(), get_sub_layout()); } template auto dictionary_encoded_layout::bitmap_cend() const -> const_bitmap_iterator { - return const_bitmap_iterator(get_const_indexes_layout().cend(), *m_sub_layout); + return const_bitmap_iterator(get_indexes_layout().cend(), get_sub_layout()); } template diff --git a/include/sparrow/mp_utils.hpp b/include/sparrow/mp_utils.hpp index cfdd87375..c90fd8bde 100644 --- a/include/sparrow/mp_utils.hpp +++ b/include/sparrow/mp_utils.hpp @@ -424,4 +424,8 @@ namespace sparrow::mpl template concept boolean_like = std::is_assignable_v>, bool> and requires { static_cast(std::declval()); }; + + /// Matches range types From whose elements are convertible to elements of range type To. + template + concept convertible_ranges = std::convertible_to, std::ranges::range_value_t>; } diff --git a/include/sparrow/variable_size_binary_layout.hpp b/include/sparrow/variable_size_binary_layout.hpp index 2dc7c7a75..a60a24e65 100644 --- a/include/sparrow/variable_size_binary_layout.hpp +++ b/include/sparrow/variable_size_binary_layout.hpp @@ -14,8 +14,10 @@ #pragma once +#include #include #include +#include #include "sparrow/array_data.hpp" #include "sparrow/contracts.hpp" @@ -73,6 +75,74 @@ namespace sparrow friend class iterator_access; }; + /** + * @class vs_binary_reference + * + * @brief Implementation of reference to inner type + * used for layout L + * + * @tparam L the layout type + */ + template + class vs_binary_reference + { + public: + + using self_type = vs_binary_reference; + using value_type = typename L::inner_value_type; + using reference = typename L::inner_reference; + using const_reference = typename L::inner_const_reference; + using size_type = typename L::size_type; + using difference_type = std::ptrdiff_t; + using iterator = typename L::data_iterator; + using const_iterator = typename L::const_data_iterator; + using offset_type = typename L::offset_type; + using buffer_type = array_data::buffer_type; + + vs_binary_reference(L* layout, size_type index); + vs_binary_reference(const vs_binary_reference&) = default; + vs_binary_reference(vs_binary_reference&&) = default; + + template + requires mpl::convertible_ranges + self_type& operator=(T&& rhs); + + // This is to avoid const char* from begin caught by the previous + // operator= overload. This would converth the const char* to + // const char[N], including the null-terminating char. + template + requires std::assignable_from + self_type& operator=(const char* rhs); + + size_type size() const; + + iterator begin(); + iterator end(); + + const_iterator begin() const; + const_iterator end() const; + const_iterator cbegin() const; + const_iterator cend() const; + + template + requires mpl::convertible_ranges + bool operator==(const T& rhs) const; + + template + requires mpl::convertible_ranges + auto operator<=>(const T& rhs) const; + + private: + + offset_type offset(size_type index) const; + size_type uoffset(size_type index) const; + + buffer_type& get_data_buffer(); + + L* p_layout = nullptr; + size_type m_index; + }; + /* * @class variable_size_binary_layout * @@ -88,30 +158,31 @@ namespace sparrow * * Let's consider the array of string ['please', 'allow', 'me', 'to', 'introduce', 'myself']. * The internal buffers will be: - * - offset: [0, 6, 11, 13, 15, 24, 30] - * - data: + * - offset (i.e data_ref().buffers[0]: stored in the index `0` of array_data buffers): + * [0, 6, 11, 13, 15, 24, 30] + * - data (i.e data_ref().buffers[1]: stored in the index `1` of array_data buffers): * ['p','l','e','a','s','e','a','l','l','o','w','m','e','t','o','i','n','t','r','o','d','u','c','e','m','y','s','e','l','f'] * * @tparam T the type of the data stored in the data buffer, not its byte representation. - * @tparam R the reference type to the data. This type is different from the reference type of the layout, - * which behaves like std::optional. * @tparam CR the const reference type to the data. This type is different from the const reference of the - * layout, which behaves like std::optional. + * layout, which behaves like nullable. * @tparam OT type of the offset values. Must be std::int64_t or std::int32_t. */ - template + template class variable_size_binary_layout { public: - using self_type = variable_size_binary_layout; + using self_type = variable_size_binary_layout; using inner_value_type = T; - using inner_reference = R; + using offset_type = OT; + using inner_reference = vs_binary_reference; using inner_const_reference = CR; using bitmap_type = array_data::bitmap_type; + using bitmap_reference = typename bitmap_type::reference; using bitmap_const_reference = typename bitmap_type::const_reference; using value_type = nullable; - using reference = nullable; + using reference = nullable; using const_reference = nullable; using size_type = std::size_t; using iterator_tag = std::contiguous_iterator_tag; @@ -129,17 +200,12 @@ namespace sparrow using const_value_iterator = vs_binary_value_iterator; using const_bitmap_iterator = array_data::bitmap_type::const_iterator; + + using value_iterator = vs_binary_value_iterator; + using bitmap_iterator = array_data::bitmap_type::iterator; + using iterator = layout_iterator; - using const_iterator = layout_iterator; - // - // TODO: required by layout_iterator, replace them with the right types - // when assignment for data in a variable size bienary layout is implemented - // and implement non const overloads of `values` and `bitmap` - using value_iterator = const_value_iterator; - using bitmap_iterator = const_bitmap_iterator; - // TODO: uncomment the following line and implement the non const overloads - // of `begin` and `end` - // using iterator = layout_iterator; + using const_iterator = layout_iterator; using const_value_range = std::ranges::subrange; using const_bitmap_range = std::ranges::subrange; @@ -153,8 +219,13 @@ namespace sparrow self_type& operator=(self_type&&) = delete; size_type size() const; + + reference operator[](size_type i); const_reference operator[](size_type i) const; + iterator begin(); + iterator end(); + const_iterator cbegin() const; const_iterator cend() const; @@ -163,15 +234,28 @@ namespace sparrow private: + value_iterator value_begin(); + value_iterator value_end(); + const_value_iterator value_cbegin() const; const_value_iterator value_cend() const; + bitmap_iterator bitmap_begin(); + bitmap_iterator bitmap_end(); + const_bitmap_iterator bitmap_cbegin() const; const_bitmap_iterator bitmap_cend() const; - bool has_value(size_type i) const; + bitmap_reference has_value(size_type i); + bitmap_const_reference has_value(size_type i) const; + + inner_reference value(size_type i); inner_const_reference value(size_type i) const; + offset_iterator offset(size_type i); + offset_iterator offset_end(); + data_iterator data(size_type i); + const_offset_iterator offset(size_type i) const; const_offset_iterator offset_end() const; const_data_iterator data(size_type i) const; @@ -181,12 +265,14 @@ namespace sparrow std::reference_wrapper m_data; + friend class vs_binary_reference; friend class vs_binary_value_iterator; }; /******************************************* * vs_binary_value_iterator implementation * *******************************************/ + template vs_binary_value_iterator::vs_binary_value_iterator(layout_type* layout, size_type index) : p_layout(layout) @@ -243,12 +329,153 @@ namespace sparrow return p_layout == rhs.m_layout && m_index < rhs.m_index; } + /************************************** + * vs_binary_reference implementation * + **************************************/ + + template + vs_binary_reference::vs_binary_reference(L* layout, size_type index) + : p_layout(layout) + , m_index(index) + { + } + + template + template + requires mpl::convertible_ranges + auto vs_binary_reference::operator=(T&& rhs) -> self_type& + { + buffer_type& data_buffer = get_data_buffer(); + const auto layout_data_length = p_layout->size(); + + auto offset_beg = offset(m_index); + auto offset_end = offset(m_index + 1); + auto initial_value_length = static_cast(offset_end - offset_beg); + auto new_value_length = std::ranges::size(rhs); + if (new_value_length > initial_value_length) + { + auto shift_val = new_value_length - initial_value_length; + // Allocate tmp buffer for data + buffer_type tmp_data_buf; + tmp_data_buf.resize(data_buffer.size() + shift_val); + // Copy initial elements + std::copy(data_buffer.cbegin(), data_buffer.cbegin() + offset_beg, tmp_data_buf.begin()); + // Copy new_inner_val + std::copy(std::ranges::cbegin(rhs), std::ranges::cend(rhs), tmp_data_buf.begin() + offset_beg); + // Copy the elements left + std::copy(data_buffer.cbegin() + offset_end, data_buffer.cend(), tmp_data_buf.begin() + offset_beg + static_cast(new_value_length)); + std::swap(data_buffer, tmp_data_buf); + // Update offsets + std::for_each(p_layout->offset(m_index + 1), p_layout->offset(layout_data_length + 1), [shift_val](auto& offset){ offset += static_cast(shift_val); }); + } + else + { + std::copy(std::ranges::cbegin(rhs), std::ranges::cend(rhs), data_buffer.begin() + offset_beg); + if (new_value_length < initial_value_length) + { + std::size_t shift_val = initial_value_length - new_value_length; + // Shift values + std::copy(data_buffer.cbegin() + offset_end, data_buffer.cend(), data_buffer.begin() + offset_beg + static_cast(new_value_length)); + // Update offsets + + std::for_each(p_layout->offset(m_index+1), p_layout->offset(layout_data_length + 1), [shift_val](auto& offset){ offset -= static_cast(shift_val); }); + } + } + return *this; + } + + template + template + requires std::assignable_from + auto vs_binary_reference::operator=(const char* rhs) -> self_type& + { + return *this = std::string_view(rhs); + } + + + template + auto vs_binary_reference::size() const -> size_type + { + return static_cast(offset(m_index + 1) - offset(m_index)); + } + + template + auto vs_binary_reference::begin() -> iterator + { + return p_layout->data(uoffset(m_index)); + } + + template + auto vs_binary_reference::end() -> iterator + { + return p_layout->data(uoffset(m_index + 1)); + } + + template + auto vs_binary_reference::begin() const -> const_iterator + { + return cbegin(); + } + + template + auto vs_binary_reference::end() const -> const_iterator + { + return cend(); + } + + template + auto vs_binary_reference::cbegin() const -> const_iterator + { + return p_layout->data(uoffset(m_index)); + } + + template + auto vs_binary_reference::cend() const -> const_iterator + { + return p_layout->data(uoffset(m_index + 1)); + } + + template + template + requires mpl::convertible_ranges + bool vs_binary_reference::operator==(const T& rhs) const + { + std::string_view view(cbegin(), cend()); + return std::equal(cbegin(), cend(), std::cbegin(rhs), std::cend(rhs)); + } + + template + template + requires mpl::convertible_ranges + auto vs_binary_reference::operator<=>(const T& rhs) const + { + return std::lexicographical_compare_three_way(cbegin(), cend(), std::cbegin(rhs), std::cend(rhs)); + } + + template + auto vs_binary_reference::offset(size_type index) const -> offset_type + { + return *(p_layout->offset(index)); + } + + template + auto vs_binary_reference::uoffset(size_type index) const -> size_type + { + return static_cast(offset(index)); + } + + template + auto vs_binary_reference::get_data_buffer() -> buffer_type& + { + return p_layout->data_ref().buffers[1]; + } + /********************************************** * variable_size_binary_layout implementation * **********************************************/ - template - variable_size_binary_layout::variable_size_binary_layout(array_data& data) + template + variable_size_binary_layout::variable_size_binary_layout(array_data& data) : m_data(data) { SPARROW_ASSERT_TRUE(data_ref().buffers.size() == 2u); @@ -257,84 +484,142 @@ namespace sparrow // data_ref().buffers[1].size()); } - template - void variable_size_binary_layout::rebind_data(array_data& data) + template + void variable_size_binary_layout::rebind_data(array_data& data) { m_data = data; } - template - auto variable_size_binary_layout::size() const -> size_type + template + auto variable_size_binary_layout::size() const -> size_type { SPARROW_ASSERT_TRUE(data_ref().offset <= data_ref().length); return static_cast(data_ref().length - data_ref().offset); } - template - auto variable_size_binary_layout::operator[](size_type i) const -> const_reference + template + auto variable_size_binary_layout::operator[](size_type i) -> reference + { + SPARROW_ASSERT_TRUE(i < size()); + return reference(value(i), has_value(i)); + } + + template + auto variable_size_binary_layout::operator[](size_type i) const -> const_reference { SPARROW_ASSERT_TRUE(i < size()); return const_reference(value(i), has_value(i)); } - template - auto variable_size_binary_layout::cbegin() const -> const_iterator + template + auto variable_size_binary_layout::begin() -> iterator + { + return iterator(value_begin(), bitmap_begin()); + } + + template + auto variable_size_binary_layout::end() -> iterator + { + return iterator(value_end(), bitmap_end()); + } + + template + auto variable_size_binary_layout::cbegin() const -> const_iterator { return const_iterator(value_cbegin(), bitmap_cbegin()); } - template - auto variable_size_binary_layout::cend() const -> const_iterator + template + auto variable_size_binary_layout::cend() const -> const_iterator { return const_iterator(value_cend(), bitmap_cend()); } - template - auto variable_size_binary_layout::bitmap() const -> const_bitmap_range + template + auto variable_size_binary_layout::bitmap() const -> const_bitmap_range { return std::ranges::subrange(bitmap_cbegin(), bitmap_cend()); } - template - auto variable_size_binary_layout::values() const -> const_value_range + template + auto variable_size_binary_layout::values() const -> const_value_range { return std::ranges::subrange(value_cbegin(), value_cend()); } - template - auto variable_size_binary_layout::bitmap_cbegin() const -> const_bitmap_iterator + template + auto variable_size_binary_layout::bitmap_begin() -> bitmap_iterator + { + return data_ref().bitmap.begin() + data_ref().offset; + } + + template + auto variable_size_binary_layout::bitmap_end() -> bitmap_iterator + { + return data_ref().bitmap.end(); + } + + template + auto variable_size_binary_layout::bitmap_cbegin() const -> const_bitmap_iterator { return data_ref().bitmap.cbegin() + data_ref().offset; } - template - auto variable_size_binary_layout::bitmap_cend() const -> const_bitmap_iterator + template + auto variable_size_binary_layout::bitmap_cend() const -> const_bitmap_iterator { return data_ref().bitmap.cend(); } - template - auto variable_size_binary_layout::value_cbegin() const -> const_value_iterator + template + auto variable_size_binary_layout::value_begin() -> value_iterator + { + return value_iterator(this, data(0u)); + } + + template + auto variable_size_binary_layout::value_end() -> value_iterator + { + return value_iterator(this, size()); + } + + template + auto variable_size_binary_layout::value_cbegin() const -> const_value_iterator { return const_value_iterator(this, 0u); } - template - auto variable_size_binary_layout::value_cend() const -> const_value_iterator + template + auto variable_size_binary_layout::value_cend() const -> const_value_iterator { return const_value_iterator(this, size()); } - template - auto variable_size_binary_layout::has_value(size_type i) const -> bool + template + auto variable_size_binary_layout::has_value(size_type i) -> bitmap_reference + { + SPARROW_ASSERT_TRUE(data_ref().offset >= 0); + const size_type pos = i + static_cast(data_ref().offset); + return data_ref().bitmap[pos]; + } + + template + auto variable_size_binary_layout::has_value(size_type i) const -> bitmap_const_reference { SPARROW_ASSERT_TRUE(data_ref().offset >= 0); const size_type pos = i + static_cast(data_ref().offset); - return data_ref().bitmap.test(pos); + return data_ref().bitmap[pos]; + } + + template + auto variable_size_binary_layout::value(size_type i) -> inner_reference + { + //const size_type pos = i + static_cast(data_ref().offset); + return inner_reference(this, i); } - template - auto variable_size_binary_layout::value(size_type i) const -> inner_const_reference + template + auto variable_size_binary_layout::value(size_type i) const -> inner_const_reference { const long long offset_i = *offset(i); SPARROW_ASSERT_TRUE(offset_i >= 0); @@ -345,35 +630,56 @@ namespace sparrow return inner_const_reference(pointer1, pointer2); } - template - auto variable_size_binary_layout::offset(size_type i) const -> const_offset_iterator + template + auto variable_size_binary_layout::offset(size_type i) -> offset_iterator + { + SPARROW_ASSERT_FALSE(data_ref().buffers.empty()); + return data_ref().buffers[0].template data() + data_ref().offset + i; + } + + template + auto variable_size_binary_layout::offset_end() -> offset_iterator + { + SPARROW_ASSERT_FALSE(data_ref().buffers.empty()); + return data_ref().buffers[0].template data() + data_ref().length; + } + + template + auto variable_size_binary_layout::data(size_type i) -> data_iterator + { + SPARROW_ASSERT_FALSE(data_ref().buffers.empty()); + return data_ref().buffers[1].template data() + i; + } + + template + auto variable_size_binary_layout::offset(size_type i) const -> const_offset_iterator { SPARROW_ASSERT_FALSE(data_ref().buffers.empty()); return data_ref().buffers[0].template data() + data_ref().offset + i; } - template - auto variable_size_binary_layout::offset_end() const -> const_offset_iterator + template + auto variable_size_binary_layout::offset_end() const -> const_offset_iterator { SPARROW_ASSERT_FALSE(data_ref().buffers.empty()); return data_ref().buffers[0].template data() + data_ref().length; } - template - auto variable_size_binary_layout::data(size_type i) const -> const_data_iterator + template + auto variable_size_binary_layout::data(size_type i) const -> const_data_iterator { SPARROW_ASSERT_FALSE(data_ref().buffers.empty()); return data_ref().buffers[1].template data() + i; } - template - array_data& variable_size_binary_layout::data_ref() + template + array_data& variable_size_binary_layout::data_ref() { return m_data.get(); } - template - const array_data& variable_size_binary_layout::data_ref() const + template + const array_data& variable_size_binary_layout::data_ref() const { return m_data.get(); } diff --git a/test/test_array_data_concepts.cpp b/test/test_array_data_concepts.cpp index 50f77184e..d253620d8 100644 --- a/test/test_array_data_concepts.cpp +++ b/test/test_array_data_concepts.cpp @@ -19,10 +19,10 @@ namespace sparrow { static_assert(arrow_layout>); - static_assert(arrow_layout>); + static_assert(arrow_layout>); static_assert(arrow_layout>>); + variable_size_binary_layout>>); static_assert(!arrow_layout); static_assert(range_of_arrow_base_type_extended>); diff --git a/test/test_array_data_factory.cpp b/test/test_array_data_factory.cpp index 6689f44cf..3279cb236 100644 --- a/test/test_array_data_factory.cpp +++ b/test/test_array_data_factory.cpp @@ -51,7 +51,7 @@ namespace sparrow TEST_CASE("variable_size_binary_layout") { constexpr size_t offset = 1; - using Layout = variable_size_binary_layout; + using Layout = variable_size_binary_layout; const std::vector v = {"a", "bb", "ccc", "dddd", "eeeee"}; const dynamic_bitset bitmap(v.size(), true); array_data ar = make_default_array_data(v, bitmap, offset); @@ -75,7 +75,7 @@ namespace sparrow TEST_CASE("dictionary_encoded_layout") { constexpr size_t offset = 1; - using SubLayout = variable_size_binary_layout; + using SubLayout = variable_size_binary_layout; using Layout = dictionary_encoded_layout; const std::vector v = {"a", "bb", "ccc", "bb", "a"}; const dynamic_bitset bitmap(v.size(), true); diff --git a/test/test_dictionary_encoded_layout.cpp b/test/test_dictionary_encoded_layout.cpp index c96d0b0c4..3a300bdd4 100644 --- a/test/test_dictionary_encoded_layout.cpp +++ b/test/test_dictionary_encoded_layout.cpp @@ -85,7 +85,7 @@ namespace sparrow static constexpr std::array words{{"you", "are", "not", "prepared", "null"}}; array_data m_data; - using sub_layout_type = variable_size_binary_layout; + using sub_layout_type = variable_size_binary_layout; using layout_type = dictionary_encoded_layout; }; diff --git a/test/test_typed_array.cpp b/test/test_typed_array.cpp index 3292bc8a9..93fd17584 100644 --- a/test/test_typed_array.cpp +++ b/test/test_typed_array.cpp @@ -55,14 +55,14 @@ TEST_SUITE("typed_array") { TEST_CASE("default constructor for variable_size_binary_layout") { - using Layout = variable_size_binary_layout; + using Layout = variable_size_binary_layout; const typed_array ta_for_vsbl; CHECK_EQ(ta_for_vsbl.size(), 0); } TEST_CASE("default constructor for dictionary_encoded_layout") { - using SubLayout = variable_size_binary_layout; + using SubLayout = variable_size_binary_layout; using Layout = dictionary_encoded_layout; typed_array ta_for_dels; CHECK_EQ(ta_for_dels.size(), 0); diff --git a/test/test_variable_size_binary_layout.cpp b/test/test_variable_size_binary_layout.cpp index d4c479de4..7a647c3f5 100644 --- a/test/test_variable_size_binary_layout.cpp +++ b/test/test_variable_size_binary_layout.cpp @@ -28,7 +28,7 @@ namespace sparrow { struct vs_binary_fixture { - using layout_type = variable_size_binary_layout; + using layout_type = variable_size_binary_layout; vs_binary_fixture() { @@ -39,17 +39,11 @@ namespace sparrow static constexpr std::array words = {"you", "are", "not", "prepared"}; array_data m_data; - // TODO: replace R = std::string_view with specific reference proxy private: - std::int64_t* offset() - { - SPARROW_ASSERT_FALSE(m_data.buffers.empty()); - return m_data.buffers[0].data(); - } - static_assert(std::same_as); + static_assert(std::same_as>); static_assert(std::same_as); using const_value_iterator = layout_type::const_value_iterator; static_assert(std::same_as); @@ -87,6 +81,20 @@ namespace sparrow CHECK_EQ(cref0.value(), words[1]); CHECK(!cref1.has_value()); CHECK_EQ(cref2.value(), words[3]); + + l[0].value() = std::string("is"); + l[2].value() = std::string("unpreparedandmore"); + + CHECK_EQ(cref0.value(), std::string("is")); + CHECK(!cref1.has_value()); + CHECK_EQ(cref2.value(), std::string("unpreparedandmore")); + + l[0].value() = std::string("are"); + l[2].value() = std::string("ok"); + + CHECK_EQ(cref0.value(), std::string("are")); + CHECK(!cref1.has_value()); + CHECK_EQ(cref2.value(), std::string("ok")); } TEST_CASE_FIXTURE(vs_binary_fixture, "const_value_iterator") @@ -121,7 +129,7 @@ namespace sparrow TEST_CASE_FIXTURE(vs_binary_fixture, "const_iterator") { - layout_type l(m_data); + const layout_type l(m_data); auto cref0 = l[0]; auto cref2 = l[2]; @@ -140,5 +148,165 @@ namespace sparrow iter -= 3; CHECK_EQ(iter, l.cbegin()); } + + TEST_CASE_FIXTURE(vs_binary_fixture, "vs_binary_reference") + { + static_assert(std::ranges::sized_range); + + m_data.bitmap.set(2, true); + layout_type l(m_data); + const layout_type& cl = l; + + SUBCASE("size") + { + + auto ref0 = l[0].value(); + CHECK_EQ(ref0.size(), 3); + } + + SUBCASE("iterator") + { + auto ref0 = l[0].value(); + auto cref0 = cl[0].value(); + auto cref1 = cl[1].value(); + auto it = ref0.begin(); + auto it_end = ref0.end(); + std::fill(it, it_end, 'a'); + CHECK_EQ(cref0, "aaa"); + CHECK_EQ(cref1, words[2]); + } + + SUBCASE("const_iterator") + { + auto cref = cl[0].value(); + auto iter = cref.begin(); + auto citer = cref.cbegin(); + auto exp_iter = words[1].cbegin(); + CHECK_EQ(*iter, *exp_iter); + CHECK_EQ(*citer, *exp_iter); + ++iter, ++citer, ++exp_iter; + CHECK_EQ(*iter, *exp_iter); + CHECK_EQ(*citer, *exp_iter); + ++iter, ++citer, ++exp_iter; + CHECK_EQ(*iter, *exp_iter); + CHECK_EQ(*citer, *exp_iter); + ++iter, ++citer, ++exp_iter; + CHECK_EQ(iter, cref.end()); + CHECK_EQ(citer, cref.cend()); + } + + SUBCASE("assign_same_size") + { + auto ref0 = l[0].value(); + ref0 = "coi"; + CHECK_EQ(cl[0].value(), "coi"); + CHECK_EQ(cl[1].value(), words[2]); + CHECK_EQ(cl[2].value(), words[3]); + } + + SUBCASE("assign_larger") + { + auto ref0 = l[0].value(); + ref0 = "coin"; + CHECK_EQ(cl[0].value(), "coin"); + CHECK_EQ(cl[1].value(), words[2]); + CHECK_EQ(cl[2].value(), words[3]); + } + + SUBCASE("assign_smaller") + { + auto ref0 = l[0].value(); + ref0 = "am"; + CHECK_EQ(cl[0].value(), "am"); + CHECK_EQ(cl[1].value(), words[2]); + CHECK_EQ(cl[2].value(), words[3]); + } + + SUBCASE("assign_strings") + { + m_data.offset = 0; + + auto ref0 = l[0]; + auto ref1 = l[1]; + auto ref2 = l[2]; + auto ref3 = l[3]; + + ref3.value() = std::string_view("unpreparedandmore"); + + CHECK_EQ(ref0.value(), words[0]); + CHECK_EQ(ref1.value(), words[1]); + CHECK_EQ(ref2.value(), words[2]); + CHECK_EQ(ref3.value(), std::string("unpreparedandmore")); + + ref0.value() = std::string("he"); + ref1.value() = std::string("is"); + ref2.value() = std::string(""); + + CHECK_EQ(ref0.value(), std::string("he")); + CHECK_EQ(ref1.value(), std::string("is")); + CHECK_EQ(ref2.value(), std::string_view("")); + CHECK_EQ(ref3.value(), std::string("unpreparedandmore")); + } + + SUBCASE("assign self_type") + { + m_data.offset = 0; + auto ref0 = l[0]; + auto ref1 = l[1]; + auto ref2 = l[2]; + auto ref3 = l[3]; + + constexpr std::array replacement_words = {"this", "is", "a", "replacement"}; + + array_data::bitmap_type rpl_bitmap{replacement_words.size(), true}; + array_data rpl_vs_data = make_default_array_data(replacement_words, rpl_bitmap, 0); + + layout_type rpl_l(rpl_vs_data); + CHECK_EQ(rpl_l.size(), rpl_vs_data.length - rpl_vs_data.offset); + + vs_binary_reference rpl_vs_ref0(&rpl_l, 0); + vs_binary_reference rpl_vs_ref1(&rpl_l, 1); + vs_binary_reference rpl_vs_ref2(&rpl_l, 2); + vs_binary_reference rpl_vs_ref3(&rpl_l, 3); + + ref0.value() = std::move(rpl_vs_ref0); + ref1.value() = std::move(rpl_vs_ref1); + ref2.value() = std::move(rpl_vs_ref2); + ref3.value() = std::move(rpl_vs_ref3); + + CHECK_EQ(ref0.value(), std::string("this")); + CHECK_EQ(ref1.value(), std::string("is")); + CHECK_EQ(ref2.value(), std::string("a")); + CHECK_EQ(ref3.value(), std::string("replacement")); + } + + SUBCASE("equality_comparison") + { + m_data.offset = 0; + auto ref0 = l[0]; + auto ref3 = l[3]; + + vs_binary_reference vs_ref0(&l, 0); + CHECK_EQ(ref0.value(), vs_ref0); + + vs_binary_reference vs_ref3(&l, 3); + CHECK_EQ(ref3.value(), vs_ref3); + + CHECK_NE(ref0.value(), vs_ref3); + CHECK_NE(ref3.value(), vs_ref0); + } + + SUBCASE("inequality_comparison") + { + m_data.offset = 0; + auto ref0 = l[0].value(); + auto ref3 = l[3].value(); + + CHECK(ref3 < ref0); + CHECK(ref3 <= ref0); + CHECK(ref0 >= ref3); + CHECK(ref0 > ref3); + } + } } }