829 lines
27 KiB
C++
829 lines
27 KiB
C++
/*! \addtogroup Containers
|
||
* \{
|
||
* \file pivector.h
|
||
* \brief
|
||
* \~english Declares \a PIVector
|
||
* \~russian Объявление \a PIVector
|
||
* \~\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
|
||
Sequence linear container aka dynamic size 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 PIVECTOR_H
|
||
#define PIVECTOR_H
|
||
|
||
#include "picontainers.h"
|
||
|
||
/*! \addtogroup Containers
|
||
* \{
|
||
* \class PIVector pivector.h
|
||
* \brief
|
||
* \~english Sequence 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 vector may be passed to any function
|
||
* that expects a pointer to an element of an array.
|
||
*
|
||
* The storage of the vector is handled automatically,
|
||
* being expanded and contracted as needed.
|
||
* Vectors usually occupy more space than static arrays,
|
||
* because more memory is allocated to handle future growth.
|
||
* This way a vector 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 vectors is as follows:
|
||
* - Random access - constant 𝓞(1)
|
||
* - Insertion or removal of elements at the end - amortized constant 𝓞(1)
|
||
* - Insertion or removal of elements - linear in the distance to the end of the vector 𝓞(n)
|
||
*
|
||
* \~russian
|
||
* Элементы хранятся непрерывно, а значит доступны не только через итераторы,
|
||
* но и с помощью смещений для обычных указателей на элементы.
|
||
* Это означает, что указатель на элемент вектора может передаваться в любую функцию,
|
||
* ожидающую указатель на элемент массива.
|
||
*
|
||
* Память вектора обрабатывается автоматически,
|
||
* расширяясь и сжимаясь по мере необходимости.
|
||
* Векторы обычно занимают больше места, чем статические массивы,
|
||
* поскольку больше памяти выделяется для обработки будущего роста.
|
||
* Таким образом, память для вектора требуется выделять
|
||
* не при каждой вставке элемента,
|
||
* а только после исчерпания дополнительной памяти.
|
||
* Общий объём выделенной памяти можно получить с помощью функции \a capacity().
|
||
*
|
||
* Выделение памяти обычно является дорогостоящей операцией
|
||
* с точки зрения производительности.
|
||
* Функцию \a reserve() можно использовать для исключения выделения памяти,
|
||
* если количество элементов известно заранее.
|
||
*
|
||
* Сложность (эффективность) обычных операций над векторами следующая:
|
||
* - Произвольный доступ — постоянная 𝓞(1)
|
||
* - Вставка и удаление элементов в конце — амортизированная постоянная 𝓞(1)
|
||
* - Вставка и удаление элементов — линейная по расстоянию до конца вектора 𝓞(n)
|
||
*/
|
||
template <typename T>
|
||
class PIVector {
|
||
public:
|
||
//! Contructs an empty vector
|
||
inline PIVector(): piv_data(0), piv_size(0), piv_rsize(0) {
|
||
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
|
||
}
|
||
//! \brief Contructs vector with size "size" filled elements "value"
|
||
inline PIVector(const T * data, size_t size): piv_data(0), piv_size(0), piv_rsize(0) {
|
||
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
|
||
alloc(size);
|
||
newT(piv_data, data, piv_size);
|
||
}
|
||
inline PIVector(const PIVector<T> & v): piv_data(0), piv_size(0), piv_rsize(0) {
|
||
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
|
||
alloc(v.piv_size);
|
||
newT(piv_data, v.piv_data, piv_size);
|
||
}
|
||
//! \brief Contructs vector from C++11 initializer list
|
||
inline PIVector(std::initializer_list<T> init_list): piv_data(0), piv_size(0), piv_rsize(0) {
|
||
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
|
||
alloc(init_list.size());
|
||
newT(piv_data, init_list.begin(), init_list.size());
|
||
}
|
||
inline PIVector(size_t piv_size, const T & f = T()): piv_data(0), piv_size(0), piv_rsize(0) {
|
||
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
|
||
resize(piv_size, f);
|
||
}
|
||
inline PIVector(size_t piv_size, std::function<T(size_t i)> f): piv_data(0), piv_size(0), piv_rsize(0) {
|
||
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
|
||
resize(piv_size, f);
|
||
}
|
||
inline PIVector(PIVector<T> && v): piv_data(v.piv_data), piv_size(v.piv_size), piv_rsize(v.piv_rsize) {
|
||
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
|
||
v._reset();
|
||
}
|
||
inline virtual ~PIVector() {
|
||
PIINTROSPECTION_CONTAINER_DELETE(T)
|
||
PIINTROSPECTION_CONTAINER_FREE(T, (piv_rsize))
|
||
deleteT(piv_data, piv_size);
|
||
dealloc();
|
||
_reset();
|
||
}
|
||
|
||
inline PIVector<T> & operator =(const PIVector<T> & v) {
|
||
if (this == &v) return *this;
|
||
clear();
|
||
deleteT(piv_data, piv_size);
|
||
alloc(v.piv_size);
|
||
newT(piv_data, v.piv_data, piv_size);
|
||
return *this;
|
||
}
|
||
|
||
inline PIVector<T> & operator =(PIVector<T> && v) {
|
||
swap(v);
|
||
return *this;
|
||
}
|
||
|
||
enum ReshapeOrder {
|
||
byRow,
|
||
byColumn
|
||
};
|
||
|
||
class iterator {
|
||
friend class PIVector<T>;
|
||
private:
|
||
inline iterator(PIVector<T> * v, size_t p): parent(v), pos(p) {}
|
||
PIVector<T> * parent;
|
||
size_t pos;
|
||
public:
|
||
inline iterator(): parent(0), pos(0) {}
|
||
inline T & operator *() {return (*parent)[pos];}
|
||
inline const T & operator *() const {return (*parent)[pos];}
|
||
inline void operator ++() {++pos;}
|
||
inline void operator ++(int) {++pos;}
|
||
inline void operator --() {--pos;}
|
||
inline void operator --(int) {--pos;}
|
||
inline bool operator ==(const iterator & it) const {return (pos == it.pos);}
|
||
inline bool operator !=(const iterator & it) const {return (pos != it.pos);}
|
||
};
|
||
|
||
class const_iterator {
|
||
friend class PIVector<T>;
|
||
private:
|
||
inline const_iterator(const PIVector<T> * v, size_t p): parent(v), pos(p) {}
|
||
const PIVector<T> * parent;
|
||
size_t pos;
|
||
public:
|
||
inline const_iterator(): parent(0), pos(0) {}
|
||
inline const T & operator *() const {return (*parent)[pos];}
|
||
inline void operator ++() {++pos;}
|
||
inline void operator ++(int) {++pos;}
|
||
inline void operator --() {--pos;}
|
||
inline void operator --(int) {--pos;}
|
||
inline bool operator ==(const const_iterator & it) const {return (pos == it.pos);}
|
||
inline bool operator !=(const const_iterator & it) const {return (pos != it.pos);}
|
||
};
|
||
|
||
class reverse_iterator {
|
||
friend class PIVector<T>;
|
||
private:
|
||
inline reverse_iterator(PIVector<T> * v, size_t p): parent(v), pos(p) {}
|
||
PIVector<T> * parent;
|
||
size_t pos;
|
||
public:
|
||
inline reverse_iterator(): parent(0), pos(0) {}
|
||
inline T & operator *() {return (*parent)[pos];}
|
||
inline const T & operator *() const {return (*parent)[pos];}
|
||
inline void operator ++() {--pos;}
|
||
inline void operator ++(int) {--pos;}
|
||
inline void operator --() {++pos;}
|
||
inline void operator --(int) {++pos;}
|
||
inline bool operator ==(const reverse_iterator & it) const {return (pos == it.pos);}
|
||
inline bool operator !=(const reverse_iterator & it) const {return (pos != it.pos);}
|
||
};
|
||
|
||
class const_reverse_iterator {
|
||
friend class PIVector<T>;
|
||
private:
|
||
inline const_reverse_iterator(const PIVector<T> * v, size_t p): parent(v), pos(p) {}
|
||
const PIVector<T> * parent;
|
||
size_t pos;
|
||
public:
|
||
inline const_reverse_iterator(): parent(0), pos(0) {}
|
||
inline const T & operator *() const {return (*parent)[pos];}
|
||
inline void operator ++() {--pos;}
|
||
inline void operator ++(int) {--pos;}
|
||
inline void operator --() {++pos;}
|
||
inline void operator --(int) {++pos;}
|
||
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);}
|
||
};
|
||
|
||
inline iterator begin() {return iterator(this, 0);}
|
||
inline iterator end() {return iterator(this, piv_size);}
|
||
inline const_iterator begin() const {return const_iterator(this, 0);}
|
||
inline const_iterator end() const {return const_iterator(this, piv_size);}
|
||
inline reverse_iterator rbegin() {return reverse_iterator(this, piv_size - 1);}
|
||
inline reverse_iterator rend() {return reverse_iterator(this, -1);}
|
||
inline const_reverse_iterator rbegin() const {return const_reverse_iterator(this, piv_size - 1);}
|
||
inline const_reverse_iterator rend() const {return const_reverse_iterator(this, -1);}
|
||
|
||
inline size_t size() const {return piv_size;}
|
||
inline ssize_t size_s() const {return piv_size;}
|
||
inline size_t length() const {return piv_size;}
|
||
inline size_t capacity() const {return piv_rsize;}
|
||
inline bool isEmpty() const {return (piv_size == 0);}
|
||
inline bool isNotEmpty() const {return (piv_size > 0);}
|
||
inline bool any(std::function<bool(const T & e)> test) const {
|
||
for (size_t i = 0; i < piv_size; ++i) {
|
||
if (test(piv_data[i])) return true;
|
||
}
|
||
return false;
|
||
}
|
||
inline bool every(std::function<bool(const T & e)> test) const {
|
||
for (size_t i = 0; i < piv_size; ++i) {
|
||
if (!test(piv_data[i])) return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
inline T & operator [](size_t index) {return piv_data[index];}
|
||
inline const T & operator [](size_t index) const {return piv_data[index];}
|
||
inline const T & at(size_t index) const {return piv_data[index];}
|
||
inline T & back() {return piv_data[piv_size - 1];}
|
||
inline const T & back() const {return piv_data[piv_size - 1];}
|
||
inline T & front() {return piv_data[0];}
|
||
inline const T & front() const {return piv_data[0];}
|
||
inline bool operator ==(const PIVector<T> & t) const {
|
||
if (piv_size != t.piv_size) {
|
||
return false;
|
||
}
|
||
for (size_t i = 0; i < piv_size; ++i) {
|
||
if (t[i] != piv_data[i]) {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
inline bool operator !=(const PIVector<T> & t) const {return !(*this == t);}
|
||
inline bool operator <(const PIVector<T> & t) const {
|
||
if (piv_size != t.piv_size) return piv_size < t.piv_size;
|
||
for (size_t i = 0; i < piv_size; ++i) {
|
||
if ((*this)[i] != t[i]) return (*this)[i] < t[i];
|
||
}
|
||
return false;
|
||
}
|
||
inline bool operator >(const PIVector<T> & t) const {
|
||
if (piv_size != t.piv_size) return piv_size > t.piv_size;
|
||
for (size_t i = 0; i < piv_size; ++i) {
|
||
if ((*this)[i] != t[i]) return (*this)[i] > t[i];
|
||
}
|
||
return false;
|
||
}
|
||
inline bool contains(const T & e) const {
|
||
for (size_t i = 0; i < piv_size; ++i) {
|
||
if (e == piv_data[i]) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
inline int etries(const T & e, size_t start = 0) const {
|
||
int ec = 0;
|
||
if (start >= piv_size) return ec;
|
||
for (size_t i = start; i < piv_size; ++i) {
|
||
if (e == piv_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 >= piv_size) return ec;
|
||
for (size_t i = start; i < piv_size; ++i) {
|
||
if (test(piv_data[i])) ++ec;
|
||
}
|
||
return ec;
|
||
}
|
||
inline ssize_t indexOf(const T & e, size_t start = 0) const {
|
||
if (start >= piv_size) return -1;
|
||
for (size_t i = start; i < piv_size; ++i) {
|
||
if (e == piv_data[i]) {
|
||
return i;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
inline ssize_t indexWhere(std::function<bool(const T & e)> test, size_t start = 0) const {
|
||
if (start >= piv_size) return -1;
|
||
for (size_t i = start; i < piv_size; ++i) {
|
||
if (test(piv_data[i])) {
|
||
return i;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
inline ssize_t lastIndexOf(const T & e, ssize_t start = -1) const {
|
||
if (start < 0) start = piv_size - 1;
|
||
else start = piMin<ssize_t>(piv_size - 1, start);
|
||
for (ssize_t i = start; i >= 0; --i) {
|
||
if (e == piv_data[i]) {
|
||
return i;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
inline ssize_t lastIndexWhere(std::function<bool(const T & e)> test, ssize_t start = -1) const {
|
||
if (start < 0) start = piv_size - 1;
|
||
else start = piMin<ssize_t>(piv_size - 1, start);
|
||
for (ssize_t i = start; i >= 0; --i) {
|
||
if (test(piv_data[i])) {
|
||
return i;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
inline T * data(size_t index = 0) {return &(piv_data[index]);}
|
||
inline const T * data(size_t index = 0) const {return &(piv_data[index]);}
|
||
|
||
PIVector<T> getRange(size_t index, size_t count) const {
|
||
if (index >= piv_size || count == 0) return PIVector<T>();
|
||
if (index + count > piv_size) count = piv_size - index;
|
||
return PIVector(&(piv_data[index]), count);
|
||
}
|
||
|
||
template<typename T1 = T, typename std::enable_if<
|
||
!std::is_trivially_copyable<T1>::value
|
||
, int>::type = 0>
|
||
inline PIVector<T> & clear() {
|
||
resize(0);
|
||
return *this;
|
||
}
|
||
template<typename T1 = T, typename std::enable_if<
|
||
std::is_trivially_copyable<T1>::value
|
||
, int>::type = 0>
|
||
inline PIVector<T> & clear() {
|
||
PIINTROSPECTION_CONTAINER_UNUSED(T, piv_size)
|
||
piv_size = 0;
|
||
return *this;
|
||
}
|
||
|
||
inline PIVector<T> & fill(const T & f = T()) {
|
||
deleteT(piv_data, piv_size);
|
||
PIINTROSPECTION_CONTAINER_USED(T, piv_size)
|
||
for (size_t i = 0; i < piv_size; ++i) {
|
||
elementNew(piv_data + i, f);
|
||
}
|
||
return *this;
|
||
}
|
||
inline PIVector<T> & fill(std::function<T(size_t i)> f) {
|
||
deleteT(piv_data, piv_size);
|
||
PIINTROSPECTION_CONTAINER_USED(T, piv_size)
|
||
for (size_t i = 0; i < piv_size; ++i) {
|
||
elementNew(piv_data + i, f(i));
|
||
}
|
||
return *this;
|
||
}
|
||
inline PIVector<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 PIVector<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 PIVector<T> & assign(size_t new_size, const T & f) {
|
||
_resizeRaw(new_size);
|
||
return fill(f);
|
||
}
|
||
|
||
inline PIVector<T> & resize(size_t new_size, const T & f = T()) {
|
||
if (new_size < piv_size) {
|
||
T * de = &(piv_data[new_size]);
|
||
deleteT(de, piv_size - new_size);
|
||
piv_size = new_size;
|
||
}
|
||
if (new_size > piv_size) {
|
||
size_t os = piv_size;
|
||
alloc(new_size);
|
||
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os))
|
||
for (size_t i = os; i < new_size; ++i) {
|
||
elementNew(piv_data + i, f);
|
||
}
|
||
}
|
||
return *this;
|
||
}
|
||
inline PIVector<T> & resize(size_t new_size, std::function<T(size_t i)> f) {
|
||
if (new_size < piv_size) {
|
||
T * de = &(piv_data[new_size]);
|
||
deleteT(de, piv_size - new_size);
|
||
piv_size = new_size;
|
||
}
|
||
if (new_size > piv_size) {
|
||
size_t os = piv_size;
|
||
alloc(new_size);
|
||
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os))
|
||
for (size_t i = os; i < new_size; ++i) {
|
||
elementNew(piv_data + i, f(i));
|
||
}
|
||
}
|
||
return *this;
|
||
}
|
||
template<typename T1 = T, typename std::enable_if<
|
||
std::is_trivially_copyable<T1>::value
|
||
, int>::type = 0>
|
||
inline PIVector<T> & _resizeRaw(size_t new_size) {
|
||
if (new_size > piv_size) {
|
||
PIINTROSPECTION_CONTAINER_USED(T, (new_size-piv_size));
|
||
}
|
||
if (new_size < piv_size) {
|
||
PIINTROSPECTION_CONTAINER_UNUSED(T, (piv_size-new_size));
|
||
}
|
||
alloc(new_size);
|
||
return *this;
|
||
}
|
||
inline void _copyRaw(T * dst, const T * src, size_t size) {
|
||
newT(dst, src, size);
|
||
}
|
||
|
||
inline PIVector<T> & reserve(size_t new_size) {
|
||
if (new_size <= piv_rsize) return *this;
|
||
size_t os = piv_size;
|
||
alloc(new_size);
|
||
piv_size = os;
|
||
return *this;
|
||
}
|
||
|
||
inline PIVector<T> & insert(size_t index, const T & e = T()) {
|
||
alloc(piv_size + 1);
|
||
if (index < piv_size - 1) {
|
||
size_t os = piv_size - index - 1;
|
||
memmove((void*)(&(piv_data[index + 1])), (const void*)(&(piv_data[index])), os * sizeof(T));
|
||
}
|
||
PIINTROSPECTION_CONTAINER_USED(T, 1)
|
||
elementNew(piv_data + index, e);
|
||
return *this;
|
||
}
|
||
inline PIVector<T> & insert(size_t index, T && e) {
|
||
alloc(piv_size + 1);
|
||
if (index < piv_size - 1) {
|
||
size_t os = piv_size - index - 1;
|
||
memmove((void*)(&(piv_data[index + 1])), (const void*)(&(piv_data[index])), os * sizeof(T));
|
||
}
|
||
PIINTROSPECTION_CONTAINER_USED(T, 1)
|
||
elementNew(piv_data + index, std::move(e));
|
||
return *this;
|
||
}
|
||
inline PIVector<T> & insert(size_t index, const PIVector<T> & v) {
|
||
if (v.isEmpty()) return *this;
|
||
assert(&v != this);
|
||
ssize_t os = piv_size - index;
|
||
alloc(piv_size + v.piv_size);
|
||
if (os > 0) {
|
||
memmove((void*)(&(piv_data[index + v.piv_size])), (const void*)(&(piv_data[index])), os * sizeof(T));
|
||
}
|
||
newT(piv_data + index, v.piv_data, v.piv_size);
|
||
return *this;
|
||
}
|
||
|
||
inline PIVector<T> & remove(size_t index, size_t count = 1) {
|
||
if (count == 0) return *this;
|
||
if (index + count >= piv_size) {
|
||
resize(index);
|
||
return *this;
|
||
}
|
||
size_t os = piv_size - index - count;
|
||
deleteT(&(piv_data[index]), count);
|
||
memmove((void*)(&(piv_data[index])), (const void*)(&(piv_data[index + count])), os * sizeof(T));
|
||
piv_size -= count;
|
||
return *this;
|
||
}
|
||
|
||
inline void swap(PIVector<T> & v) {
|
||
piSwap<T*>(piv_data, v.piv_data);
|
||
piSwap<size_t>(piv_size, v.piv_size);
|
||
piSwap<size_t>(piv_rsize, v.piv_rsize);
|
||
}
|
||
|
||
typedef int (*CompareFunc)(const T * , const T * );
|
||
static int compare_func(const T * t0, const T * t1) {return (*t0) < (*t1) ? -1 : ((*t0) == (*t1) ? 0 : 1);}
|
||
inline PIVector<T> & sort(CompareFunc compare = compare_func) {
|
||
piqsort(piv_data, piv_size, sizeof(T), (int(*)(const void * , const void * ))compare);
|
||
return *this;
|
||
}
|
||
|
||
inline PIVector<T> & enlarge(llong piv_size) {
|
||
llong ns = size_s() + piv_size;
|
||
if (ns <= 0) clear();
|
||
else resize(size_t(ns));
|
||
return *this;
|
||
}
|
||
|
||
/*! \brief Remove no more than one element equal "v" and return reference to vector
|
||
* \details Example: \snippet picontainers.cpp PIVector::removeOne
|
||
* \sa \a remove(), \a removeAll()
|
||
*/
|
||
inline PIVector<T> & removeOne(const T & e) {
|
||
for (size_t i = 0; i < piv_size; ++i) {
|
||
if (piv_data[i] == e) {
|
||
remove(i);
|
||
return *this;
|
||
}
|
||
}
|
||
return *this;
|
||
}
|
||
inline PIVector<T> & removeAll(const T & e) {
|
||
for (ssize_t i = 0; i < ssize_t(piv_size); ++i) {
|
||
if (piv_data[i] == e) {
|
||
remove(i);
|
||
--i;
|
||
}
|
||
}
|
||
return *this;
|
||
}
|
||
inline PIVector<T> & removeWhere(std::function<bool(const T & e)> test) {
|
||
for (ssize_t i = 0; i < ssize_t(piv_size); ++i) {
|
||
if (test(piv_data[i])) {
|
||
remove(i);
|
||
--i;
|
||
}
|
||
}
|
||
return *this;
|
||
}
|
||
|
||
inline PIVector<T> & push_back(const T & e) {
|
||
alloc(piv_size + 1);
|
||
PIINTROSPECTION_CONTAINER_USED(T, 1);
|
||
elementNew(piv_data + piv_size - 1, e);
|
||
return *this;
|
||
}
|
||
|
||
inline PIVector<T> & push_back(T && e) {
|
||
alloc(piv_size + 1);
|
||
PIINTROSPECTION_CONTAINER_USED(T, 1);
|
||
elementNew(piv_data + piv_size - 1, std::move(e));
|
||
return *this;
|
||
}
|
||
|
||
inline PIVector<T> & append(const T & e) {return push_back(e);}
|
||
inline PIVector<T> & append(T && e) {return push_back(std::move(e));}
|
||
inline PIVector<T> & append(const PIVector<T> & v) {
|
||
assert(&v != this);
|
||
size_t ps = piv_size;
|
||
alloc(piv_size + v.piv_size);
|
||
newT(piv_data + ps, v.piv_data, v.piv_size);
|
||
return *this;
|
||
}
|
||
inline PIVector<T> & operator <<(const T & e) {return push_back(e);}
|
||
inline PIVector<T> & operator <<(T && e) {return push_back(std::move(e));}
|
||
inline PIVector<T> & operator <<(const PIVector<T> & v) {return append(v);}
|
||
|
||
inline PIVector<T> & push_front(const T & e) {insert(0, e); return *this;}
|
||
inline PIVector<T> & push_front(T && e) {insert(0, std::move(e)); return *this;}
|
||
inline PIVector<T> & prepend(const T & e) {return push_front(e);}
|
||
inline PIVector<T> & prepend(T && e) {return push_front(std::move(e));}
|
||
|
||
inline PIVector<T> & pop_back() {
|
||
if (piv_size == 0) return *this;
|
||
resize(piv_size - 1);
|
||
return *this;
|
||
}
|
||
inline PIVector<T> & pop_front() {
|
||
if (piv_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>
|
||
PIVector<ST> toType() const {
|
||
PIVector<ST> ret(piv_size);
|
||
for (size_t i = 0; i < piv_size; ++i) {
|
||
ret[i] = ST(piv_data[i]);
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
const PIVector<T> & forEach(std::function<void(const T & e)> f) const {
|
||
for (size_t i = 0; i < piv_size; ++i) {
|
||
f(piv_data[i]);
|
||
}
|
||
return *this;
|
||
}
|
||
PIVector<T> copyForEach(std::function<T(const T & e)> f) const {
|
||
PIVector<T> ret; ret.reserve(piv_size);
|
||
for (size_t i = 0; i < piv_size; ++i) {
|
||
ret << f(piv_data[i]);
|
||
}
|
||
return ret;
|
||
}
|
||
PIVector<T> & forEachInplace(std::function<T(const T & e)> f) {
|
||
for (size_t i = 0; i < piv_size; ++i) {
|
||
piv_data[i] = f(piv_data[i]);
|
||
}
|
||
return *this;
|
||
}
|
||
|
||
template <typename ST>
|
||
PIVector<ST> map(std::function<ST(const T & e)> f) const {
|
||
PIVector<ST> ret; ret.reserve(piv_size);
|
||
for (size_t i = 0; i < piv_size; ++i) {
|
||
ret << f(piv_data[i]);
|
||
}
|
||
return ret;
|
||
}
|
||
template <typename ST>
|
||
PIVector<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 < piv_size; ++i) {
|
||
ret = f(piv_data[i], ret);
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
inline PIVector<PIVector<T>> reshape(size_t rows, size_t cols, ReshapeOrder order = byRow) const {
|
||
PIVector<PIVector<T>> ret;
|
||
if (isEmpty()) return ret;
|
||
assert(rows*cols == piv_size);
|
||
ret.resize(rows);
|
||
if (order == byRow) {
|
||
for (size_t r = 0; r < rows; r++) {
|
||
ret[r] = PIVector<T>(&(piv_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] = piv_data[c*rows + r];
|
||
}
|
||
}
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
template<typename C, typename std::enable_if<
|
||
std::is_same<T, PIVector<C>>::value
|
||
, int>::type = 0>
|
||
inline PIVector<C> reshape(ReshapeOrder order = byRow) const {
|
||
PIVector<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() {piv_size = piv_rsize = 0; piv_data = 0;}
|
||
inline size_t asize(size_t s) {
|
||
if (s == 0) return 0;
|
||
if (piv_rsize + piv_rsize >= s && piv_rsize < s) {
|
||
return piv_rsize + piv_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*)piv_data != 0) free((uchar*)piv_data);
|
||
piv_data = 0;
|
||
}
|
||
inline void alloc(size_t new_size) {
|
||
if (new_size <= piv_rsize) {
|
||
piv_size = new_size;
|
||
return;
|
||
}
|
||
piv_size = new_size;
|
||
size_t as = asize(new_size);
|
||
if (as == piv_rsize) return;
|
||
PIINTROSPECTION_CONTAINER_ALLOC(T, (as-piv_rsize))
|
||
T * p_d = (T*)(realloc((void*)(piv_data), as*sizeof(T)));
|
||
assert(p_d);
|
||
piv_data = p_d;
|
||
piv_rsize = as;
|
||
}
|
||
|
||
T * piv_data;
|
||
size_t piv_size, piv_rsize;
|
||
};
|
||
|
||
|
||
|
||
#ifdef PIP_STD_IOSTREAM
|
||
template<typename T>
|
||
inline std::ostream & operator <<(std::ostream & s, const PIVector<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 PIVector<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(PIVector<T> & f, PIVector<T> & s) {f.swap(s);}
|
||
|
||
|
||
#endif // PIVECTOR_H
|