PIDeque optimize and bugfix #165

Merged
andrey merged 2 commits from deque2 into master 2022-08-23 10:30:06 +03:00
3 changed files with 153 additions and 104 deletions

View File

@@ -127,13 +127,13 @@ public:
//! \~english Constructs an empty array. //! \~english Constructs an empty array.
//! \~russian Создает пустой массив. //! \~russian Создает пустой массив.
inline PIDeque(): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) { inline PIDeque() {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
} }
//! \~english Copy constructor. //! \~english Copy constructor.
//! \~russian Копирующий конструктор. //! \~russian Копирующий конструктор.
inline PIDeque(const PIDeque<T> & other): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) { inline PIDeque(const PIDeque<T> & other) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc_forward(other.pid_size); alloc_forward(other.pid_size);
newT(pid_data + pid_start, other.pid_data + other.pid_start, pid_size); newT(pid_data + pid_start, other.pid_data + other.pid_start, pid_size);
@@ -148,7 +148,7 @@ public:
//! PIDeque <int> v{1,2,3}; //! PIDeque <int> v{1,2,3};
//! piCout << v; // {1, 2, 3} //! piCout << v; // {1, 2, 3}
//! \endcode //! \endcode
inline PIDeque(std::initializer_list<T> init_list): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) { inline PIDeque(std::initializer_list<T> init_list) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc_forward(init_list.size()); alloc_forward(init_list.size());
newT(pid_data, init_list.begin(), init_list.size()); newT(pid_data, init_list.begin(), init_list.size());
@@ -158,7 +158,7 @@ public:
//! This constructor reserve `size` and copy from `data` pointer. //! This constructor reserve `size` and copy from `data` pointer.
//! \~russian Создает массив из указателя на данные `data` и размер `size`. //! \~russian Создает массив из указателя на данные `data` и размер `size`.
//! То есть выделяет память для `size` элементов и копирует данные из указателя `data`. //! То есть выделяет память для `size` элементов и копирует данные из указателя `data`.
inline PIDeque(const T * data, size_t size): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) { inline PIDeque(const T * data, size_t size) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc_forward(size); alloc_forward(size);
newT(pid_data + pid_start, data, pid_size); newT(pid_data + pid_start, data, pid_size);
@@ -166,9 +166,9 @@ public:
//! \~english Contructs array with size `size` filled elements `e`. //! \~english Contructs array with size `size` filled elements `e`.
//! \~russian Создает массив из `size` элементов заполненных `e`. //! \~russian Создает массив из `size` элементов заполненных `e`.
inline PIDeque(size_t pid_size, const T & e = T()): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) { inline PIDeque(size_t pid_size, const T & e = T()) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(pid_size, e); expand(pid_size, e);
} }
//! \~english Contructs array with size `size` and elements created by function `f(size_t i)`. //! \~english Contructs array with size `size` and elements created by function `f(size_t i)`.
@@ -184,15 +184,19 @@ public:
//! PIDeque <int> v(5, [](size_t i){return i*2;}); //! PIDeque <int> v(5, [](size_t i){return i*2;});
//! piCout << v; // {0, 2, 4, 6, 8} //! piCout << v; // {0, 2, 4, 6, 8}
//! \endcode //! \endcode
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) { inline PIDeque(size_t piv_size, std::function<T(size_t i)> f) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(piv_size, f); expand(piv_size, f);
} }
//! \~english Move constructor. //! \~english Move constructor.
//! \~russian Перемещающий конструктор. //! \~russian Перемещающий конструктор.
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) { inline PIDeque(PIDeque<T> && other) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
pid_data = other.pid_data;
pid_size = other.pid_size;
pid_rsize = other.pid_rsize;
pid_start = other.pid_start;
other._reset(); other._reset();
} }
@@ -1185,7 +1189,9 @@ public:
!std::is_trivially_copyable<T1>::value !std::is_trivially_copyable<T1>::value
, int>::type = 0> , int>::type = 0>
inline PIDeque<T> & clear() { inline PIDeque<T> & clear() {
resize(0); deleteT(&(pid_data[pid_start]), pid_size);
pid_size = 0;
pid_start = (pid_rsize - pid_size) / 2;
return *this; return *this;
} }
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<
@@ -1269,20 +1275,12 @@ public:
//! лишние элементы удаляются с конца массива. //! лишние элементы удаляются с конца массива.
//! \~\sa \a size(), \a clear() //! \~\sa \a size(), \a clear()
inline PIDeque<T> & resize(size_t new_size, const T & e = T()) { inline PIDeque<T> & resize(size_t new_size, const T & e = T()) {
if (new_size == 0) return clear();
if (new_size < pid_size) { if (new_size < pid_size) {
deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size); deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size);
pid_size = new_size; pid_size = new_size;
if (new_size == 0) { }else if (new_size > pid_size) {
pid_start = (pid_rsize - pid_size) / 2; expand(new_size, e);
}
}
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, e);
}
} }
return *this; return *this;
} }
@@ -1299,20 +1297,12 @@ public:
//! лишние элементы удаляются с конца массива. //! лишние элементы удаляются с конца массива.
//! \~\sa \a size(), \a clear() //! \~\sa \a size(), \a clear()
inline PIDeque<T> & resize(size_t new_size, std::function<T(size_t i)> f) { inline PIDeque<T> & resize(size_t new_size, std::function<T(size_t i)> f) {
if (new_size == 0) return clear();
if (new_size < pid_size) { if (new_size < pid_size) {
deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size); deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size);
pid_size = new_size; pid_size = new_size;
if (new_size == 0) { } else if (new_size > pid_size) {
pid_start = (pid_rsize - pid_size) / 2; expand(new_size, f);
}
}
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; return *this;
} }
@@ -1428,7 +1418,7 @@ public:
} }
#endif #endif
assert(&v != this); assert(&v != this);
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false); bool dir = v.size() > pid_size ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) { if (dir) {
ssize_t os = pid_size - index; ssize_t os = pid_size - index;
alloc_forward(pid_size + v.pid_size); alloc_forward(pid_size + v.pid_size);
@@ -1456,7 +1446,7 @@ public:
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list). //! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a append(), \a prepend(), \a remove() //! \~\sa \a append(), \a prepend(), \a remove()
inline PIDeque<T> & insert(size_t index, std::initializer_list<T> init_list) { inline PIDeque<T> & insert(size_t index, std::initializer_list<T> init_list) {
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false); bool dir = init_list.size() > pid_size ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) { if (dir) {
ssize_t os = ssize_t(pid_size) - index; ssize_t os = ssize_t(pid_size) - index;
alloc_forward(pid_size + init_list.size()); alloc_forward(pid_size + init_list.size());
@@ -1485,7 +1475,10 @@ public:
inline PIDeque<T> & remove(size_t index, size_t count = 1) { inline PIDeque<T> & remove(size_t index, size_t count = 1) {
if (count == 0) return *this; if (count == 0) return *this;
if (index + count >= pid_size) { if (index + count >= pid_size) {
resize(index); if (index < pid_size) {
deleteT(&(pid_data[index + pid_start]), pid_size - index);
pid_size = index;
}
return *this; return *this;
} }
size_t os = pid_size - index - count; size_t os = pid_size - index - count;
@@ -1758,6 +1751,7 @@ public:
//! \~russian Перегруженая функция. //! \~russian Перегруженая функция.
//! \~\sa \a push_back() //! \~\sa \a push_back()
inline PIDeque<T> & push_back(const PIDeque<T> & v) { inline PIDeque<T> & push_back(const PIDeque<T> & v) {
if (v.isEmpty()) return *this;
#ifndef NDEBUG #ifndef NDEBUG
if (&v == this) { if (&v == this) {
printf("error with PIDeque<%s>::append\n", __PIP_TYPENAME__(T)); printf("error with PIDeque<%s>::append\n", __PIP_TYPENAME__(T));
@@ -1887,7 +1881,9 @@ public:
//! \endcode //! \endcode
//! \~\sa \a push_back(), \a append(), \a prepend(), \a insert() //! \~\sa \a push_back(), \a append(), \a prepend(), \a insert()
inline PIDeque<T> & push_front(const T & e) { inline PIDeque<T> & push_front(const T & e) {
insert(0, e); if (isEmpty()) return push_back(e);
alloc_backward(pid_size + 1, -1);
elementNew(pid_data + pid_start, e);
return *this; return *this;
} }
@@ -1898,7 +1894,9 @@ public:
//! \~russian Перегруженая функция. //! \~russian Перегруженая функция.
//! \~\sa \a push_front() //! \~\sa \a push_front()
inline PIDeque<T> & push_front(T && e) { inline PIDeque<T> & push_front(T && e) {
insert(0, std::move(e)); if (isEmpty()) return push_back(std::move(e));
alloc_backward(pid_size + 1, -1);
elementNew(pid_data + pid_start, std::move(e));
return *this; return *this;
} }
@@ -1914,8 +1912,7 @@ public:
//! \endcode //! \endcode
//! \~\sa \a push_front() //! \~\sa \a push_front()
inline PIDeque<T> & push_front(const PIDeque<T> & v) { inline PIDeque<T> & push_front(const PIDeque<T> & v) {
insert(0, v); return insert(0, v);
return *this;
} }
//! \~english Appends the given elements to the begin of the array. //! \~english Appends the given elements to the begin of the array.
@@ -1929,8 +1926,7 @@ public:
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list). //! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a append() //! \~\sa \a append()
inline PIDeque<T> & push_front(std::initializer_list<T> init_list) { inline PIDeque<T> & push_front(std::initializer_list<T> init_list) {
insert(0, init_list); return insert(0, init_list);
return *this;
} }
//! \~english Appends the given element `e` to the begin of the array. //! \~english Appends the given element `e` to the begin of the array.
@@ -2007,7 +2003,8 @@ public:
//! \~\sa \a pop_front(), \a take_back(), \a take_front() //! \~\sa \a pop_front(), \a take_back(), \a take_front()
inline PIDeque<T> & pop_back() { inline PIDeque<T> & pop_back() {
if (pid_size == 0) return *this; if (pid_size == 0) return *this;
resize(pid_size - 1); elementDelete(pid_data[pid_size + pid_start - 1]);
pid_size = pid_size - 1;
return *this; return *this;
} }
@@ -2028,7 +2025,9 @@ public:
//! \~\sa \a pop_back(), \a take_back(), \a take_front() //! \~\sa \a pop_back(), \a take_back(), \a take_front()
inline PIDeque<T> & pop_front() { inline PIDeque<T> & pop_front() {
if (pid_size == 0) return *this; if (pid_size == 0) return *this;
remove(0); elementDelete(pid_data[pid_start]);
pid_start += 1;
pid_size -= 1;
return *this; return *this;
} }
@@ -2420,7 +2419,7 @@ public:
} }
#endif #endif
assert(rows*cols == pid_size); assert(rows*cols == pid_size);
ret.resize(rows); ret.expand(rows);
if (order == ReshapeByRow) { if (order == ReshapeByRow) {
for (size_t r = 0; r < rows; r++) { for (size_t r = 0; r < rows; r++) {
ret[r] = PIDeque<T>(&(pid_data[r*cols]), cols); ret[r] = PIDeque<T>(&(pid_data[r*cols]), cols);
@@ -2428,7 +2427,7 @@ public:
} }
if (order == ReshapeByColumn) { if (order == ReshapeByColumn) {
for (size_t r = 0; r < rows; r++) { for (size_t r = 0; r < rows; r++) {
ret[r].resize(cols); ret[r].expand(cols);
for (size_t c = 0; c < cols; c++) { for (size_t c = 0; c < cols; c++) {
ret[r][c] = pid_data[c*rows + r]; ret[r][c] = pid_data[c*rows + r];
} }
@@ -2503,7 +2502,13 @@ public:
} }
private: private:
inline void _reset() {pid_size = pid_rsize = pid_start = 0; pid_data = 0;} inline void _reset() {
pid_size = 0;
pid_rsize = 0;
pid_start = 0;
pid_data = nullptr;
}
inline size_t asize(ssize_t s) { inline size_t asize(ssize_t s) {
if (s <= 0) return 0; if (s <= 0) return 0;
if (pid_rsize + pid_rsize >= size_t(s) && pid_rsize < size_t(s)) { if (pid_rsize + pid_rsize >= size_t(s) && pid_rsize < size_t(s)) {
@@ -2511,18 +2516,20 @@ private:
} }
size_t t = _PIContainerConstants<T>::minCountPoT(); size_t t = _PIContainerConstants<T>::minCountPoT();
size_t s_ = s - 1; size_t s_ = s - 1;
while (s_ >> t) while (s_ >> t) ++t;
++t;
return (1 << t); return (1 << t);
} }
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value !std::is_trivially_copyable<T1>::value
, int>::type = 0> , int>::type = 0>
inline void newT(T * dst, const T * src, size_t s) { inline void newT(T * dst, const T * src, size_t s) {
PIINTROSPECTION_CONTAINER_USED(T, s) PIINTROSPECTION_CONTAINER_USED(T, s)
for (size_t i = 0; i < s; ++i) for (size_t i = 0; i < s; ++i) {
elementNew(dst + i, src[i]); elementNew(dst + i, src[i]);
} }
}
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value std::is_trivially_copyable<T1>::value
, int>::type = 0> , int>::type = 0>
@@ -2530,55 +2537,77 @@ private:
PIINTROSPECTION_CONTAINER_USED(T, s) PIINTROSPECTION_CONTAINER_USED(T, s)
memcpy((void*)(dst), (const void*)(src), s * sizeof(T)); memcpy((void*)(dst), (const void*)(src), s * sizeof(T));
} }
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value !std::is_trivially_copyable<T1>::value
, int>::type = 0> , int>::type = 0>
inline void deleteT(T * d, size_t sz) { inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz) PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
if ((uchar*)d != 0) { if (d != nullptr) {
for (size_t i = 0; i < sz; ++i) { for (size_t i = 0; i < sz; ++i) {
elementDelete(d[i]); elementDelete(d[i]);
} }
} }
} }
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value std::is_trivially_copyable<T1>::value
, int>::type = 0> , int>::type = 0>
inline void deleteT(T * d, size_t sz) { inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz) PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
} }
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value !std::is_trivially_copyable<T1>::value
, int>::type = 0> , int>::type = 0>
inline void elementNew(T * to, const T & from) {new(to)T(from);} inline void elementNew(T * to, const T & from) {
new(to)T(from);
}
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value !std::is_trivially_copyable<T1>::value
, int>::type = 0> , int>::type = 0>
inline void elementNew(T * to, T && from) {new(to)T(std::move(from));} inline void elementNew(T * to, T && from) {
new(to)T(std::move(from));
}
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value std::is_trivially_copyable<T1>::value
, int>::type = 0> , int>::type = 0>
inline void elementNew(T1 * to, const T & from) {(*to) = from;} inline void elementNew(T1 * to, const T & from) {
(*to) = from;
}
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value std::is_trivially_copyable<T1>::value
, int>::type = 0> , int>::type = 0>
inline void elementNew(T * to, T && from) {(*to) = std::move(from);} inline void elementNew(T * to, T && from) {
(*to) = std::move(from);
}
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value !std::is_trivially_copyable<T1>::value
, int>::type = 0> , int>::type = 0>
inline void elementDelete(T & from) {from.~T();} inline void elementDelete(T & from) {
from.~T();
}
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value std::is_trivially_copyable<T1>::value
, int>::type = 0> , int>::type = 0>
inline void elementDelete(T & from) {} inline void elementDelete(T & from) {}
inline void dealloc() { inline void dealloc() {
if ((uchar*)pid_data != 0) free((uchar*)pid_data); if (pid_data != nullptr) {
pid_data = 0; free((void*)pid_data);
pid_data = nullptr;
} }
}
inline void checkMove() { inline void checkMove() {
if (pid_size >= 4) { if (pid_size >= 4) {
if (pid_size < pid_rsize / 6) { if (pid_size < pid_rsize / 6) {
if (pid_start < (pid_size + pid_size) || ssize_t(pid_start) > (ssize_t(pid_rsize) - ssize_t(pid_size) - ssize_t(pid_size))) { if (pid_start < (pid_size * 2) || ssize_t(pid_start) > (ssize_t(pid_rsize) - (ssize_t(pid_size) * 2))) {
size_t ns = (pid_rsize - pid_size) / 2; size_t ns = (pid_rsize - pid_size) / 2;
if (pid_start != ns) { if (pid_start != ns) {
memmove((void*)(pid_data + ns), (const void*)(pid_data + pid_start), pid_size * sizeof(T)); memmove((void*)(pid_data + ns), (const void*)(pid_data + pid_start), pid_size * sizeof(T));
@@ -2594,10 +2623,11 @@ private:
} }
} }
} }
inline void alloc_forward(size_t new_size) { // direction == true -> alloc forward
inline void alloc_forward(size_t new_size) {
if (pid_start + new_size <= pid_rsize) { if (pid_start + new_size <= pid_rsize) {
pid_size = new_size; pid_size = new_size;
checkMove(); if (pid_start > 0) checkMove();
return; return;
} }
pid_size = new_size; pid_size = new_size;
@@ -2615,7 +2645,8 @@ private:
pid_rsize = as; pid_rsize = as;
} }
} }
inline void alloc_backward(size_t new_size, ssize_t start_offset = 0) { //alloc backward
inline void alloc_backward(size_t new_size, ssize_t start_offset = 0) {
size_t as; size_t as;
if (ssize_t(pid_start) + start_offset < 0) { if (ssize_t(pid_start) + start_offset < 0) {
as = asize(pid_rsize - start_offset); as = asize(pid_rsize - start_offset);
@@ -2639,10 +2670,28 @@ private:
checkMove(); checkMove();
} }
T * pid_data; inline void expand(size_t new_size, const T & e = T()) {
size_t pid_size; size_t os = pid_size;
size_t pid_rsize; alloc_forward(new_size);
size_t pid_start; PIINTROSPECTION_CONTAINER_USED(T, (new_size-os))
for (size_t i = os + pid_start; i < new_size + pid_start; ++i) {
elementNew(pid_data + i, e);
}
}
inline void expand(size_t new_size, std::function<T(size_t i)> f) {
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));
}
}
T * pid_data = nullptr;
size_t pid_size = 0;
size_t pid_rsize = 0;
size_t pid_start = 0;
}; };

View File

@@ -39,7 +39,7 @@ public:
T & head() {return PIDeque<T>::back();} T & head() {return PIDeque<T>::back();}
const T & head() const {return PIDeque<T>::back();} const T & head() const {return PIDeque<T>::back();}
PIVector<T> toVector() {return PIVector<T>(PIDeque<T>::data(), PIDeque<T>::size());} PIVector<T> toVector() {return PIVector<T>(PIDeque<T>::data(), PIDeque<T>::size());}
PIVector<T> toDeque() {return PIDeque<T>(*this);} PIDeque<T> toDeque() {return PIDeque<T>(*this);}
}; };
#endif // PIQUEUE_H #endif // PIQUEUE_H

View File

@@ -38,7 +38,7 @@ public:
T & top() {return PIVector<T>::back();} T & top() {return PIVector<T>::back();}
const T & top() const {return PIVector<T>::back();} const T & top() const {return PIVector<T>::back();}
PIVector<T> toVector() {return PIVector<T>(*this);} PIVector<T> toVector() {return PIVector<T>(*this);}
PIVector<T> toDeque() {return PIDeque<T>(PIVector<T>::data(), PIVector<T>::size());} PIDeque<T> toDeque() {return PIDeque<T>(PIVector<T>::data(), PIVector<T>::size());}
}; };
#endif // PISTACK_H #endif // PISTACK_H