Files
pip/libs/main/containers/pideque.h
2022-04-18 19:10:01 +03:00

1084 lines
42 KiB
C++
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! \addtogroup Containers
//! \{
//! \file pideque.h
//! \brief
//! \~english Declares \a PIDeque
//! \~russian Объявление \a PIDeque
//! \~\authors
//! \~english
//! Ivan Pelipenko peri4ko@yandex.ru;
//! Andrey Bychkov work.a.b@yandex.ru;
//! \~russian
//! Иван Пелипенко peri4ko@yandex.ru;
//! Андрей Бычков work.a.b@yandex.ru;
//! \~\}
/*
PIP - Platform Independent Primitives
Dynamic array of any type
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIDEQUE_H
#define PIDEQUE_H
#include "picontainers.h"
//! \addtogroup Containers
//! \{
//! \class PIDeque
//! \brief
//! \~english Sequence two-way linear container - dynamic size array of any type.
//! \~russian Последовательный двухсторонний контейнер с линейной памятью - динамический массив любого типа.
//! \~\}
//! \details
//! \~english
//! The elements are stored contiguously,
//! which means that elements can be accessed not only through iterators,
//! but also using offsets to regular pointers to elements.
//! This means that a pointer to an element of a PIDeque may be passed to any function
//! that expects a pointer to an element of an array.
//! To add elements you can use functions \a append() and \a insert(),
//! to remove elements you can use functions \a remove() and \a clear().
//! Change size by function \a resize().
//!
//! The storage of the PIDeque is handled automatically,
//! being expanded as needed.
//! PIDeque usually occupy more space than \a PIVector,
//! because more memory is allocated to handle future growth
//! from both the beginning and the end.
//! This way a PIDeque does not need to reallocate each time an element is inserted,
//! but only when the additional memory is exhausted.
//! The total amount of allocated memory can be queried using \a capacity() function.
//! Reallocations are usually costly operations in terms of performance.
//! The \a reserve() function can be used to eliminate reallocations
//! if the number of elements is known beforehand.
//!
//! The complexity (efficiency) of common operations on PIDeque is as follows:
//! - Random access - constant 𝓞(1)
//! - Insertion or removal of elements at the end or begin - amortized constant 𝓞(1)
//! - Insertion or removal of elements - linear in the distance to the end of the array 𝓞(n)
//!
//! \~russian
//! Элементы хранятся непрерывно, а значит доступны не только через итераторы,
//! но и с помощью смещений для обычных указателей на элементы.
//! Это означает, что указатель на элемент PIDeque может передаваться в любую функцию,
//! ожидающую указатель на элемент массива.
//! Добавить элементы можно с помощью функции \a append() или \a insert(),
//! а удалить с помощью \a remove() или \a clear().
//! Изменить размер можно функцией \a resize().
//!
//! Память PIDeque обрабатывается автоматически,
//! расширяясь по мере необходимости.
//! PIDeque занимает больше места, чем \a PIVector, поскольку
//! больше памяти выделяется для обработки будущего роста и с начала и с конца.
//! Таким образом, память для PIDeque требуется выделять
//! не при каждой вставке элемента, а только после исчерпания дополнительной памяти.
//! Общий объём выделенной памяти можно получить с помощью функции \a capacity().
//!
//! Выделение памяти обычно является дорогостоящей операцией
//! с точки зрения производительности.
//! Функцию \a reserve() можно использовать для исключения выделения памяти,
//! если количество элементов известно заранее.
//!
//! Сложность (эффективность) обычных операций над PIDeque следующая:
//! - Произвольный доступ — постоянная 𝓞(1)
//! - Вставка и удаление элементов в конце или начале — амортизированная постоянная 𝓞(1)
//! - Вставка и удаление элементов — линейная по расстоянию до конца массива 𝓞(n)
//!
//! \~\sa \a PIVector, \a PIMap
template <typename T>
class PIDeque {
public:
typedef bool (*CompareFunc)(const T & , const T & );
inline PIDeque(): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
}
inline PIDeque(const PIDeque<T> & other): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc_forward(other.pid_size);
newT(pid_data + pid_start, other.pid_data + other.pid_start, pid_size);
}
inline PIDeque(std::initializer_list<T> init_list): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc_forward(init_list.size());
newT(pid_data, init_list.begin(), init_list.size());
}
inline PIDeque(const T * data, size_t size): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc_forward(size);
newT(pid_data + pid_start, data, pid_size);
}
inline PIDeque(size_t pid_size, const T & f = T()): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(pid_size, f);
}
inline PIDeque(size_t piv_size, std::function<T(size_t i)> f): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(piv_size, f);
}
inline PIDeque(PIDeque<T> && other): pid_data(other.pid_data), pid_size(other.pid_size), pid_rsize(other.pid_rsize), pid_start(other.pid_start) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
other._reset();
}
inline virtual ~PIDeque() {
PIINTROSPECTION_CONTAINER_DELETE(T)
PIINTROSPECTION_CONTAINER_FREE(T, (pid_rsize))
deleteT(pid_data + pid_start, pid_size);
dealloc();
_reset();
}
inline PIDeque<T> & operator =(const PIDeque<T> & other) {
if (this == &other) return *this;
deleteT(pid_data + pid_start, pid_size);
alloc_forward(other.pid_size);
newT(pid_data + pid_start, other.pid_data + other.pid_start, pid_size);
return *this;
}
inline PIDeque<T> & operator =(PIDeque<T> && other) {
swap(other);
return *this;
}
typedef T value_type;
enum ReshapeOrder {
byRow,
byColumn
};
class iterator {
friend class PIDeque<T>;
private:
inline iterator(PIDeque<T> * v, ssize_t p): parent(v), pos(p) {}
PIDeque<T> * parent;
ssize_t pos;
public:
typedef T value_type;
typedef T* pointer;
typedef T& reference;
typedef std::ptrdiff_t difference_type;
typedef std::random_access_iterator_tag iterator_category;
inline iterator(): parent(0), pos(0) {}
inline T & operator *() {return (*parent)[pos];}
inline const T & operator *() const {return (*parent)[pos];}
inline T & operator ->() {return (*parent)[pos];}
inline const T & operator ->() const {return (*parent)[pos];}
inline iterator & operator ++() {++pos; return *this;}
inline iterator & operator ++(int) {const auto tmp = *this; ++*this; return tmp;}
inline iterator & operator --() {--pos; return *this;}
inline iterator & operator --(int) {const auto tmp = *this; --*this; return tmp;}
inline iterator & operator +=(const iterator & it) {pos += it.pos; return *this;}
inline iterator & operator +=(size_t p) {pos += p; return *this;}
inline iterator & operator -=(const iterator & it) {pos -= it.pos; return *this;}
inline iterator & operator -=(size_t p) {pos -= p; return *this;}
friend inline iterator operator -(const iterator & it, size_t p) {auto tmp = it; tmp -= p; return tmp;}
friend inline iterator operator -(size_t p, const iterator & it) {return it - p;}
friend inline std::ptrdiff_t operator -(const iterator & it1, const iterator & it2) {return it1.pos - it2.pos;}
friend inline iterator operator +(const iterator & it, size_t p) {auto tmp = it; tmp += p; return tmp;}
friend inline iterator operator +(size_t p, const iterator & it) {return it + p;}
inline bool operator ==(const iterator & it) const {return (pos == it.pos);}
inline bool operator !=(const iterator & it) const {return (pos != it.pos);}
friend inline bool operator <(const iterator & it1, const iterator & it2) {return it1.pos < it2.pos;}
friend inline bool operator <=(const iterator & it1, const iterator & it2) {return it1.pos <= it2.pos;}
friend inline bool operator >(const iterator & it1, const iterator & it2) {return it1.pos > it2.pos;}
friend inline bool operator >=(const iterator & it1, const iterator & it2) {return it1.pos >= it2.pos;}
};
class const_iterator {
friend class PIDeque<T>;
private:
inline const_iterator(const PIDeque<T> * v, ssize_t p): parent(v), pos(p) {}
const PIDeque<T> * parent;
ssize_t pos;
public:
typedef T value_type;
typedef T* pointer;
typedef T& reference;
typedef std::ptrdiff_t difference_type;
typedef std::random_access_iterator_tag iterator_category;
inline const_iterator(): parent(0), pos(0) {}
inline const T & operator *() const {return (*parent)[pos];}
inline const T & operator ->() const {return (*parent)[pos];}
inline const_iterator & operator ++() {++pos; return *this;}
inline const_iterator & operator ++(int) {const auto tmp = *this; ++*this; return tmp;}
inline const_iterator & operator --() {--pos; return *this;}
inline const_iterator & operator --(int) {const auto tmp = *this; --*this; return tmp;}
inline const_iterator & operator +=(const const_iterator & it) {pos += it.pos; return *this;}
inline const_iterator & operator +=(size_t p) {pos += p; return *this;}
inline const_iterator & operator -=(const const_iterator & it) {pos -= it.pos; return *this;}
inline const_iterator & operator -=(size_t p) {pos -= p; return *this;}
friend inline const_iterator operator -(const const_iterator & it, size_t p) {auto tmp = it; tmp -= p; return tmp;}
friend inline const_iterator operator -(size_t p, const const_iterator & it) {return it - p;}
friend inline std::ptrdiff_t operator -(const const_iterator & it1, const const_iterator & it2) {return it1.pos - it2.pos;}
friend inline const_iterator operator +(const const_iterator & it, size_t p) {auto tmp = it; tmp += p; return tmp;}
friend inline const_iterator operator +(size_t p, const const_iterator & it) {return it + p;}
inline bool operator ==(const const_iterator & it) const {return (pos == it.pos);}
inline bool operator !=(const const_iterator & it) const {return (pos != it.pos);}
friend inline bool operator <(const const_iterator & it1, const const_iterator & it2) {return it1.pos < it2.pos;}
friend inline bool operator <=(const const_iterator & it1, const const_iterator & it2) {return it1.pos <= it2.pos;}
friend inline bool operator >(const const_iterator & it1, const const_iterator & it2) {return it1.pos > it2.pos;}
friend inline bool operator >=(const const_iterator & it1, const const_iterator & it2) {return it1.pos >= it2.pos;}
};
class reverse_iterator {
friend class PIDeque<T>;
private:
inline reverse_iterator(PIDeque<T> * v, ssize_t p): parent(v), pos(p) {}
PIDeque<T> * parent;
ssize_t pos;
public:
typedef T value_type;
typedef T* pointer;
typedef T& reference;
typedef std::ptrdiff_t difference_type;
typedef std::random_access_iterator_tag iterator_category;
inline reverse_iterator(): parent(0), pos(0) {}
inline T & operator *() {return (*parent)[pos];}
inline const T & operator *() const {return (*parent)[pos];}
inline T & operator ->() {return (*parent)[pos];}
inline const T & operator ->() const {return (*parent)[pos];}
inline reverse_iterator & operator ++() {--pos; return *this;}
inline reverse_iterator & operator ++(int) {const auto tmp = *this; --*this; return tmp;}
inline reverse_iterator & operator --() {++pos; return *this;}
inline reverse_iterator & operator --(int) {const auto tmp = *this; ++*this; return tmp;}
inline reverse_iterator & operator +=(const reverse_iterator & it) {pos -= it.pos; return *this;}
inline reverse_iterator & operator +=(size_t p) {pos -= p; return *this;}
inline reverse_iterator & operator -=(const reverse_iterator & it) {pos += it.pos; return *this;}
inline reverse_iterator & operator -=(size_t p) {pos += p; return *this;}
friend inline reverse_iterator operator -(const reverse_iterator & it, size_t p) {auto tmp = it; tmp -= p; return tmp;}
friend inline reverse_iterator operator -(size_t p, const reverse_iterator & it) {return it - p;}
friend inline std::ptrdiff_t operator -(const reverse_iterator & it1, const reverse_iterator & it2) {return it2.pos - it1.pos;}
friend inline reverse_iterator operator +(const reverse_iterator & it, size_t p) {auto tmp = it; tmp += p; return tmp;}
friend inline reverse_iterator operator +(size_t p, const reverse_iterator & it) {return it + p;}
inline bool operator ==(const reverse_iterator & it) const {return (pos == it.pos);}
inline bool operator !=(const reverse_iterator & it) const {return (pos != it.pos);}
friend inline bool operator <(const reverse_iterator & it1, const reverse_iterator & it2) {return it1.pos < it2.pos;}
friend inline bool operator <=(const reverse_iterator & it1, const reverse_iterator & it2) {return it1.pos <= it2.pos;}
friend inline bool operator >(const reverse_iterator & it1, const reverse_iterator & it2) {return it1.pos > it2.pos;}
friend inline bool operator >=(const reverse_iterator & it1, const reverse_iterator & it2) {return it1.pos >= it2.pos;}
};
class const_reverse_iterator {
friend class PIDeque<T>;
private:
inline const_reverse_iterator(const PIDeque<T> * v, ssize_t p): parent(v), pos(p) {}
const PIDeque<T> * parent;
ssize_t pos;
public:
typedef T value_type;
typedef T* pointer;
typedef T& reference;
typedef std::ptrdiff_t difference_type;
typedef std::random_access_iterator_tag iterator_category;
inline const_reverse_iterator(): parent(0), pos(0) {}
inline const T & operator *() const {return (*parent)[pos];}
inline const T & operator ->() const {return (*parent)[pos];}
inline const_reverse_iterator & operator ++() {--pos; return *this;}
inline const_reverse_iterator & operator ++(int) {const auto tmp = *this; --*this; return tmp;}
inline const_reverse_iterator & operator --() {++pos; return *this;}
inline const_reverse_iterator & operator --(int) {const auto tmp = *this; ++*this; return tmp;}
inline const_reverse_iterator & operator +=(const const_reverse_iterator & it) {pos -= it.pos; return *this;}
inline const_reverse_iterator & operator +=(size_t p) {pos -= p; return *this;}
inline const_reverse_iterator & operator -=(const const_reverse_iterator & it) {pos += it.pos; return *this;}
inline const_reverse_iterator & operator -=(size_t p) {pos += p; return *this;}
friend inline const_reverse_iterator operator -(const const_reverse_iterator & it, size_t p) {auto tmp = it; tmp -= p; return tmp;}
friend inline const_reverse_iterator operator -(size_t p, const const_reverse_iterator & it) {return it - p;}
friend inline std::ptrdiff_t operator -(const const_reverse_iterator & it1, const const_reverse_iterator & it2) {return it2.pos - it1.pos;}
friend inline const_reverse_iterator operator +(const const_reverse_iterator & it, size_t p) {auto tmp = it; tmp += p; return tmp;}
friend inline const_reverse_iterator operator +(size_t p, const const_reverse_iterator & it) {return it + p;}
inline bool operator ==(const const_reverse_iterator & it) const {return (pos == it.pos);}
inline bool operator !=(const const_reverse_iterator & it) const {return (pos != it.pos);}
friend inline bool operator <(const const_reverse_iterator & it1, const const_reverse_iterator & it2) {return it1.pos < it2.pos;}
friend inline bool operator <=(const const_reverse_iterator & it1, const const_reverse_iterator & it2) {return it1.pos <= it2.pos;}
friend inline bool operator >(const const_reverse_iterator & it1, const const_reverse_iterator & it2) {return it1.pos > it2.pos;}
friend inline bool operator >=(const const_reverse_iterator & it1, const const_reverse_iterator & it2) {return it1.pos >= it2.pos;}
};
inline iterator begin() {return iterator(this, 0);}
inline iterator end() {return iterator(this, pid_size);}
inline const_iterator begin() const {return const_iterator(this, 0);}
inline const_iterator end() const {return const_iterator(this, pid_size);}
inline reverse_iterator rbegin() {return reverse_iterator(this, pid_size - 1);}
inline reverse_iterator rend() {return reverse_iterator(this, -1);}
inline const_reverse_iterator rbegin() const {return const_reverse_iterator(this, pid_size - 1);}
inline const_reverse_iterator rend() const {return const_reverse_iterator(this, -1);}
inline size_t size() const {return pid_size;}
inline ssize_t size_s() const {return pid_size;}
inline size_t length() const {return pid_size;}
inline size_t capacity() const {return pid_rsize;}
inline size_t _start() const {return pid_start;}
inline bool isEmpty() const {return (pid_size == 0);}
inline bool isNotEmpty() const {return (pid_size > 0);}
inline bool any(std::function<bool(const T & e)> test) const {
for (ssize_t i = pid_start; i < pid_start + (ssize_t)pid_size; ++i) {
if (test(pid_data[i])) return true;
}
return false;
}
inline bool every(std::function<bool(const T & e)> test) const {
for (ssize_t i = pid_start; i < pid_start + (ssize_t)pid_size; ++i) {
if (!test(pid_data[i])) return false;
}
return true;
}
inline T & operator [](size_t index) {return pid_data[pid_start + index];}
inline const T & operator [](size_t index) const {return pid_data[pid_start + index];}
inline const T & at(size_t index) const {return pid_data[pid_start + index];}
inline T & back() {return pid_data[pid_start + pid_size - 1];}
inline const T & back() const {return pid_data[pid_start + pid_size - 1];}
inline T & front() {return pid_data[pid_start];}
inline const T & front() const {return pid_data[pid_start];}
inline bool operator ==(const PIDeque<T> & v) const {
if (pid_size != v.pid_size) return false;
for (size_t i = 0; i < pid_size; ++i) {
if (v[i] != (*this)[i]) {
return false;
}
}
return true;
}
inline bool operator !=(const PIDeque<T> & v) const {return !(*this == v);}
inline bool operator <(const PIDeque<T> & v) const {
if (pid_size != v.pid_size) return pid_size < v.pid_size;
for (size_t i = 0; i < pid_size; ++i) {
if ((*this)[i] != v[i]) return (*this)[i] < v[i];
}
return false;
}
inline bool operator >(const PIDeque<T> & v) const {
if (pid_size != v.pid_size) return pid_size > v.pid_size;
for (size_t i = 0; i < pid_size; ++i) {
if ((*this)[i] != v[i]) return (*this)[i] > v[i];
}
return false;
}
inline bool contains(const T & e) const {
for (ssize_t i = pid_start; i < pid_start + (ssize_t)pid_size; ++i) {
if (e == pid_data[i]) {
return true;
}
}
return false;
}
inline int etries(const T & e, size_t start = 0) const {
int ec = 0;
if (start >= pid_size) return ec;
for (ssize_t i = pid_start + start; i < pid_start + (ssize_t)pid_size; ++i) {
if (e == pid_data[i]) ++ec;
}
return ec;
}
inline int etries(std::function<bool(const T & e)> test, size_t start = 0) const {
int ec = 0;
if (start >= pid_size) return ec;
for (ssize_t i = pid_start + start; i < pid_start + (ssize_t)pid_size; ++i) {
if (test(pid_data[i])) ++ec;
}
return ec;
}
inline ssize_t indexOf(const T & e, size_t start = 0) const {
if (start >= pid_size) return -1;
for (ssize_t i = pid_start + start; i < pid_start + (ssize_t)pid_size; ++i) {
if (e == pid_data[i]) {
return i - pid_start;
}
}
return -1;
}
inline ssize_t indexWhere(std::function<bool(const T & e)> test, size_t start = 0) const {
if (start >= pid_size) return -1;
for (ssize_t i = pid_start + start; i < pid_start + (ssize_t)pid_size; ++i) {
if (test(pid_data[i])) {
return i - pid_start;
}
}
return -1;
}
inline ssize_t lastIndexOf(const T & e, ssize_t start = -1) const {
if (start < 0) start = pid_size - 1;
else start = piMin<ssize_t>(pid_size - 1, start);
for (ssize_t i = pid_start + start; i >= pid_start; --i) {
if (e == pid_data[i]) {
return i - pid_start;
}
}
return -1;
}
inline ssize_t lastIndexWhere(std::function<bool(const T & e)> test, ssize_t start = -1) const {
if (start < 0) start = pid_size - 1;
else start = piMin<ssize_t>(pid_size - 1, start);
for (ssize_t i = pid_start + start; i >= pid_start; --i) {
if (test(pid_data[i])) {
return i - pid_start;
}
}
return -1;
}
inline T * data(size_t index = 0) {return &(pid_data[pid_start + index]);}
inline const T * data(size_t index = 0) const {return &(pid_data[pid_start + index]);}
PIDeque<T> getRange(size_t index, size_t count) const {
if (index >= pid_size || count == 0) return PIDeque<T>();
if (index + count > pid_size) count = pid_size - index;
return PIDeque(&(pid_data[pid_start + index]), count);
}
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIDeque<T> & clear() {
resize(0);
return *this;
}
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIDeque<T> & clear() {
PIINTROSPECTION_CONTAINER_UNUSED(T, pid_size)
pid_size = 0;
pid_start = (pid_rsize - pid_size) / 2;
return *this;
}
inline PIDeque<T> & fill(const T & f = T()) {
deleteT(pid_data + pid_start, pid_size);
PIINTROSPECTION_CONTAINER_USED(T, pid_size)
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
elementNew(pid_data + i, f);
}
return *this;
}
inline PIDeque<T> & fill(std::function<T(size_t i)> f) {
deleteT(pid_data + pid_start, pid_size);
PIINTROSPECTION_CONTAINER_USED(T, pid_size)
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
elementNew(pid_data + i, f(i));
}
return *this;
}
inline PIDeque<T> & assign(const T & f = T()) {return fill(f);}
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIDeque<T> & assign(size_t new_size, const T & f) {
resize(new_size);
return fill(f);
}
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIDeque<T> & assign(size_t new_size, const T & f) {
_resizeRaw(new_size);
return fill(f);
}
inline PIDeque<T> & resize(size_t new_size, const T & f = T()) {
if (new_size < pid_size) {
deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size);
pid_size = new_size;
if (new_size == 0) {
pid_start = (pid_rsize - pid_size) / 2;
}
}
if (new_size > pid_size) {
size_t os = pid_size;
alloc_forward(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os))
for (size_t i = os + pid_start; i < new_size + pid_start; ++i) {
elementNew(pid_data + i, f);
}
}
return *this;
}
inline PIDeque<T> & resize(size_t new_size, std::function<T(size_t i)> f) {
if (new_size < pid_size) {
deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size);
pid_size = new_size;
if (new_size == 0) {
pid_start = (pid_rsize - pid_size) / 2;
}
}
if (new_size > pid_size) {
size_t os = pid_size;
alloc_forward(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os))
for (size_t i = os + pid_start; i < new_size + pid_start; ++i) {
elementNew(pid_data + i, f(i));
}
}
return *this;
}
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIDeque<T> & _resizeRaw(size_t new_size) {
if (new_size > pid_size) {
PIINTROSPECTION_CONTAINER_USED(T, (new_size-pid_size));
}
if (new_size < pid_size) {
PIINTROSPECTION_CONTAINER_UNUSED(T, (pid_size-new_size));
}
alloc_forward(new_size);
return *this;
}
inline PIDeque<T> & reserve(size_t new_size) {
if (new_size <= pid_rsize) return *this;
size_t os = pid_size;
alloc_forward(new_size);
pid_size = os;
return *this;
}
inline PIDeque<T> & insert(size_t index, const T & e = T()) {
if (index == pid_size) return push_back(e);
PIINTROSPECTION_CONTAINER_USED(T, 1)
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) {
alloc_forward(pid_size + 1);
if (index < pid_size - 1) {
size_t os = pid_size - index - 1;
memmove((void*)(&(pid_data[index + pid_start + 1])), (const void*)(&(pid_data[index + pid_start])), os * sizeof(T));
}
} else {
alloc_backward(pid_size + 1, -1);
if (index > 0) {
memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + 1])), index * sizeof(T));
}
}
elementNew(pid_data + pid_start + index, e);
return *this;
}
inline PIDeque<T> & insert(size_t index, T && e) {
if (index == pid_size) return push_back(e);
PIINTROSPECTION_CONTAINER_USED(T, 1)
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) {
alloc_forward(pid_size + 1);
if (index < pid_size - 1) {
size_t os = pid_size - index - 1;
memmove((void*)(&(pid_data[index + pid_start + 1])), (const void*)(&(pid_data[index + pid_start])), os * sizeof(T));
}
} else {
alloc_backward(pid_size + 1, -1);
if (index > 0) {
memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + 1])), index * sizeof(T));
}
}
elementNew(pid_data + pid_start + index, std::move(e));
return *this;
}
inline PIDeque<T> & insert(size_t index, const PIDeque<T> & other) {
if (other.isEmpty()) return *this;
#ifndef NDEBUG
if (&other == this) {
printf("error with PIDeque<%s>::insert\n", __PIP_TYPENAME__(T));
}
#endif
assert(&other != this);
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) {
ssize_t os = pid_size - index;
alloc_forward(pid_size + other.pid_size);
if (os > 0) {
memmove((void*)(&(pid_data[index + pid_start + other.pid_size])), (const void*)(&(pid_data[index + pid_start])), os * sizeof(T));
}
} else {
alloc_backward(pid_size + other.pid_size, -other.pid_size);
if (index > 0) {
memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + other.pid_size])), index * sizeof(T));
}
}
newT(pid_data + pid_start + index, other.pid_data + other.pid_start, other.pid_size);
return *this;
}
inline PIDeque<T> & remove(size_t index, size_t count = 1) {
if (count == 0) return *this;
if (index + count >= pid_size) {
resize(index);
return *this;
}
size_t os = pid_size - index - count;
deleteT(&(pid_data[index + pid_start]), count);
if (os <= index) {
if (os > 0) {
memmove((void*)(&(pid_data[index + pid_start])), (const void*)(&(pid_data[index + pid_start + count])), os * sizeof(T));
}
} else {
if (index > 0) {
memmove((void*)(&(pid_data[pid_start + count])), (const void*)(&(pid_data[pid_start])), index * sizeof(T));
}
pid_start += count;
}
pid_size -= count;
return *this;
}
inline void swap(PIDeque<T> & other) {
piSwap<T*>(pid_data, other.pid_data);
piSwap<size_t>(pid_size, other.pid_size);
piSwap<size_t>(pid_rsize, other.pid_rsize);
piSwap<ssize_t>(pid_start, other.pid_start);
}
//! \~\brief
//! \~english Sorts the elements in non-descending order.
//! \~russian Сортировка элементов в порядке возрастания.
//! \~\details
//! \~english The order of equal elements is not guaranteed to be preserved.
//! Elements are compared using operator<.
//! Sorting provided by [std::sort](https://en.cppreference.com/w/cpp/algorithm/sort).
//! Complexity `O(N·log(N))`.
//! \~russian Сохранность порядка элементов, имеющих одинаковое значение, не гарантируется.
//! Для сравнения элементов используется оператор `operator<`.
//! Для сортировки используется функция [std::sort](https://ru.cppreference.com/w/cpp/algorithm/sort).
//! Сложность сортировки `O(N·log(N))`.
//! \~\code
//! PIDeque<int> v{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
//! v.sort();
//! piCout << v; // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
//! \endcode
//! \~\sa \a sort(std::function<bool(const T &a, const T &b)> comp)
inline PIDeque<T> & sort() {
std::sort(begin(), end());
return *this;
}
//! \~\brief
//! \~english Sorts the elements in non-descending order.
//! \~russian Сортировка элементов в порядке возрастания.
//! \~\details
//! \~english The order of equal elements is not guaranteed to be preserved.
//! Elements are compared using the given binary comparison function `comp`.
//! which returns `true` if the first argument is less than (i.e. is ordered before) the second.
//! The signature of the comparison function should be equivalent to the following:
//! \code
//! bool comp(const T &a, const T &b);
//! \endcode
//! While the signature does not need to have const &, the function must not modify the objects passed to it.
//! The function must return `false` for identical elements,
//! otherwise, it will lead to undefined program behavior and memory errors.
//! Sorting provided by [std::sort](https://en.cppreference.com/w/cpp/algorithm/sort).
//! Complexity `O(N·log(N))`.
//! \~russian Сохранность порядка элементов, имеющих одинаковое значение, не гарантируется.
//! Для сравнения элементов используется функция сравнения `comp`.
//! Функция сравнения, возвращает `true` если первый аргумент меньше второго.
//! Сигнатура функции сравнения должна быть эквивалентна следующей:
//! \code
//! bool comp(const T &a, const T &b);
//! \endcode
//! Сигнатура не обязана содержать const &, однако, функция не может изменять переданные объекты.
//! Функция обязана возвращать `false` для одинаковых элементов,
//! иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
//! Для сортировки используется функция [std::sort](https://ru.cppreference.com/w/cpp/algorithm/sort).
//! Сложность сортировки `O(N·log(N))`.
//! \~\code
//! PIDeque<int> v{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
//! v.sort([](const int & a, const int & b){return a > b;});
//! piCout << v; // 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
//! \endcode
//! \~\sa \a sort()
inline PIDeque<T> & sort(std::function<bool(const T &a, const T &b)> comp) {
std::sort(begin(), end(), comp);
return *this;
}
inline PIDeque<T> & enlarge(llong pid_size) {
llong ns = size_s() + pid_size;
if (ns <= 0) clear();
else resize(size_t(ns));
return *this;
}
inline PIDeque<T> & removeOne(const T & e) {
for (size_t i = 0; i < pid_size; ++i) {
if (pid_data[i + pid_start] == e) {
remove(i);
return *this;
}
}
return *this;
}
inline PIDeque<T> & removeAll(const T & e) {
for (ssize_t i = 0; i < ssize_t(pid_size); ++i) {
if (pid_data[i + pid_start] == e) {
remove(i);
--i;
}
}
return *this;
}
inline PIDeque<T> & removeWhere(std::function<bool(const T & e)> test) {
for (ssize_t i = 0; i < ssize_t(pid_size); ++i) {
if (test(pid_data[i + pid_start])) {
remove(i);
--i;
}
}
return *this;
}
inline PIDeque<T> & push_back(const T & e) {
alloc_forward(pid_size + 1);
PIINTROSPECTION_CONTAINER_USED(T, 1);
elementNew(pid_data + pid_start + pid_size - 1, e);
return *this;
}
inline PIDeque<T> & push_back(T && e) {
alloc_forward(pid_size + 1);
PIINTROSPECTION_CONTAINER_USED(T, 1);
elementNew(pid_data + pid_start + pid_size - 1, std::move(e));
return *this;
}
inline PIDeque<T> & append(const T & e) {return push_back(e);}
inline PIDeque<T> & append(T && e) {return push_back(std::move(e));}
inline PIDeque<T> & append(const PIDeque<T> & v) {
#ifndef NDEBUG
if (&v == this) {
printf("error with PIDeque<%s>::append\n", __PIP_TYPENAME__(T));
}
#endif
assert(&v != this);
size_t ps = pid_size;
alloc_forward(pid_size + v.pid_size);
newT(pid_data + ps + pid_start, v.pid_data + v.pid_start, v.pid_size);
return *this;
}
inline PIDeque<T> & operator <<(const T & e) {return push_back(e);}
inline PIDeque<T> & operator <<(T && e) {return push_back(std::move(e));}
inline PIDeque<T> & operator <<(const PIDeque<T> & v) {return append(v);}
inline PIDeque<T> & push_front(const T & e) {insert(0, e); return *this;}
inline PIDeque<T> & push_front(T && e) {insert(0, std::move(e)); return *this;}
inline PIDeque<T> & prepend(const T & e) {return push_front(e);}
inline PIDeque<T> & prepend(T && e) {return push_front(std::move(e));}
inline PIDeque<T> & pop_back() {if (pid_size == 0) return *this; resize(pid_size - 1); return *this;}
inline PIDeque<T> & pop_front() {if (pid_size == 0) return *this; remove(0); return *this;}
inline T take_back() {T e(back()); pop_back(); return e;}
inline T take_front() {T e(front()); pop_front(); return e;}
template <typename ST>
PIDeque<ST> toType() const {
PIDeque<ST> ret(pid_size);
for (size_t i = 0; i < pid_size; ++i) {
ret[i] = ST(pid_data[i + pid_start]);
}
return ret;
}
const PIDeque<T> & forEach(std::function<void(const T & e)> f) const {
for (size_t i = 0; i < pid_size; ++i) {
f(pid_data[i + pid_start]);
}
return *this;
}
PIDeque<T> copyForEach(std::function<T(const T & e)> f) const {
PIDeque<T> ret; ret.reserve(pid_size);
for (size_t i = 0; i < pid_size; ++i) {
ret << f(pid_data[i + pid_start]);
}
return ret;
}
PIDeque<T> & forEachInplace(std::function<T(const T & e)> f) {
for (size_t i = 0; i < pid_size; ++i)
pid_data[i + pid_start] = f(pid_data[i + pid_start]);
return *this;
}
template <typename ST>
PIDeque<ST> map(std::function<ST(const T & e)> f) const {
PIDeque<ST> ret; ret.reserve(pid_size);
for (size_t i = 0; i < pid_size; ++i) {
ret << f(pid_data[i + pid_start]);
}
return ret;
}
template <typename ST>
PIDeque<ST> toType(std::function<ST(const T & e)> f) const {return map(f);}
template <typename ST>
ST reduce(std::function<ST(const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial);
for (size_t i = 0; i < pid_size; ++i) {
ret = f(pid_data[i + pid_start], ret);
}
return ret;
}
inline PIDeque<PIDeque<T>> reshape(size_t rows, size_t cols, int order = byRow) const {
PIDeque<PIDeque<T>> ret;
if (isEmpty()) return ret;
#ifndef NDEBUG
if (rows*cols != pid_size) {
printf("error with PIDeque<%s>::reshape\n", __PIP_TYPENAME__(T));
}
#endif
assert(rows*cols == pid_size);
ret.resize(rows);
if (order == byRow) {
for (size_t r = 0; r < rows; r++) {
ret[r] = PIDeque<T>(&(pid_data[r*cols]), cols);
}
}
if (order == byColumn) {
for (size_t r = 0; r < rows; r++) {
ret[r].resize(cols);
for (size_t c = 0; c < cols; c++) {
ret[r][c] = pid_data[c*rows + r];
}
}
}
return ret;
}
template<typename C, typename std::enable_if<
std::is_same<T, PIDeque<C>>::value
, int>::type = 0>
inline PIDeque<C> reshape(int order = byRow) const {
PIDeque<C> ret;
if (isEmpty()) return ret;
size_t rows = size();
size_t cols = at(0).size();
ret.reserve(rows * cols);
if (order == byRow) {
for (size_t r = 0; r < rows; r++) {
ret.append(at(r));
}
}
if (order == byColumn) {
for (size_t c = 0; c < cols; c++) {
for (size_t r = 0; r < rows; r++) {
ret << at(r)[c];
}
}
}
ret.resize(rows * cols);
return ret;
}
private:
inline void _reset() {pid_size = pid_rsize = pid_start = 0; pid_data = 0;}
inline size_t asize(ssize_t s) {
if (s <= 0) return 0;
if (pid_rsize + pid_rsize >= size_t(s) && pid_rsize < size_t(s)) {
return pid_rsize + pid_rsize;
}
ssize_t t = 0, s_ = s - 1;
while (s_ >> t) {
++t;
}
return (1 << t);
}
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void newT(T * dst, const T * src, size_t s) {
PIINTROSPECTION_CONTAINER_USED(T, s)
for (size_t i = 0; i < s; ++i)
elementNew(dst + i, src[i]);
}
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void newT(T * dst, const T * src, size_t s) {
PIINTROSPECTION_CONTAINER_USED(T, s)
memcpy((void*)(dst), (const void*)(src), s * sizeof(T));
}
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
if ((uchar*)d != 0) {
for (size_t i = 0; i < sz; ++i) {
elementDelete(d[i]);
}
}
}
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
}
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementNew(T * to, const T & from) {new(to)T(from);}
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementNew(T * to, T && from) {new(to)T(std::move(from));}
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementNew(T1 * to, const T & from) {(*to) = from;}
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementNew(T * to, T && from) {(*to) = std::move(from);}
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementDelete(T & from) {from.~T();}
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementDelete(T & from) {}
inline void dealloc() {
if ((uchar*)pid_data != 0) free((uchar*)pid_data);
pid_data = 0;
}
inline void checkMove() {
if (pid_size >= 4) {
if (pid_size < pid_rsize / 6) {
if (pid_start < ssize_t(pid_size + pid_size) || pid_start > (ssize_t(pid_rsize) - ssize_t(pid_size) - ssize_t(pid_size))) {
ssize_t ns = (pid_rsize - pid_size) / 2;
if (pid_start != ns) {
memmove((void*)(pid_data + ns), (const void*)(pid_data + pid_start), pid_size * sizeof(T));
pid_start = ns;
}
}
}
} else {
ssize_t ns = (pid_rsize - pid_size) / 2;
if (pid_start != ns) {
memmove((void*)(pid_data + ns), (const void*)(pid_data + pid_start), pid_size * sizeof(T));
pid_start = ns;
}
}
}
inline void alloc_forward(size_t new_size) { // direction == true -> alloc forward
if (pid_start + new_size <= pid_rsize) {
pid_size = new_size;
checkMove();
return;
}
pid_size = new_size;
size_t as = asize(pid_start + new_size);
if (as != pid_rsize) {
PIINTROSPECTION_CONTAINER_ALLOC(T, (as-pid_rsize))
T * p_d = (T*)(realloc((void*)(pid_data), as*sizeof(T)));
#ifndef NDEBUG
if (!p_d) {
printf("error with PIDeque<%s>::alloc\n", __PIP_TYPENAME__(T));
}
#endif
assert(p_d);
pid_data = p_d;
pid_rsize = as;
}
}
inline void alloc_backward(size_t new_size, ssize_t start_offset = 0) { //alloc backward
size_t as;
if (pid_start + start_offset < 0) {
as = asize(pid_rsize - start_offset);
} else {
as = pid_rsize;
}
if (as > pid_rsize) {
T * td = (T*)(malloc(as * sizeof(T)));
ssize_t ns = pid_start + as - pid_rsize;
PIINTROSPECTION_CONTAINER_ALLOC(T, (as-pid_rsize))
if (pid_rsize > 0 && pid_data != 0) {
memcpy((void*)(td + ns), (const void*)(pid_data + pid_start), pid_size * sizeof(T));
dealloc();
}
pid_data = td;
pid_rsize = as;
pid_start = ns;
}
pid_start += start_offset;
pid_size = new_size;
checkMove();
}
T * pid_data;
size_t pid_size, pid_rsize;
ssize_t pid_start;
};
#ifdef PIP_STD_IOSTREAM
template<typename T>
inline std::ostream & operator <<(std::ostream & s, const PIDeque<T> & v) {
s << "{";
for (size_t i = 0; i < v.size(); ++i) {
s << v[i];
if (i < v.size() - 1) s << ", ";
}
s << "}";
return s;
}
#endif
template<typename T>
inline PICout operator <<(PICout s, const PIDeque<T> & v) {
s.space();
s.setControl(0, true);
s << "{";
for (size_t i = 0; i < v.size(); ++i) {
s << v[i];
if (i < v.size() - 1) s << ", ";
}
s << "}";
s.restoreControl();
return s;
}
template<typename T> inline void piSwap(PIDeque<T> & f, PIDeque<T> & s) {f.swap(s);}
#endif // PIDEQUE_H