/* * 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/assert.hpp" #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*; using const_iterator = value_type const*; /////////////////////////////////////////////////////////////////////// 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 (); } /////////////////////////////////////////////////////////////////////// iterator find (KeyT const &key)& { ComparatorT cmp {}; for (auto cursor = begin (), last = end (); cursor != last; ++cursor) if (cmp (cursor->first, key)) return cursor; return end (); } //--------------------------------------------------------------------- const_iterator find (KeyT const &key) const& { ComparatorT cmp {}; for (auto cursor = begin (), last = end (); cursor != last; ++cursor) if (cmp (cursor->first, key)) return cursor; return end (); } /////////////////////////////////////////////////////////////////////// mapped_type& at (KeyT const &key) & { if (auto pos = find (key); pos != end ()) return pos->second; throw std::out_of_range ("Element out of range"); } //--------------------------------------------------------------------- mapped_type const& at (KeyT const &key) const& { if (auto pos = find (key); pos != end ()) return pos->second; throw std::out_of_range ("Element out of range"); } //--------------------------------------------------------------------- std::pair insert (value_type const &keyval) { if (auto pos = find (keyval.first); pos != end ()) return { pos, 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 { return at (key); } //--------------------------------------------------------------------- mapped_type& operator[] (KeyT const &key) { // If it's present, then return a reference to the value if (auto pos = find (key); pos != end ()) return pos->second; // Make space for a new entry, initialise it, and return that. 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; } //--------------------------------------------------------------------- iterator begin (void)& { return std::begin (m_store.data); } iterator end (void)& { return begin () + m_size; } const_iterator begin (void) const& { return std::begin (m_store.data); } const_iterator end (void) const& { return begin () + m_size; } const_iterator cbegin (void) const& { return begin (); } const_iterator cend (void) const& { return end (); } //--------------------------------------------------------------------- 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; }; }