/* * 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 > class HashMap; } // namespace fud namespace fud::detail { enum class BucketState : uint8_t { Disengaged, Engaged, Tombstoned }; template struct MapEntry { static_assert(!std::is_same_v); static_assert(!std::is_same_v); static_assert(!std::is_reference_v); static_assert(!std::is_reference_v); 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(m_keyData.data()); } [[nodiscard]] constexpr const Value& value() const& { fudAssert(hasValue()); return *std::bit_cast(m_valueData.data()); } [[nodiscard]] constexpr Key& key() & { fudAssert(hasValue()); return *std::bit_cast(m_keyData.data()); } [[nodiscard]] constexpr Value& value() & { fudAssert(hasValue()); return *std::bit_cast(m_valueData.data()); } [[nodiscard]] constexpr Key&& takeKey() & { fudAssert(hasValue()); return std::move(*std::bit_cast(m_keyData.data())); } [[nodiscard]] constexpr Value&& takeValue() & { fudAssert(hasValue()); return std::move(*std::bit_cast(m_valueData.data())); } constexpr void tombstone() noexcept { destroy(true); } constexpr void destroy(bool entomb) noexcept { if (m_state == BucketState::Engaged) { std::bit_cast(m_keyData.data())->~Key(); m_keyData.clear(); std::bit_cast(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 m_keyData{}; alignas(alignof(Value)) option_detail::DataArray m_valueData{}; BucketState m_state{BucketState::Disengaged}; }; } // namespace fud::detail #endif