summaryrefslogtreecommitdiff
path: root/include/fud_hash_map_impl.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'include/fud_hash_map_impl.hpp')
-rw-r--r--include/fud_hash_map_impl.hpp180
1 files changed, 180 insertions, 0 deletions
diff --git a/include/fud_hash_map_impl.hpp b/include/fud_hash_map_impl.hpp
new file mode 100644
index 0000000..e4b79c4
--- /dev/null
+++ b/include/fud_hash_map_impl.hpp
@@ -0,0 +1,180 @@
+/*
+ * libfud
+ * Copyright 2025 Dominick Allen
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FUD_HASH_MAP_IMPL_HPP
+#define FUD_HASH_MAP_IMPL_HPP
+
+#include "fud_hash.hpp"
+
+namespace fud {
+
+template <typename Key, typename Value, typename Hash = detail::DefaultHash<Key>>
+class HashMap;
+
+} // namespace fud
+
+namespace fud::detail {
+
+enum class BucketState : uint8_t
+{
+ Disengaged,
+ Engaged,
+ Tombstoned
+};
+
+template <typename Key, typename Value>
+struct MapEntry {
+ static_assert(!std::is_same_v<Key, option_detail::NullOptionType>);
+ static_assert(!std::is_same_v<Value, option_detail::NullOptionType>);
+ static_assert(!std::is_reference_v<Key>);
+ static_assert(!std::is_reference_v<Value>);
+
+ constexpr MapEntry() noexcept : m_state{BucketState::Disengaged}
+ {
+ }
+
+ constexpr MapEntry(const Key& key, const Value& value) : m_state{BucketState::Engaged}
+ {
+ new (m_keyData.data()) Key(key);
+ new (m_valueData.data()) Value(value);
+ }
+
+ constexpr MapEntry(Key&& key, const Value& value) : m_state{BucketState::Engaged}
+ {
+ new (m_keyData.data()) Key(std::move(key));
+ new (m_valueData.data()) Value(value);
+ }
+
+ constexpr MapEntry(const Key& key, Value&& value) : m_state{BucketState::Engaged}
+ {
+ new (m_keyData.data()) Key(key);
+ new (m_valueData.data()) Value(std::move(value));
+ }
+
+ constexpr MapEntry(Key&& key, Value&& value) : m_state{BucketState::Engaged}
+ {
+ new (m_keyData.data()) Key(std::move(key));
+ new (m_valueData.data()) Value(std::move(value));
+ }
+
+ constexpr MapEntry(const MapEntry& rhs) noexcept :
+ m_keyData(rhs.m_keyData), m_valueData(rhs.m_valueData), m_state(rhs.m_state)
+ {
+ }
+
+ constexpr MapEntry(MapEntry&& rhs) noexcept :
+ m_keyData(std::move(rhs.m_keyData)), m_valueData(std::move(rhs.m_valueData)), m_state(rhs.m_state)
+ {
+ rhs.destroy(false);
+ }
+
+ constexpr MapEntry& operator=(const MapEntry& rhs) noexcept
+ {
+ if (&rhs == this) {
+ return *this;
+ }
+ destroy(false);
+ m_keyData = rhs.m_keyData;
+ m_valueData = rhs.m_valueData;
+ m_state = rhs.m_state;
+ return *this;
+ }
+
+ constexpr MapEntry& operator=(MapEntry&& rhs) noexcept
+ {
+ if (&rhs == this) {
+ return *this;
+ }
+ destroy(false);
+ m_keyData = rhs.m_keyData;
+ m_valueData = rhs.m_valueData;
+ m_state = rhs.m_state;
+ rhs.destroy(false);
+ return *this;
+ }
+
+ constexpr ~MapEntry() noexcept
+ {
+ destroy(false);
+ }
+
+ [[nodiscard]] constexpr bool hasValue() const
+ {
+ return m_state == BucketState::Engaged;
+ }
+
+ [[nodiscard]] constexpr bool isNone() const
+ {
+ return m_state == BucketState::Disengaged;
+ }
+
+ [[nodiscard]] constexpr bool isTombstone() const
+ {
+ return m_state == BucketState::Tombstoned;
+ }
+
+ [[nodiscard]] constexpr const Key& key() const&
+ {
+ fudAssert(hasValue());
+ return *std::bit_cast<const Key*>(m_keyData.data());
+ }
+
+ [[nodiscard]] constexpr const Value& value() const&
+ {
+ fudAssert(hasValue());
+ return *std::bit_cast<const Value*>(m_valueData.data());
+ }
+
+ [[nodiscard]] constexpr Key& key() &
+ {
+ fudAssert(hasValue());
+ return *std::bit_cast<Key*>(m_keyData.data());
+ }
+
+ [[nodiscard]] constexpr Value& value() &
+ {
+ fudAssert(hasValue());
+ return *std::bit_cast<Value*>(m_valueData.data());
+ }
+
+ constexpr void tombstone() noexcept
+ {
+ destroy(true);
+ }
+
+ constexpr void destroy(bool entomb) noexcept
+ {
+ if (m_state == BucketState::Engaged) {
+ std::bit_cast<Key*>(m_keyData.data())->~Key();
+ m_keyData.clear();
+ std::bit_cast<Value*>(m_valueData.data())->~Value();
+ m_valueData.clear();
+ m_state = entomb ? BucketState::Tombstoned : BucketState::Disengaged;
+ } else if (m_state == BucketState::Tombstoned and not entomb) {
+ m_state = BucketState::Disengaged;
+ }
+ }
+
+ static constexpr auto Align = max(alignof(Key), alignof(Value));
+ alignas(alignof(Key)) option_detail::DataArray<sizeof(Key)> m_keyData{};
+ alignas(alignof(Value)) option_detail::DataArray<sizeof(Value)> m_valueData{};
+ BucketState m_state{BucketState::Disengaged};
+};
+
+} // namespace fud::detail
+
+#endif