188 lines
5.3 KiB
C++
188 lines
5.3 KiB
C++
/*
|
|
* 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 <danny@nerdcruft.net>
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "../debug/assert.hpp"
|
|
|
|
#include <utility>
|
|
#include <stdexcept>
|
|
#include <functional>
|
|
|
|
#include <cstddef>
|
|
|
|
|
|
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<KeyT,ValueT>;
|
|
|
|
using iterator = value_type*;
|
|
using const_iterator = value_type const*;
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
fixed () = default;
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
fixed (std::initializer_list<value_type> 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<iterator,bool> 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;
|
|
};
|
|
}
|