map/multi_fixed: add insert, erase, find, comparators
This commit is contained in:
parent
9439f76ddd
commit
24d31b216b
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include "../iterator/unordered_insert.hpp"
|
#include "../iterator/unordered_insert.hpp"
|
||||||
#include "../iterator/placement_output.hpp"
|
#include "../iterator/placement_output.hpp"
|
||||||
|
#include "../iterator/tuple_picker.hpp"
|
||||||
#include "../cast.hpp"
|
#include "../cast.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -20,6 +21,7 @@
|
|||||||
|
|
||||||
|
|
||||||
namespace cruft::map {
|
namespace cruft::map {
|
||||||
|
/// A multi-map with a compile-time fixed-size backing store.
|
||||||
template <
|
template <
|
||||||
std::size_t SizeV,
|
std::size_t SizeV,
|
||||||
typename KeyT,
|
typename KeyT,
|
||||||
@ -71,7 +73,19 @@ namespace cruft::map {
|
|||||||
}
|
}
|
||||||
|
|
||||||
multi_fixed (multi_fixed const&);
|
multi_fixed (multi_fixed const&);
|
||||||
multi_fixed (multi_fixed &&) noexcept;
|
|
||||||
|
multi_fixed (multi_fixed &&rhs) noexcept (std::is_nothrow_move_constructible_v<value_type>)
|
||||||
|
{
|
||||||
|
clear ();
|
||||||
|
|
||||||
|
while (m_size != rhs.m_size) {
|
||||||
|
new (m_store.data + m_size) value_type (std::move (rhs.m_store.data[m_size]));
|
||||||
|
++m_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
multi_fixed& operator= (multi_fixed&&) noexcept (std::is_nothrow_move_assignable_v<value_type>) = default;
|
||||||
|
multi_fixed& operator= (multi_fixed const&) noexcept (std::is_nothrow_assignable_v<value_type>) = default;
|
||||||
|
|
||||||
iterator begin (void)& { return m_store.data + 0; }
|
iterator begin (void)& { return m_store.data + 0; }
|
||||||
iterator end (void)& { return m_store.data + m_size; }
|
iterator end (void)& { return m_store.data + m_size; }
|
||||||
@ -93,7 +107,8 @@ namespace cruft::map {
|
|||||||
// avoid moving too many key-value pairs backwards to make room
|
// avoid moving too many key-value pairs backwards to make room
|
||||||
// for the data.
|
// for the data.
|
||||||
auto cursor = begin ();
|
auto cursor = begin ();
|
||||||
while (cursor->first <= kv.first && cursor != end ())
|
ComparatorT cmp {};
|
||||||
|
while (cmp (cursor->first, kv.first) && cursor != end ())
|
||||||
++cursor;
|
++cursor;
|
||||||
|
|
||||||
// Shuffle the items back in the storage.
|
// Shuffle the items back in the storage.
|
||||||
@ -169,15 +184,118 @@ namespace cruft::map {
|
|||||||
template <typename K>
|
template <typename K>
|
||||||
const_iterator find (K const&) const&;
|
const_iterator find (K const&) const&;
|
||||||
|
|
||||||
|
template <typename K>
|
||||||
|
iterator
|
||||||
|
lower_bound (K const &k)&
|
||||||
|
{
|
||||||
|
ComparatorT cmp {};
|
||||||
|
return std::find_if (
|
||||||
|
begin (),
|
||||||
|
end (),
|
||||||
|
[&] (auto const &val) { return !cmp (val.first, k); }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename K>
|
||||||
|
iterator
|
||||||
|
upper_bound (K const &k)&
|
||||||
|
{
|
||||||
|
ComparatorT cmp {};
|
||||||
|
return std::find_if (
|
||||||
|
begin (),
|
||||||
|
end (),
|
||||||
|
[&] (auto const &val) { return cmp (k, val.first); }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename K>
|
template <typename K>
|
||||||
std::pair<iterator, iterator>
|
std::pair<iterator, iterator>
|
||||||
equal_range (K const&)&;
|
equal_range (K const &key)&
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
lower_bound (key),
|
||||||
|
upper_bound (key)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
void clear (void);
|
void clear (void)
|
||||||
|
{
|
||||||
|
for (std::size_t i = 0; i < m_size; ++i)
|
||||||
|
m_store.data[i].~value_type ();
|
||||||
|
m_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void erase (iterator it)
|
||||||
|
{
|
||||||
|
CHECK_GE (it, begin ());
|
||||||
|
CHECK_LT (it, end ());
|
||||||
|
CHECK (!empty ());
|
||||||
|
|
||||||
|
std::move (it + 1, end (), it);
|
||||||
|
--m_size;
|
||||||
|
m_store.data[m_size].~value_type ();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t erase (key_type const&);
|
||||||
|
|
||||||
|
bool empty (void) const { return m_size == 0; }
|
||||||
auto size (void) const { return m_size; }
|
auto size (void) const { return m_size; }
|
||||||
auto capacity (void) const { return elements; }
|
auto capacity (void) const { return elements; }
|
||||||
|
|
||||||
|
void swap (multi_fixed &rhs)
|
||||||
|
{
|
||||||
|
// To save duplicating the code which moves the trailing excess
|
||||||
|
// items between containers we instead just reverse the direction
|
||||||
|
// here.
|
||||||
|
if (rhs.size () > size ())
|
||||||
|
rhs.swap (*this);
|
||||||
|
|
||||||
|
using std::swap;
|
||||||
|
|
||||||
|
// Swap the commonly held indices
|
||||||
|
std::size_t const common = std::min (size (), rhs.size ());
|
||||||
|
for (std::size_t i = 0; i != common; ++i)
|
||||||
|
swap (m_store.data[i], rhs.m_store.data[i]);
|
||||||
|
|
||||||
|
// Move our indices to the rhs if we're larger. We don't need the
|
||||||
|
// reverse case because we took care of that earlier.
|
||||||
|
CHECK_GE (size (), rhs.size ());
|
||||||
|
if (size () > common) {
|
||||||
|
for (std::size_t i = common; i < size (); ++i)
|
||||||
|
new (rhs.m_store.data + i) value_type (std::move (m_store.data[i]));
|
||||||
|
|
||||||
|
swap (m_size, rhs.m_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A helper class that allows iteration over the keys of a
|
||||||
|
/// multi_fixed map.
|
||||||
|
///
|
||||||
|
/// The iterators it provides may be invalidated if any mutating
|
||||||
|
/// operations are performed on the underlying multi_fixed object.
|
||||||
|
class keys_proxy {
|
||||||
|
public:
|
||||||
|
using iterator_category = std::random_access_iterator_tag;
|
||||||
|
using value_type = KeyT;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using pointer = value_type*;
|
||||||
|
using reference = value_type&;
|
||||||
|
|
||||||
|
keys_proxy (multi_fixed const &_parent)
|
||||||
|
: m_parent (&_parent)
|
||||||
|
{ ; }
|
||||||
|
|
||||||
|
auto begin (void) const { return cruft::iterator::make_tuple_picker<0> (m_parent->begin ()); }
|
||||||
|
auto end (void) const { return cruft::iterator::make_tuple_picker<0> (m_parent->end ()); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
multi_fixed const *m_parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Returns a container that allows traversal of the underlying keys
|
||||||
|
/// of the store.
|
||||||
|
keys_proxy keys (void) const& { return keys_proxy (*this); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::size_t m_size = 0;
|
std::size_t m_size = 0;
|
||||||
|
|
||||||
@ -191,6 +309,20 @@ namespace cruft::map {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <
|
||||||
|
std::size_t SizeV,
|
||||||
|
typename KeyT,
|
||||||
|
typename ValueT,
|
||||||
|
typename ComparatorT
|
||||||
|
>
|
||||||
|
void swap (
|
||||||
|
multi_fixed<SizeV, KeyT, ValueT, ComparatorT> &a,
|
||||||
|
multi_fixed<SizeV, KeyT, ValueT, ComparatorT> &b
|
||||||
|
) {
|
||||||
|
a.swap (b);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Returns a concatenation of two multi_fixed maps. ie, a copy of
|
/// Returns a concatenation of two multi_fixed maps. ie, a copy of
|
||||||
/// all entries in the first map, and all entries in the second map.
|
/// all entries in the first map, and all entries in the second map.
|
||||||
///
|
///
|
||||||
|
@ -73,6 +73,20 @@ int main ()
|
|||||||
tap.expect_eq (a - b, expected, "difference of two sets");
|
tap.expect_eq (a - b, expected, "difference of two sets");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
cruft::map::multi_fixed<4, int, int> init {{ {0,0}, {1,1}, {2,2}, {3,3} }};
|
||||||
|
init.erase (init.find (2));
|
||||||
|
cruft::map::multi_fixed<4, int, int> expected {{ {0,0}, {1,1}, {3,3} }};
|
||||||
|
tap.expect_eq (init, expected, "erase of inner element");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
cruft::map::multi_fixed<4, int, int> init {{ {0,0}, {1,1}, {2,2}, {3,3} }};
|
||||||
|
init.erase (init.find (3));
|
||||||
|
cruft::map::multi_fixed<4, int, int> expected {{ {0,0}, {1,1}, {2,2} }};
|
||||||
|
tap.expect_eq (init, expected, "erase of last element");
|
||||||
|
}
|
||||||
|
|
||||||
test_sorted_iterators (tap);
|
test_sorted_iterators (tap);
|
||||||
test_bad_alloc (tap);
|
test_bad_alloc (tap);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user