/* * Copyright 2015 - 2025 gary@drinkingtea.net * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once #include "def.hpp" #include "hash.hpp" #include "ignore.hpp" #include "stringview.hpp" #include "strops.hpp" #include "vector.hpp" namespace ox { template class SmallMap { public: using key_t = K; using value_t = T; struct Pair { K key = {}; T value{}; }; protected: using PairVector = Vector; PairVector m_pairs; public: constexpr SmallMap() = default; constexpr SmallMap(SmallMap const&other); constexpr SmallMap(SmallMap &&other) noexcept; constexpr bool operator==(SmallMap const&other) const; constexpr SmallMap &operator=(SmallMap const&other); constexpr SmallMap &operator=(SmallMap &&other) noexcept; constexpr T &operator[](MaybeView_t const&key); constexpr Result at(MaybeView_t const&key) noexcept; constexpr Result at(MaybeView_t const&key) const noexcept; constexpr void erase(MaybeView_t const&key); [[nodiscard]] constexpr bool contains(MaybeView_t const&key) const noexcept; [[nodiscard]] constexpr std::size_t size() const noexcept; [[nodiscard]] constexpr Vector keys() const noexcept; [[nodiscard]] constexpr Vector values() const noexcept; [[nodiscard]] constexpr K const&key(size_t i) const noexcept; [[nodiscard]] constexpr T const&value(size_t i) const noexcept; [[nodiscard]] constexpr T &value(size_t i) noexcept; [[nodiscard]] constexpr Pair const&get(size_t i) const noexcept; [[nodiscard]] constexpr Pair &get(size_t i) noexcept; [[nodiscard]] constexpr ox::SpanView pairs() const noexcept { return m_pairs; } [[nodiscard]] constexpr ox::Span pairs() noexcept { return m_pairs; } constexpr void clear(); private: template constexpr Pair const*access(PairVector const&pairs, KK const&key, bool &isNew) const; template constexpr Pair *access(PairVector &pairs, KK const&key, bool &isNew); template constexpr Pair *accessNoCreate(PairVector &pairs, KK const&key); }; template constexpr SmallMap::SmallMap(SmallMap const&other) { m_pairs = other.m_pairs; } template constexpr SmallMap::SmallMap(SmallMap &&other) noexcept { m_pairs = std::move(other.m_pairs); } template constexpr bool SmallMap::operator==(SmallMap const&other) const { return m_pairs == other.m_pairs; } template constexpr SmallMap &SmallMap::operator=(SmallMap const&other) { if (this != &other) { clear(); m_pairs = other.m_pairs; } return *this; } template constexpr SmallMap &SmallMap::operator=(SmallMap &&other) noexcept { if (this != &other) { clear(); m_pairs = std::move(other.m_pairs); } return *this; } template constexpr T &SmallMap::operator[](MaybeView_t const&k) { bool isNew{}; auto p = access(m_pairs, k, isNew); if (isNew) { p->key = k; } return p->value; } template constexpr Result SmallMap::at(MaybeView_t const&k) noexcept { auto const p = accessNoCreate(m_pairs, k); if (!p) { return {nullptr, ox::Error(1, "value not found for given key")}; } return &p->value; } template constexpr Result SmallMap::at(MaybeView_t const&k) const noexcept { bool isNew{}; auto p = access(m_pairs, k, isNew); if (!p) { return {nullptr, ox::Error(1, "value not found for given key")}; } return &p->value; } template constexpr void SmallMap::erase(MaybeView_t const&k) { size_t i{}; for (auto const&p : m_pairs) { if (k == p.key) { break; } ++i; } std::ignore = m_pairs.erase(i); } template constexpr bool SmallMap::contains(MaybeView_t const&k) const noexcept { bool isNew{}; return access(m_pairs, k, isNew) != nullptr; } template constexpr std::size_t SmallMap::size() const noexcept { return m_pairs.size(); } template constexpr Vector SmallMap::keys() const noexcept { ox::Vector keys; keys.reserve(m_pairs.size()); for (auto const&p : m_pairs) { keys.emplace_back(p.key); } return keys; } template constexpr Vector SmallMap::values() const noexcept { ox::Vector keys; keys.reserve(m_pairs.size()); for (auto const&p : m_pairs) { keys.emplace_back(p.key); } return keys; } template constexpr K const&SmallMap::key(size_t i) const noexcept { return m_pairs[i].key; } template constexpr T const&SmallMap::value(size_t i) const noexcept { return m_pairs[i].value; } template constexpr T &SmallMap::value(size_t i) noexcept { return m_pairs[i].value; } template constexpr typename SmallMap::Pair const&SmallMap::get(size_t i) const noexcept { return m_pairs[i]; } template constexpr typename SmallMap::Pair &SmallMap::get(size_t i) noexcept { return m_pairs[i]; } template constexpr void SmallMap::clear() { m_pairs.clear(); } template template constexpr typename SmallMap::Pair const*SmallMap::access( PairVector const&pairs, KK const&k, bool &isNew) const { for (auto const&p : pairs) { if (p.key == k) { isNew = false; return &p; } } isNew = true; return nullptr; } template template constexpr typename SmallMap::Pair *SmallMap::access( PairVector &pairs, KK const&k, bool &isNew) { for (auto &p : pairs) { if (p.key == k) { isNew = false; return &p; } } isNew = true; return &pairs.emplace_back(); } template template constexpr typename SmallMap::Pair *SmallMap::accessNoCreate( PairVector &pairs, KK const&k) { for (auto &p : pairs) { if (p.key == k) { return &p; } } return nullptr; } template constexpr Error model(T *io, ox::CommonPtrWith> auto *obj) noexcept { using Map = SmallMap; OX_RETURN_ERROR(io->template setTypeInfo()); OX_RETURN_ERROR(io->field("pairs", &obj->m_pairs)); return {}; } }