map/fixed: add static sized flat map
This commit is contained in:
parent
b9f739324a
commit
9926179e7f
@ -376,6 +376,8 @@ list (
|
||||
library.hpp
|
||||
log.cpp
|
||||
log.hpp
|
||||
map/fixed.cpp
|
||||
map/fixed.hpp
|
||||
maths.cpp
|
||||
maths.hpp
|
||||
maths/fast.hpp
|
||||
@ -603,6 +605,7 @@ if (TESTS)
|
||||
job/dispatch
|
||||
job/queue
|
||||
kmeans
|
||||
map/fixed
|
||||
maths
|
||||
maths/fast
|
||||
matrix
|
||||
|
1
map/fixed.cpp
Normal file
1
map/fixed.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "fixed.hpp"
|
157
map/fixed.hpp
Normal file
157
map/fixed.hpp
Normal file
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* 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 <cruft/util/debug.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <utility>
|
||||
#include <stdexcept>
|
||||
|
||||
#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>
|
||||
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*;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
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 (); }
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
mapped_type& at (KeyT const &key) &
|
||||
{
|
||||
for (auto &i: *this)
|
||||
if (i.first == key)
|
||||
return i.second;
|
||||
|
||||
throw std::out_of_range ("Element out of range");
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
mapped_type const& at (KeyT const &key) const&
|
||||
{
|
||||
for (auto &i: *this)
|
||||
if (i.first == key)
|
||||
return i.second;
|
||||
|
||||
throw std::out_of_range ("Element out of range");
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
std::pair<iterator,bool> insert (value_type const &keyval)
|
||||
{
|
||||
for (auto &i: *this) {
|
||||
if (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& operator[] (KeyT const &key)
|
||||
{
|
||||
for (auto &i: *this)
|
||||
if (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;
|
||||
};
|
||||
}
|
26
test/map/fixed.cpp
Normal file
26
test/map/fixed.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
#include "tap.hpp"
|
||||
|
||||
#include "map/fixed.hpp"
|
||||
|
||||
int main ()
|
||||
{
|
||||
cruft::TAP::logger tap;
|
||||
|
||||
cruft::map::fixed<4, int,std::string> map;
|
||||
|
||||
auto const [pos, success] = map.insert ({ 0, "zero" });
|
||||
tap.expect (success, "map insertion reports success");
|
||||
|
||||
tap.expect_eq (pos->second, "zero", "inserted value is equal");
|
||||
|
||||
map.insert ({ 1, "one" });
|
||||
map.insert ({ 2, "two" });
|
||||
map.insert ({ 3, "three" });
|
||||
|
||||
tap.expect_throw<std::bad_alloc> (
|
||||
[&] () { map.insert ({ 4, "four" }); },
|
||||
"over-allocation throws bad_alloc"
|
||||
);
|
||||
|
||||
return tap.status ();
|
||||
}
|
Loading…
Reference in New Issue
Block a user