186 lines
5.0 KiB
C++
186 lines
5.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 "../iterator.hpp"
|
|
|
|
#include <iterator>
|
|
|
|
#include <cstddef>
|
|
|
|
|
|
namespace cruft {
|
|
/// A runtime-sizable array with a capacity fixed at compile-time.
|
|
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::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[] (std::size_t idx)& noexcept
|
|
{
|
|
CHECK_LT (idx, m_size);
|
|
return m_data.objects[idx];
|
|
}
|
|
|
|
ValueT const& operator[] (std::size_t 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 (); }
|
|
|
|
std::size_t 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 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) {
|
|
char store[sizeof (ValueT) * CapacityV];
|
|
ValueT objects[CapacityV];
|
|
} m_data;
|
|
|
|
std::size_t 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);
|
|
}
|
|
}
|