From c946cf6a89bbeae7fb96a67b55d91b7ae0cfa48d Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 30 Mar 2026 12:41:14 +0000 Subject: kstd/flat_map: fix iterator reference --- libs/kstd/include/kstd/bits/flat_map.hpp | 108 ++++++++++++++++++++++++++++++- libs/kstd/tests/src/flat_map.cpp | 25 +++++++ 2 files changed, 131 insertions(+), 2 deletions(-) (limited to 'libs') 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 #include #include +#include +#include +#include #include namespace kstd::bits { + template + 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 + requires(std::tuple_size_v> == 2) + constexpr auto operator=(TupleLikeType && tuple) const -> flat_map_reference const & + { + second = std::forward(tuple).second; + return *this; + } + + template + 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 + 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 struct flat_map_iterator { using iterator_category = std::random_access_iterator_tag; using value_type = std::pair; using difference_type = std::ptrdiff_t; - using reference = std::pair; - using pointer = void; + using reference = flat_map_reference; + using pointer = flat_map_pointer; + + 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 + requires(std::convertible_to && + std::convertible_to) + constexpr flat_map_iterator( + flat_map_iterator 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 +struct std::tuple_size> : std::integral_constant +{ +}; + +template +struct std::tuple_element<0, kstd::bits::flat_map_reference> +{ + using type = K const &; +}; + +template +struct std::tuple_element<1, kstd::bits::flat_map_reference> +{ + 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 #include +#include +#include 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); + STATIC_REQUIRE(std::is_same_v); + } } WHEN("using reverse iterators") -- cgit v1.2.3