libcruft-util/set/dset.hpp

207 lines
5.5 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 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;
};
}