map/fixed: add static sized flat map
This commit is contained in:
parent
b9f739324a
commit
9926179e7f
@ -376,6 +376,8 @@ list (
|
|||||||
library.hpp
|
library.hpp
|
||||||
log.cpp
|
log.cpp
|
||||||
log.hpp
|
log.hpp
|
||||||
|
map/fixed.cpp
|
||||||
|
map/fixed.hpp
|
||||||
maths.cpp
|
maths.cpp
|
||||||
maths.hpp
|
maths.hpp
|
||||||
maths/fast.hpp
|
maths/fast.hpp
|
||||||
@ -603,6 +605,7 @@ if (TESTS)
|
|||||||
job/dispatch
|
job/dispatch
|
||||||
job/queue
|
job/queue
|
||||||
kmeans
|
kmeans
|
||||||
|
map/fixed
|
||||||
maths
|
maths
|
||||||
maths/fast
|
maths/fast
|
||||||
matrix
|
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…
x
Reference in New Issue
Block a user