221 lines
6.0 KiB
C++
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);
|
|
}
|
|
}
|