libcruft-util/array/darray.hpp

221 lines
6.0 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 2017 Danny Robson <danny@nerdcruft.net>
*/
#pragma once
#include "../debug/assert.hpp"
#include "../iterator/zip.hpp"
#include <iterator>
#include <cstddef>
namespace cruft {
/// An array-like object with capacity fixed at instantiation time, and a
/// size which is variable at runtime.
template <std::size_t CapacityV, typename ValueT>
class darray {
public:
using value_type = ValueT;
using size_type = std::size_t;
static constexpr auto elements = CapacityV;
using pointer = ValueT*;
using const_pointer = ValueT const*;
using iterator = pointer;
using const_iterator = const_pointer;
darray (): m_size (0) { ; }
darray (darray const&) = default;
darray (darray &&) = default;
darray& operator= (darray const&) = default;
darray& operator= (darray &&) = default;
~darray ()
{
for (auto &i: *this)
i.~ValueT ();
}
darray (std::initializer_list<ValueT> init):
m_size (init.size ())
{
CHECK_LE (init.size (), CapacityV);
for (auto &&[idx, src]: cruft::iterator::izip (init))
m_data.objects[idx] = std::move (src);
}
template <typename InputT>
darray (InputT first, InputT last):
darray ()
{
for ( ; first != last; ++first) {
CHECK_LT (m_size, CapacityV);
m_data.objects[m_size++] = *first;
}
}
ValueT& operator[] (size_type idx)& noexcept
{
CHECK_LT (idx, m_size);
return m_data.objects[idx];
}
ValueT const& operator[] (size_type idx) const& noexcept
{
CHECK_LT (idx, m_size);
return m_data.objects[idx];
}
iterator begin (void)& { return m_data.objects + 0; }
iterator end (void)& { return m_data.objects + m_size; }
const_iterator begin (void) const& { return m_data.objects + 0; }
const_iterator end (void) const& { return m_data.objects + m_size; }
decltype(auto) cbegin (void) const& { return begin (); }
decltype(auto) cend (void) const& { return end (); }
constexpr value_type* data (void)& noexcept
{
return m_data.objects + 0;
}
constexpr value_type const* data (void) const& noexcept
{
return m_data.objects + 0;
}
size_type size (void) const noexcept { return m_size; }
constexpr auto capacity (void) const noexcept { return CapacityV; }
constexpr auto remain (void) const noexcept { return capacity () - size (); }
constexpr void
resize (size_type const count, value_type const &value)
{
if (count < m_size) {
while (m_size > count) {
--m_size;
m_data.objects[m_size].~ValueT ();
}
return;
}
if (count > m_size) {
for ( ; m_size < count; ++m_size)
new (m_data.objects + m_size) ValueT (value);
return;
}
}
constexpr void resize (size_type count) { return resize (count, value_type {}); }
constexpr bool empty (void) const noexcept { return m_size == 0; }
constexpr bool full (void) const noexcept { return m_size == CapacityV; }
void erase (iterator pos)
{
CHECK_LIMIT (pos, begin (), end ());
for (auto cursor = pos + 1; cursor != end (); ++cursor)
*(cursor - 1) = std::move (*cursor);
--m_size;
}
/// Insert one copy of `value' before `pos'
iterator insert (iterator pos, ValueT const &val)
{
return insert (pos, 1u, val);
}
/// Insert `count' copies of `value' before `pos'.
iterator insert (const_iterator pos, size_type count, ValueT const &val)
{
// Ensure we have enough space
CHECK_LIMIT (pos, begin (), end ());
CHECK_LE (m_size, CapacityV - count);
std::move_backward (pos, cend (), end () + count);
m_size += count;
auto dst = const_cast<iterator> (pos);
std::fill_n (dst, count, val);
return dst;
}
iterator push_back (value_type const &val)&
{
CHECK_LT (m_size, CapacityV);
m_data.objects[m_size] = val;
return m_data.objects + m_size++;
}
iterator push_back (value_type &&val)&
{
CHECK_LT (m_size, CapacityV);
m_data.objects[m_size] = std::move (val);
return m_data.objects + m_size++;
}
private:
union alignas (ValueT) storage_t {
storage_t () { };
char store[sizeof (ValueT) * CapacityV];
ValueT objects[CapacityV];
} m_data;
size_type m_size;
};
//-------------------------------------------------------------------------
template <
std::size_t SizeA, typename ValueA,
std::size_t SizeB, typename ValueB
>
constexpr auto
operator== (
darray<SizeA,ValueA> const &a,
darray<SizeB,ValueB> const &b
) {
return std::equal (
a.begin (), a.end (),
b.begin (), b.end ()
);
}
//-------------------------------------------------------------------------
template <
std::size_t SizeA, typename ValueA,
std::size_t SizeB, typename ValueB
>
constexpr auto
operator!= (
darray<SizeA,ValueA> const &a,
darray<SizeB,ValueB> const &b
) {
return !(a == b);
}
}