2019-07-27 17:36:24 +03:00
|
|
|
//
|
|
|
|
|
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
|
|
|
|
|
// Copyright (c) YaPB Development Team.
|
|
|
|
|
//
|
|
|
|
|
// This software is licensed under the BSD-style license.
|
|
|
|
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
|
|
|
// https://yapb.ru/license
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <crlib/cr-basic.h>
|
|
|
|
|
#include <crlib/cr-alloc.h>
|
|
|
|
|
#include <crlib/cr-movable.h>
|
|
|
|
|
#include <crlib/cr-random.h>
|
|
|
|
|
|
2019-07-29 23:11:49 +03:00
|
|
|
#include <initializer_list>
|
|
|
|
|
|
2019-07-27 17:36:24 +03:00
|
|
|
// policy to reserve memory
|
|
|
|
|
CR_DECLARE_SCOPED_ENUM (ReservePolicy,
|
2019-07-29 23:13:47 +03:00
|
|
|
Multiple,
|
2019-07-29 23:11:49 +03:00
|
|
|
Single,
|
2019-08-01 23:02:44 +03:00
|
|
|
)
|
2019-07-27 17:36:24 +03:00
|
|
|
|
|
|
|
|
CR_NAMESPACE_BEGIN
|
|
|
|
|
|
|
|
|
|
// simple array class like std::vector
|
2019-07-29 23:13:47 +03:00
|
|
|
template <typename T, ReservePolicy R = ReservePolicy::Multiple, size_t S = 0> class Array : public DenyCopying {
|
2019-07-27 17:36:24 +03:00
|
|
|
public:
|
|
|
|
|
T *m_data = nullptr;
|
|
|
|
|
size_t m_capacity = 0;
|
|
|
|
|
size_t m_length = 0;
|
|
|
|
|
|
|
|
|
|
public:
|
2019-07-29 23:11:49 +03:00
|
|
|
explicit Array () {
|
|
|
|
|
if (fix (S > 0)) {
|
|
|
|
|
reserve (S);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-07-27 17:36:24 +03:00
|
|
|
|
|
|
|
|
Array (const size_t amount) {
|
|
|
|
|
reserve (amount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Array (Array &&rhs) noexcept {
|
|
|
|
|
m_data = rhs.m_data;
|
|
|
|
|
m_length = rhs.m_length;
|
|
|
|
|
m_capacity = rhs.m_capacity;
|
|
|
|
|
|
|
|
|
|
rhs.reset ();
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-29 23:11:49 +03:00
|
|
|
Array (std::initializer_list <T> list) {
|
|
|
|
|
for (const auto &elem : list) {
|
|
|
|
|
push (elem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-27 17:36:24 +03:00
|
|
|
~Array () {
|
|
|
|
|
destroy ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void destructElements () noexcept {
|
|
|
|
|
for (size_t i = 0; i < m_length; ++i) {
|
|
|
|
|
alloc.destruct (&m_data[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void transferElements (T *dest, T *src, size_t length) noexcept {
|
|
|
|
|
for (size_t i = 0; i < length; ++i) {
|
|
|
|
|
alloc.construct (&dest[i], cr::move (src[i]));
|
|
|
|
|
alloc.destruct (&src[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void destroy () {
|
|
|
|
|
destructElements ();
|
|
|
|
|
alloc.deallocate (m_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void reset () {
|
|
|
|
|
m_data = nullptr;
|
|
|
|
|
m_capacity = 0;
|
|
|
|
|
m_length = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
bool reserve (const size_t amount) {
|
|
|
|
|
if (m_length + amount < m_capacity) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2019-07-29 23:11:49 +03:00
|
|
|
auto capacity = m_capacity ? m_capacity : 12;
|
2019-07-27 17:36:24 +03:00
|
|
|
|
2019-07-29 23:13:47 +03:00
|
|
|
if (cr::fix (R == ReservePolicy::Multiple)) {
|
2019-07-27 17:36:24 +03:00
|
|
|
while (m_length + amount > capacity) {
|
|
|
|
|
capacity *= 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
capacity = amount + m_capacity + 1;
|
|
|
|
|
}
|
|
|
|
|
auto data = alloc.allocate <T> (capacity);
|
|
|
|
|
|
|
|
|
|
transferElements (data, m_data, m_length);
|
|
|
|
|
alloc.deallocate (m_data);
|
|
|
|
|
|
|
|
|
|
m_data = data;
|
|
|
|
|
m_capacity = capacity;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool resize (const size_t amount) {
|
|
|
|
|
if (amount < m_length) {
|
|
|
|
|
while (amount < m_length) {
|
|
|
|
|
discard ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (amount > m_length) {
|
|
|
|
|
if (!ensure (amount)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2019-07-29 23:11:49 +03:00
|
|
|
size_t resizeLength = amount - m_length;
|
2019-07-27 17:36:24 +03:00
|
|
|
|
2019-07-29 23:11:49 +03:00
|
|
|
while (resizeLength--) {
|
|
|
|
|
emplace ();
|
2019-07-27 17:36:24 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ensure (const size_t amount) {
|
|
|
|
|
if (amount <= m_length) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return reserve (amount - m_length);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t length () const {
|
|
|
|
|
return m_length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t capacity () const {
|
|
|
|
|
return m_capacity;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename U> bool set (size_t index, U &&object) {
|
|
|
|
|
if (index >= m_capacity) {
|
|
|
|
|
if (!reserve (index + 1)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
alloc.construct (&m_data[index], cr::forward <U> (object));
|
|
|
|
|
|
|
|
|
|
if (index >= m_length) {
|
|
|
|
|
m_length = index + 1;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename U> bool insert (size_t index, U &&object) {
|
|
|
|
|
return insert (index, &object, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename U> bool insert (size_t index, U *objects, size_t count = 1) {
|
|
|
|
|
if (!objects || !count) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
const size_t capacity = (m_length > index ? m_length : index) + count;
|
|
|
|
|
|
|
|
|
|
if (capacity >= m_capacity && !reserve (capacity)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (index >= m_length) {
|
|
|
|
|
for (size_t i = 0; i < count; ++i) {
|
|
|
|
|
alloc.construct (&m_data[i + index], cr::forward <U> (objects[i]));
|
|
|
|
|
}
|
|
|
|
|
m_length = capacity;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
size_t i = 0;
|
|
|
|
|
|
|
|
|
|
for (i = m_length; i > index; --i) {
|
|
|
|
|
m_data[i + count - 1] = cr::move (m_data[i - 1]);
|
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
|
|
|
alloc.construct (&m_data[i + index], cr::forward <U> (objects[i]));
|
|
|
|
|
}
|
|
|
|
|
m_length += count;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool insert (size_t at, const Array &rhs) {
|
|
|
|
|
if (&rhs == this) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return insert (at, &rhs.m_data[0], rhs.m_length);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool erase (const size_t index, const size_t count) {
|
|
|
|
|
if (index + count > m_capacity) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2019-08-04 18:22:01 +03:00
|
|
|
for (size_t i = index; i < index + count; ++i) {
|
2019-07-29 23:11:49 +03:00
|
|
|
alloc.destruct (&m_data[i]);
|
|
|
|
|
}
|
2019-07-27 17:36:24 +03:00
|
|
|
m_length -= count;
|
|
|
|
|
|
|
|
|
|
for (size_t i = index; i < m_length; ++i) {
|
|
|
|
|
m_data[i] = cr::move (m_data[i + count]);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool shift () {
|
|
|
|
|
return erase (0, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename U> bool unshift (U &&object) {
|
|
|
|
|
return insert (0, &object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool remove (const T &object) {
|
|
|
|
|
return erase (index (object), 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename U> bool push (U &&object) {
|
|
|
|
|
if (!reserve (1)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
alloc.construct (&m_data[m_length], cr::forward <U> (object));
|
2019-08-04 18:22:01 +03:00
|
|
|
++m_length;
|
2019-07-27 17:36:24 +03:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename ...Args> bool emplace (Args &&...args) {
|
|
|
|
|
if (!reserve (1)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
alloc.construct (&m_data[m_length], cr::forward <Args> (args)...);
|
2019-08-04 18:22:01 +03:00
|
|
|
++m_length;
|
2019-07-27 17:36:24 +03:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
T pop () {
|
|
|
|
|
auto object = cr::move (m_data[m_length - 1]);
|
|
|
|
|
discard ();
|
|
|
|
|
|
|
|
|
|
return object;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void discard () {
|
|
|
|
|
erase (m_length - 1, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t index (const T &object) const {
|
|
|
|
|
return &object - &m_data[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void shuffle () {
|
|
|
|
|
for (size_t i = m_length; i >= 1; --i) {
|
|
|
|
|
cr::swap (m_data[i - 1], m_data[rg.int_ (i, m_length - 2)]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void reverse () {
|
|
|
|
|
for (size_t i = 0; i < m_length / 2; ++i) {
|
|
|
|
|
cr::swap (m_data[i], m_data[m_length - 1 - i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename U> bool extend (U &&rhs) {
|
|
|
|
|
if (m_length == 0) {
|
|
|
|
|
*this = cr::move (rhs);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
for (size_t i = 0; i < rhs.length (); ++i) {
|
|
|
|
|
if (!push (cr::move (rhs[i]))) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename U> bool assign (U &&rhs) {
|
|
|
|
|
clear ();
|
|
|
|
|
return extend (cr::move (rhs));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void clear () {
|
|
|
|
|
destructElements ();
|
|
|
|
|
m_length = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool empty () const {
|
|
|
|
|
return m_length == 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool shrink () {
|
|
|
|
|
if (m_length == m_capacity || !m_length) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto data = alloc.allocate <T> (m_length);
|
|
|
|
|
transferElements (data, m_data, m_length);
|
|
|
|
|
|
|
|
|
|
alloc.deallocate (m_data);
|
|
|
|
|
|
|
|
|
|
m_data = data;
|
|
|
|
|
m_capacity = m_length;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const T &at (size_t index) const {
|
|
|
|
|
return m_data[index];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
T &at (size_t index) {
|
|
|
|
|
return m_data[index];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const T &first () const {
|
|
|
|
|
return m_data[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
T &first () {
|
|
|
|
|
return m_data[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
T &last () {
|
|
|
|
|
return m_data[m_length - 1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const T &last () const {
|
|
|
|
|
return m_data[m_length - 1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const T &random () const {
|
|
|
|
|
return m_data[rg.int_ <size_t> (0, m_length - 1)];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
T &random () {
|
|
|
|
|
return m_data[rg.int_ <size_t> (0u, m_length - 1u)];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
T *data () {
|
|
|
|
|
return m_data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
T *data () const {
|
|
|
|
|
return m_data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
Array &operator = (Array &&rhs) noexcept {
|
|
|
|
|
if (this != &rhs) {
|
|
|
|
|
destroy ();
|
|
|
|
|
|
|
|
|
|
m_data = rhs.m_data;
|
|
|
|
|
m_length = rhs.m_length;
|
|
|
|
|
m_capacity = rhs.m_capacity;
|
|
|
|
|
|
|
|
|
|
rhs.reset ();
|
|
|
|
|
}
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
const T &operator [] (size_t index) const {
|
|
|
|
|
return at (index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
T &operator [] (size_t index) {
|
|
|
|
|
return at (index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// for range-based loops
|
|
|
|
|
public:
|
|
|
|
|
T *begin () {
|
|
|
|
|
return m_data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
T *begin () const {
|
|
|
|
|
return m_data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
T *end () {
|
|
|
|
|
return m_data + m_length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
T *end () const {
|
|
|
|
|
return m_data + m_length;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2019-07-29 23:11:49 +03:00
|
|
|
// small array (with minimal reserve policy, something like fixed array, but still able to grow, by default allocates 64 elements)
|
|
|
|
|
template <typename T> using SmallArray = Array <T, ReservePolicy::Single, 64>;
|
|
|
|
|
|
2019-07-27 17:36:24 +03:00
|
|
|
CR_NAMESPACE_END
|
|
|
|
|
|