/* * 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 http://mozilla.org/MPL/2.0/. * * Copyright 2019 Danny Robson */ #pragma once #include "../debug.hpp" #include #include #include #include #include namespace cruft::map { /// A flat map structure with a static capacity store and dynamic size. template < std::size_t SizeV, typename KeyT, typename ValueT, typename ComparatorT = std::equal_to<> > class fixed { public: static constexpr auto elements = SizeV; using key_type = KeyT; using mapped_type = ValueT; using value_type = std::pair; using iterator = value_type*; /////////////////////////////////////////////////////////////////////// fixed () = default; //--------------------------------------------------------------------- fixed (std::initializer_list keyvals) { if (keyvals.size () > capacity ()) throw std::bad_alloc (); for (auto const &kv: keyvals) { auto const &[pos,success] = insert (kv); CHECK (success); (void)pos; (void)success; } } fixed (fixed&&) noexcept; fixed& operator= (fixed&&) noexcept; fixed (fixed const&); fixed& operator= (fixed const&); ~fixed () { clear (); } /////////////////////////////////////////////////////////////////////// mapped_type& at (KeyT const &key) & { ComparatorT cmp {}; for (auto &i: *this) if (cmp (i.first, key)) return i.second; throw std::out_of_range ("Element out of range"); } //--------------------------------------------------------------------- mapped_type const& at (KeyT const &key) const& { ComparatorT cmp {}; for (auto &i: *this) if (cmp (i.first, key)) return i.second; throw std::out_of_range ("Element out of range"); } //--------------------------------------------------------------------- std::pair insert (value_type const &keyval) { ComparatorT cmp {}; for (auto &i: *this) { if (cmp (i.first, keyval.first)) { return { &i, false }; } } if (m_size >= capacity ()) throw std::bad_alloc (); auto ptr = m_store.data + m_size; new (ptr) value_type (keyval); ++m_size; return { ptr, true }; } //--------------------------------------------------------------------- mapped_type const& operator[] (KeyT const &key) const { ComparatorT cmp {}; for (auto &i: *this) if (cmp (i.first, key)) return i.second; throw std::out_of_range ("Invalid key"); } //--------------------------------------------------------------------- mapped_type& operator[] (KeyT const &key) { ComparatorT cmp {}; for (auto &i: *this) if (cmp (i.first, key)) return i.second; if (m_size >= capacity ()) throw std::bad_alloc (); auto ptr = m_store.data + m_size; new (ptr) value_type ({ key, {} }); ++m_size; return ptr->second; } /////////////////////////////////////////////////////////////////////// void clear (void) { for (auto i: *this) i.~value_type (); m_size = 0; } //--------------------------------------------------------------------- auto begin (void)& { return std::begin (m_store.data); } auto end (void)& { return begin () + m_size; } auto begin (void) const& { return std::begin (m_store.data); } auto end (void) const& { return begin () + m_size; } //--------------------------------------------------------------------- auto size (void) const { return m_size; } static auto capacity (void) { return elements; } private: std::size_t m_size = 0; union storage { storage () {}; ~storage () {}; char defer; value_type data[elements]; } m_store; }; }