aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/kstd/include/kstd/bits/flat_map.hpp108
-rw-r--r--libs/kstd/tests/src/flat_map.cpp25
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")