set: add a simple static-alloc, dynamic-resize, set
This commit is contained in:
parent
831a7b7037
commit
a392ca1aa9
@ -505,6 +505,8 @@ list (
|
|||||||
registrar.hpp
|
registrar.hpp
|
||||||
roots/bisection.hpp
|
roots/bisection.hpp
|
||||||
scoped.hpp
|
scoped.hpp
|
||||||
|
set/dset.cpp
|
||||||
|
set/dset.hpp
|
||||||
signal.cpp
|
signal.cpp
|
||||||
signal.hpp
|
signal.hpp
|
||||||
singleton.hpp
|
singleton.hpp
|
||||||
@ -725,6 +727,7 @@ if (TESTS)
|
|||||||
registrar
|
registrar
|
||||||
roots/bisection
|
roots/bisection
|
||||||
scoped
|
scoped
|
||||||
|
set/dset
|
||||||
signal
|
signal
|
||||||
singleton
|
singleton
|
||||||
stream
|
stream
|
||||||
|
9
set/dset.cpp
Normal file
9
set/dset.cpp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* 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 2020, Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "./dset.hpp"
|
207
set/dset.hpp
Normal file
207
set/dset.hpp
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
/*
|
||||||
|
* 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 2020, Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
|
||||||
|
namespace cruft::set {
|
||||||
|
/// A multiset container whose storage is a constant capacity fixed at
|
||||||
|
/// compile time.
|
||||||
|
template <
|
||||||
|
typename ValueT,
|
||||||
|
std::size_t MaxV
|
||||||
|
>
|
||||||
|
struct dset {
|
||||||
|
public:
|
||||||
|
using value_type = ValueT;
|
||||||
|
using pointer = value_type*;
|
||||||
|
using const_pointer = value_type const*;
|
||||||
|
using reference = value_type&;
|
||||||
|
using const_reference = value_type const&;
|
||||||
|
|
||||||
|
using iterator = pointer;
|
||||||
|
using const_iterator = const_pointer;
|
||||||
|
|
||||||
|
using size_type = std::size_t;
|
||||||
|
|
||||||
|
dset () = default;
|
||||||
|
dset (std::initializer_list<ValueT> _init)
|
||||||
|
{
|
||||||
|
std::copy (_init.begin (), _init.end (), m_data.begin ());
|
||||||
|
m_size = _init.size ();
|
||||||
|
}
|
||||||
|
|
||||||
|
decltype(auto) begin (void) const& { return m_data.data (); }
|
||||||
|
decltype(auto) end (void) const& { return begin () + m_size; }
|
||||||
|
|
||||||
|
void clear (void);
|
||||||
|
|
||||||
|
/// A list of items to add to this set.
|
||||||
|
///
|
||||||
|
/// Items must be in sorted order.
|
||||||
|
void add (std::span<ValueT const>);
|
||||||
|
|
||||||
|
/// Add a number of copies of a specified item to the set.
|
||||||
|
void add (std::size_t count, ValueT const &val)
|
||||||
|
{
|
||||||
|
if (capacity () - size () < count)
|
||||||
|
throw std::bad_alloc ();
|
||||||
|
|
||||||
|
auto pos = std::lower_bound (m_data.begin (), m_data.begin () + m_size, val);
|
||||||
|
std::copy_backward (pos, m_data.begin () + m_size, m_data.begin () + m_size + count);
|
||||||
|
std::fill_n (pos, count, val);
|
||||||
|
m_size += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A list of items to remove from this store.
|
||||||
|
///
|
||||||
|
/// Items must be in sorted order, and must be a subset of this
|
||||||
|
/// container.
|
||||||
|
void erase (std::span<ValueT const>);
|
||||||
|
|
||||||
|
/// Tests if the list is a subset of this container.
|
||||||
|
///
|
||||||
|
/// The list must be sorted.
|
||||||
|
bool contains (std::span<ValueT const> rhs) const
|
||||||
|
{
|
||||||
|
return std::includes (begin (), end (), rhs.begin (), rhs.end ());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tests if this store contains at least the items in the
|
||||||
|
/// supplied store.
|
||||||
|
bool contains (dset const &rhs) const
|
||||||
|
{
|
||||||
|
return contains (rhs.m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t count (ValueT const &val) const
|
||||||
|
{
|
||||||
|
auto pos = std::find (begin (), end (), val);
|
||||||
|
|
||||||
|
std::size_t tally = 0;
|
||||||
|
for ( ; pos != end () && *pos == val; ++pos)
|
||||||
|
++tally;
|
||||||
|
|
||||||
|
return tally;
|
||||||
|
}
|
||||||
|
|
||||||
|
dset operator+ (std::span<ValueT const> rhs) const
|
||||||
|
{
|
||||||
|
if (remain () < rhs.size ())
|
||||||
|
throw std::bad_alloc ();
|
||||||
|
|
||||||
|
dset res;
|
||||||
|
auto const pos = std::merge (
|
||||||
|
begin (),
|
||||||
|
end (),
|
||||||
|
rhs.begin (),
|
||||||
|
rhs.end (),
|
||||||
|
res.m_data.begin ()
|
||||||
|
);
|
||||||
|
res.m_size = std::distance (res.m_data.begin (), pos);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
dset operator- (std::span<ValueT const> rhs) const
|
||||||
|
{
|
||||||
|
dset res;
|
||||||
|
auto const pos = std::set_difference (
|
||||||
|
begin (),
|
||||||
|
end (),
|
||||||
|
rhs.begin (),
|
||||||
|
rhs.end (),
|
||||||
|
res.m_data.begin ()
|
||||||
|
);
|
||||||
|
|
||||||
|
res.m_size = std::distance (res.m_data.begin (), pos);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
dset& operator+= (std::span<ValueT const>) &;
|
||||||
|
dset& operator-= (std::span<ValueT const>) &;
|
||||||
|
|
||||||
|
dset operator+ (dset const &rhs) const
|
||||||
|
{
|
||||||
|
return *this + std::span (rhs.m_data.data (), rhs.m_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
dset operator- (dset const &rhs) const
|
||||||
|
{
|
||||||
|
return *this - std::span (rhs.m_data.data (), rhs.m_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dset& operator+= (dset const &rhs) &
|
||||||
|
{
|
||||||
|
// TODO: Optimise me.
|
||||||
|
return *this = *this + std::span (rhs.m_data.data (), rhs.m_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
dset& operator-= (dset const &rhs) &
|
||||||
|
{
|
||||||
|
// TODO: Optimise me.
|
||||||
|
return *this = *this - rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dset
|
||||||
|
operator& (dset const &rhs) const
|
||||||
|
{
|
||||||
|
dset res;
|
||||||
|
|
||||||
|
auto const pos = std::set_intersection (
|
||||||
|
begin (),
|
||||||
|
end (),
|
||||||
|
rhs.begin (),
|
||||||
|
rhs.end (),
|
||||||
|
res.m_data.begin ()
|
||||||
|
);
|
||||||
|
|
||||||
|
res.m_size = std::distance (res.m_data.begin (), pos);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
dset& operator&= (dset const &rhs) &;
|
||||||
|
|
||||||
|
bool operator== (dset const &rhs) const
|
||||||
|
{
|
||||||
|
return std::equal (begin (), end (), rhs.begin (), rhs.end ());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!= (dset const &rhs) const
|
||||||
|
{
|
||||||
|
return !(*this == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty (void) const
|
||||||
|
{
|
||||||
|
return m_size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t size (void) const { return m_size; }
|
||||||
|
|
||||||
|
std::size_t
|
||||||
|
capacity (void) const
|
||||||
|
{
|
||||||
|
return MaxV;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t remain (void) const { return capacity () - size (); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::size_t m_size = 0;
|
||||||
|
std::array<value_type, MaxV> m_data;
|
||||||
|
};
|
||||||
|
}
|
30
test/set/dset.cpp
Normal file
30
test/set/dset.cpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include "set/dset.hpp"
|
||||||
|
#include "tap.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
using cruft::set::dset;
|
||||||
|
|
||||||
|
|
||||||
|
int main ()
|
||||||
|
{
|
||||||
|
|
||||||
|
cruft::TAP::logger tap;
|
||||||
|
|
||||||
|
{
|
||||||
|
dset<int, 5> const a { 1, 2, 3, 5, };
|
||||||
|
dset<int, 5> const b { 2, 4, 5, };
|
||||||
|
dset<int, 5> const c { 2, 5, };
|
||||||
|
|
||||||
|
tap.expect_eq (a & b, c, "set intersection");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
dset<int, 5> val { 3, 4, 5 };
|
||||||
|
val.add (2, 4);
|
||||||
|
dset<int, 5> const expected { 3, 4, 4, 4, 5 };
|
||||||
|
|
||||||
|
tap.expect_eq (val, expected, "set add_n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return tap.status ();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user