diff options
Diffstat (limited to 'include/fud_hash_map_impl.hpp')
-rw-r--r-- | include/fud_hash_map_impl.hpp | 180 |
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 |