diff options
Diffstat (limited to 'libs')
| -rw-r--r-- | libs/kstd/include/kstd/bits/flat_map.hpp | 108 | ||||
| -rw-r--r-- | libs/kstd/tests/src/flat_map.cpp | 25 |
2 files changed, 131 insertions, 2 deletions
diff --git a/libs/kstd/include/kstd/bits/flat_map.hpp b/libs/kstd/include/kstd/bits/flat_map.hpp index 903841e..9455549 100644 --- a/libs/kstd/include/kstd/bits/flat_map.hpp +++ b/libs/kstd/include/kstd/bits/flat_map.hpp @@ -1,27 +1,107 @@ #ifndef KSTD_BITS_FLAT_MAP_HPP #define KSTD_BITS_FLAT_MAP_HPP +#include <concepts> #include <cstddef> #include <iterator> +#include <memory> +#include <tuple> +#include <type_traits> #include <utility> namespace kstd::bits { + template<typename KeyType, typename MappedType> + struct flat_map_reference + { + using key_type = KeyType; + using mapped_type = MappedType; + + constexpr flat_map_reference(key_type const & key, mapped_type & mapped) + : first{key} + , second{mapped} + {} + + constexpr auto operator=(flat_map_reference const & other) const -> flat_map_reference const & + { + second = other.second; + return *this; + } + + constexpr auto operator=(flat_map_reference && other) const -> flat_map_reference const & + { + second = std::move(other.second); + return *this; + } + + template<typename TupleLikeType> + requires(std::tuple_size_v<std::remove_cvref_t<TupleLikeType>> == 2) + constexpr auto operator=(TupleLikeType && tuple) const -> flat_map_reference const & + { + second = std::forward<TupleLikeType>(tuple).second; + return *this; + } + + template<std::size_t Index> + requires(Index >= 0 && Index <= 1) + constexpr auto get() const noexcept -> decltype(auto) + { + if constexpr (Index == 0) + { + return (first); + } + else + { + return (second); + } + } + + key_type const & first; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members) + mapped_type & second; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members) + }; + + template<typename Reference> + struct flat_map_pointer + { + Reference reference; + + [[nodiscard]] constexpr auto operator->() noexcept -> Reference * + { + return std::addressof(reference); + } + + [[nodiscard]] constexpr auto operator->() const noexcept -> Reference const * + { + return std::addressof(reference); + } + }; + template<typename KeyType, typename MappedType, typename KeyIterator, typename MappedIterator> struct flat_map_iterator { using iterator_category = std::random_access_iterator_tag; using value_type = std::pair<KeyType, MappedType>; using difference_type = std::ptrdiff_t; - using reference = std::pair<KeyType const &, MappedType &>; - using pointer = void; + using reference = flat_map_reference<KeyType, MappedType>; + using pointer = flat_map_pointer<reference>; + + constexpr flat_map_iterator() = default; constexpr flat_map_iterator(KeyIterator key_iterator, MappedIterator mapped_iterator) : m_key_iterator{key_iterator} , m_mapped_iterator{mapped_iterator} {} + template<typename OtherMappedType, typename OtherKeyIterator, typename OtherMappedIterator> + requires(std::convertible_to<OtherKeyIterator, KeyIterator> && + std::convertible_to<OtherMappedIterator, MappedIterator>) + constexpr flat_map_iterator( + flat_map_iterator<KeyType, OtherMappedType, OtherKeyIterator, OtherMappedIterator> const & other) noexcept + : m_key_iterator{other.m_key_iterator} + , m_mapped_iterator{other.m_mapped_iterator} + {} + [[nodiscard]] auto key_iterator() const noexcept -> KeyIterator { return m_key_iterator; @@ -32,6 +112,13 @@ namespace kstd::bits return {*m_key_iterator, *m_mapped_iterator}; } + [[nodiscard]] constexpr auto operator->() const noexcept -> pointer + { + return { + {*m_key_iterator, *m_mapped_iterator} + }; + } + constexpr auto operator++() noexcept -> flat_map_iterator & { ++m_key_iterator; @@ -79,4 +166,21 @@ namespace kstd::bits } // namespace kstd::bits +template<typename K, typename M> +struct std::tuple_size<kstd::bits::flat_map_reference<K, M>> : std::integral_constant<std::size_t, 2> +{ +}; + +template<typename K, typename M> +struct std::tuple_element<0, kstd::bits::flat_map_reference<K, M>> +{ + using type = K const &; +}; + +template<typename K, typename M> +struct std::tuple_element<1, kstd::bits::flat_map_reference<K, M>> +{ + using type = M &; +}; + #endif
\ No newline at end of file diff --git a/libs/kstd/tests/src/flat_map.cpp b/libs/kstd/tests/src/flat_map.cpp index cde136a..eb599af 100644 --- a/libs/kstd/tests/src/flat_map.cpp +++ b/libs/kstd/tests/src/flat_map.cpp @@ -4,6 +4,8 @@ #include <catch2/catch_test_macros.hpp> #include <functional> +#include <type_traits> +#include <utility> SCENARIO("Flat Map initialization and construction", "[flat_map]") { @@ -159,6 +161,29 @@ SCENARIO("Flat Map iterators", "[flat_map]") ++it; REQUIRE(it == map.cend()); } + + THEN("assignment through the proxy modifies the mapped value") + { + auto it = map.begin(); + + *it = std::pair{1, 100}; + + REQUIRE(it->second == 100); + REQUIRE(map.at(1) == 100); + } + + THEN("structured bindings evaluate correctly") + { + auto it = map.cbegin(); + + auto [key, value] = *it; + + REQUIRE(key == 1); + REQUIRE(value == 10); + + STATIC_REQUIRE(std::is_same_v<decltype(key), int const &>); + STATIC_REQUIRE(std::is_same_v<decltype(value), int const &>); + } } WHEN("using reverse iterators") |
