Compare commits
14 Commits
a581d9bf9d
...
854916ad9f
| Author | SHA1 | Date | |
|---|---|---|---|
| 854916ad9f | |||
| 0b7d565b93 | |||
| 97691e888c | |||
| 525dbf8e9e | |||
| b86786e343 | |||
| 8a26b6174d | |||
| 14e62a41bd | |||
| 56ff28c793 | |||
| b01aecc2fe | |||
| 42a1507536 | |||
| 6557933a2e | |||
| 42b2fd4dbe | |||
| 071ab85359 | |||
| 91b20467a7 |
10
AGENTS.md
10
AGENTS.md
@@ -19,13 +19,13 @@ PIP is a C++ cross-platform library providing platform-independent abstractions
|
||||
### Basic Build
|
||||
```bash
|
||||
cmake -B build
|
||||
cmake --build build
|
||||
cmake --build build -j8
|
||||
```
|
||||
|
||||
### Build with Tests
|
||||
```bash
|
||||
cmake -B build -DTESTS=ON
|
||||
cmake --build build
|
||||
cmake --build build -j8
|
||||
```
|
||||
|
||||
### Run Tests
|
||||
@@ -46,7 +46,7 @@ ctest --test-dir build/tests -R "TestName"
|
||||
### Other Commands
|
||||
```bash
|
||||
cmake --build build --target clean # Clean build
|
||||
cmake --install build_pip # Install
|
||||
cmake --install build_pip # Install
|
||||
cmake --build build --target doc # Build documentation
|
||||
```
|
||||
|
||||
@@ -160,3 +160,7 @@ TEST(PIString_Tests, constructor_empty) {
|
||||
### Key Files
|
||||
- `CMakeLists.txt` - Main build configuration
|
||||
- `tests/CMakeLists.txt` - Test configuration
|
||||
|
||||
|
||||
## Lint/Format Commands
|
||||
- For formatting, use clang-format with .clang-format in repo root
|
||||
|
||||
70
dependencies.md
Normal file
70
dependencies.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# PIP Dependencies
|
||||
|
||||
## Встроенные (included in 3rd/)
|
||||
|
||||
| Библиотека | Назначение | Модуль PIP |
|
||||
|------------|------------|------------|
|
||||
| **PCRE2** | Регулярные выражения | main (internal) |
|
||||
| **BLAKE2** | Хеширование | main (internal) |
|
||||
| **SipHash** | Хеширование | main (internal) |
|
||||
| **Lua** | Lua scripting | lua |
|
||||
| **LuaBridge** | Lua bindings | lua |
|
||||
|
||||
## Внешние (системные)
|
||||
|
||||
| Библиотека | Опция | Модуль PIP |
|
||||
|------------|-------|------------|
|
||||
| **ICU** | `-DICU=ON` | main (string conversion) |
|
||||
| **zlib** | `PIP_BUILD_COMPRESS` | compress |
|
||||
| **libsodium** | `PIP_BUILD_CRYPT` | crypt, io_utils, cloud |
|
||||
| **libusb** | `PIP_BUILD_USB` | usb |
|
||||
| **FFTW3** (+ threads) | `PIP_BUILD_FFTW` | fftw |
|
||||
| **OpenCL** | `PIP_BUILD_OPENCL` | opencl |
|
||||
| **libmicrohttpd** | `PIP_BUILD_HTTP_SERVER` | http_server |
|
||||
| **libcurl** | `PIP_BUILD_HTTP_CLIENT` | http_client |
|
||||
| **gnutls** | (optional, для http_server) | http_server |
|
||||
| **pthread** | (system) | main |
|
||||
| **libdl** | (system) | main |
|
||||
| **librt** | (system, не Apple/Android) | main |
|
||||
| **libutil** | (system) | main |
|
||||
| **libsocket** | (QNX) | main |
|
||||
| **ws2_32, iphlpapi, psapi, cfgmgr32, setupapi, hid** | (Windows) | main |
|
||||
|
||||
## Опциональные (тесты/документация)
|
||||
|
||||
| Инструмент | Назначение |
|
||||
|------------|------------|
|
||||
| **Google Test** | Тестирование (fetched automatically) |
|
||||
| **Doxygen** | Генерация документации |
|
||||
|
||||
## Стандартные системные библиотеки
|
||||
|
||||
- libm (math)
|
||||
- libc (C standard)
|
||||
|
||||
## Схема зависимостей модулей
|
||||
|
||||
```
|
||||
main (core)
|
||||
├── PCRE2 (встроен)
|
||||
├── BLAKE2 (встроен)
|
||||
├── SipHash (встроен)
|
||||
├── pthread (система)
|
||||
├── libdl (система)
|
||||
├── librt (система)
|
||||
├── libutil (система)
|
||||
└── ICU (опционально)
|
||||
|
||||
console → main
|
||||
compress → zlib
|
||||
crypt → libsodium
|
||||
usb → libusb
|
||||
fftw → FFTW3
|
||||
opencl → OpenCL
|
||||
io_utils → [crypt, если доступен]
|
||||
client_server → io_utils
|
||||
cloud → io_utils, crypt
|
||||
lua → Lua (встроен), LuaBridge (встроен)
|
||||
http_server → libmicrohttpd, [gnutls]
|
||||
http_client → libcurl
|
||||
```
|
||||
@@ -1321,14 +1321,16 @@ public:
|
||||
//! piCout << v; // {1, 3, 7, 5}
|
||||
//! \endcode
|
||||
//! \~\sa \a append(), \a prepend(), \a remove()
|
||||
inline PIVector<T> & insert(size_t index, const T & e = T()) {
|
||||
alloc(piv_size + 1);
|
||||
if (index < piv_size - 1) {
|
||||
const size_t os = piv_size - index - 1;
|
||||
memmove(reinterpret_cast<void *>(piv_data + index + 1), reinterpret_cast<const void *>(piv_data + index), os * sizeof(T));
|
||||
inline PIVector<T> & insert(size_t index, const T & e = T(), size_t count = 1) {
|
||||
alloc(piv_size + count);
|
||||
if (index < piv_size - count) {
|
||||
const size_t os = piv_size - index - count;
|
||||
memmove(reinterpret_cast<void *>(piv_data + index + count), reinterpret_cast<const void *>(piv_data + index), os * sizeof(T));
|
||||
}
|
||||
PIINTROSPECTION_CONTAINER_USED(T, count)
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
elementNew(piv_data + index + i, e);
|
||||
}
|
||||
PIINTROSPECTION_CONTAINER_USED(T, 1)
|
||||
elementNew(piv_data + index, e);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#ifndef PIVECTOR2D_H
|
||||
#define PIVECTOR2D_H
|
||||
|
||||
#include "pipair.h"
|
||||
#include "pivector.h"
|
||||
|
||||
//! \addtogroup Containers
|
||||
@@ -52,6 +51,20 @@
|
||||
template<typename T>
|
||||
class PIVector2D {
|
||||
public:
|
||||
//! \brief
|
||||
//! \~english Index structure for 2D array elements (row, column).
|
||||
//! \~russian Структура индекса для элементов двумерного массива (строка, столбец).
|
||||
struct Index {
|
||||
ssize_t row = -1;
|
||||
ssize_t col = -1;
|
||||
|
||||
inline Index() = default;
|
||||
inline Index(ssize_t r, ssize_t c): row(r), col(c) {}
|
||||
|
||||
inline bool isValid() const { return row >= 0 && col >= 0; }
|
||||
inline bool isNotValid() const { return !isValid(); }
|
||||
};
|
||||
|
||||
//! \~english Constructs an empty 2D array. No memory is allocated.
|
||||
//! \~russian Создаёт пустой двумерный массив. Память не выделяется.
|
||||
//! \details
|
||||
@@ -180,432 +193,11 @@ public:
|
||||
//! \sa isEmpty(), PIVector::isNotEmpty()
|
||||
inline bool isNotEmpty() const { return mat.isNotEmpty(); }
|
||||
|
||||
class RowConst;
|
||||
class ColConst;
|
||||
class Row;
|
||||
class Col;
|
||||
|
||||
//! \class Row
|
||||
//! \brief
|
||||
//! \~english Proxy class representing a single row in a \a PIVector2D for modification.
|
||||
//! \~russian Прокси-класс, представляющий одну строку в \a PIVector2D для модификации.
|
||||
//! \details
|
||||
//! \~english Objects of this class are returned by non-const \a operator[] or \a row().
|
||||
//! They provide array-like access to the elements of a specific row and allow operations such as assignment from another row or a \a
|
||||
//! PIVector, searching, filling, and iteration.
|
||||
//! \~russian Объекты этого класса возвращаются неконстантными операторами \a operator[] или методом \a row().
|
||||
//! Они предоставляют доступ к элементам конкретной строки, подобный массиву, и позволяют выполнять такие операции, как присваивание из
|
||||
//! другой строки или \a PIVector, поиск, заполнение и итерацию. \sa Col, RowConst
|
||||
class Row {
|
||||
friend class PIVector2D<T>;
|
||||
|
||||
private:
|
||||
inline Row(PIVector2D<T> * p, size_t row): p_(&(p->mat)) {
|
||||
st_ = p->cols_ * row;
|
||||
sz_ = p->cols_;
|
||||
}
|
||||
PIVector<T> * p_;
|
||||
size_t st_, sz_;
|
||||
|
||||
public:
|
||||
//! \~english Returns the number of columns in this row.
|
||||
//! \~russian Возвращает количество столбцов в этой строке.
|
||||
//! \return Row size (number of columns).
|
||||
//! \sa PIVector::size()
|
||||
inline size_t size() const { return sz_; }
|
||||
|
||||
//! \~english Accesses the element at the given column index within the row.
|
||||
//! \~russian Доступ к элементу по заданному индексу столбца в строке.
|
||||
//! \details
|
||||
//! \~english No bounds checking is performed in release builds; use with caution.
|
||||
//! \~russian В релизной сборке проверка границ не выполняется; используйте с осторожностью.
|
||||
//! \sa PIVector::operator[]
|
||||
inline T & operator[](size_t index) { return (*p_)[st_ + index]; }
|
||||
|
||||
//! \~english Const access to the element at the given column index within the row.
|
||||
//! \~russian Константный доступ к элементу по заданному индексу столбца в строке.
|
||||
//! \sa operator[] (non-const)
|
||||
inline const T & operator[](size_t index) const { return (*p_)[st_ + index]; }
|
||||
|
||||
//! \~english Returns a pointer to the row data starting at an optional offset.
|
||||
//! \~russian Возвращает указатель на данные строки, начиная с опционального смещения.
|
||||
//! \details
|
||||
//! \~english The pointer can be used for direct memory operations. It remains valid as long as the underlying 2D array is not
|
||||
//! reallocated.
|
||||
//! \~russian Указатель можно использовать для прямых операций с памятью. Он остаётся действительным, пока не произойдёт
|
||||
//! перераспределение памяти внутреннего двумерного массива. \sa PIVector::data()
|
||||
inline T * data(size_t index = 0) { return p_->data(st_ + index); }
|
||||
|
||||
//! \~english Returns a const pointer to the row data starting at an optional offset.
|
||||
//! \~russian Возвращает константный указатель на данные строки, начиная с опционального смещения.
|
||||
//! \sa data() (non-const)
|
||||
inline const T * data(size_t index = 0) const { return p_->data(st_ + index); }
|
||||
|
||||
//! \~english Assigns the contents of another Row to this row.
|
||||
//! \~russian Присваивает этой строке содержимое другой строки.
|
||||
//! \details
|
||||
//! \~english Only the minimum of the two row sizes is copied; if this row is shorter, excess elements in `other` are ignored.
|
||||
//! \~russian Копируется только минимум из размеров двух строк; если эта строка короче, лишние элементы из `other` игнорируются.
|
||||
//! \sa PIVector::operator=
|
||||
inline Row & operator=(const Row & other) {
|
||||
if (p_ == other.p_ && st_ == other.st_) return *this;
|
||||
const size_t sz = piMin<size_t>(sz_, other.sz_);
|
||||
p_->_copyRaw(p_->data(st_), other.data(), sz);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Assigns the contents of a \a PIVector to this row.
|
||||
//! \~russian Присваивает этой строке содержимое \a PIVector.
|
||||
//! \details
|
||||
//! \~english Only the minimum of the row size and vector size is copied.
|
||||
//! \~russian Копируется только минимум из размера строки и размера вектора.
|
||||
//! \sa PIVector::operator=
|
||||
inline Row & operator=(const PIVector<T> & other) {
|
||||
const size_t sz = piMin<size_t>(sz_, other.size());
|
||||
p_->_copyRaw(p_->data(st_), other.data(), sz);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Converts the row to a \a PIVector.
|
||||
//! \~russian Преобразует строку в \a PIVector.
|
||||
//! \sa PIVector::PIVector(const T*, size_t)
|
||||
inline PIVector<T> toVector() const { return PIVector<T>(p_->data(st_), sz_); }
|
||||
|
||||
//! \~english Returns the first index of element `e` in the row, starting from `start`.
|
||||
//! \~russian Возвращает первый индекс элемента `e` в строке, начиная с позиции `start`.
|
||||
//! \details
|
||||
//! \~english See \a PIVector::indexOf() for details on negative start handling.
|
||||
//! \~russian Подробнее об обработке отрицательного `start` см. \a PIVector::indexOf().
|
||||
//! \sa PIVector::indexOf()
|
||||
inline ssize_t indexOf(const T & e, ssize_t start = 0) const {
|
||||
if (start < 0) start = 0;
|
||||
for (size_t i = (size_t)start; i < sz_; ++i) {
|
||||
if ((*p_)[st_ + i] == e) return (ssize_t)i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//! \~english Returns the last index of element `e` in the row, searching backwards from `start`.
|
||||
//! \~russian Возвращает последний индекс элемента `e` в строке, выполняя поиск в обратном направлении от `start`.
|
||||
//! \sa PIVector::lastIndexOf()
|
||||
inline ssize_t lastIndexOf(const T & e, ssize_t start = -1) const {
|
||||
ssize_t from = (start < 0 || (size_t)start >= sz_) ? (ssize_t)sz_ - 1 : start;
|
||||
for (ssize_t i = from; i >= 0; --i) {
|
||||
if ((*p_)[st_ + i] == e) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//! \~english Returns the first index where the predicate `test` returns true, starting from `start`.
|
||||
//! \~russian Возвращает первый индекс, для которого предикат `test` возвращает true, начиная с `start`.
|
||||
//! \sa PIVector::indexWhere()
|
||||
inline ssize_t indexWhere(std::function<bool(const T & e)> test, ssize_t start = 0) const {
|
||||
if (start < 0) start = 0;
|
||||
for (size_t i = (size_t)start; i < sz_; ++i) {
|
||||
if (test((*p_)[st_ + i])) return (ssize_t)i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//! \~english Returns the last index where the predicate `test` returns true, searching backwards from `start`.
|
||||
//! \~russian Возвращает последний индекс, для которого предикат `test` возвращает true,
|
||||
//! выполняя поиск в обратном направлении от `start`.
|
||||
//! \sa PIVector::lastIndexWhere()
|
||||
inline ssize_t lastIndexWhere(std::function<bool(const T & e)> test, ssize_t start = -1) const {
|
||||
ssize_t from = (start < 0 || (size_t)start >= sz_) ? (ssize_t)sz_ - 1 : start;
|
||||
for (ssize_t i = from; i >= 0; --i) {
|
||||
if (test((*p_)[st_ + i])) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//! \~english Applies a function to each element of the row (modifiable).
|
||||
//! \~russian Применяет функцию к каждому элементу строки (с возможностью изменения).
|
||||
//! \param func Function that takes a reference to T.
|
||||
//! \details
|
||||
//! \~english The function can modify the elements.
|
||||
//! \~russian Функция может изменять элементы.
|
||||
//! \sa PIVector::forEach()
|
||||
inline void forEach(std::function<void(T &)> func) {
|
||||
for (size_t i = 0; i < sz_; ++i) {
|
||||
func((*p_)[st_ + i]);
|
||||
}
|
||||
}
|
||||
|
||||
//! \~english Applies a function to each element of the row (read-only).
|
||||
//! \~russian Применяет функцию к каждому элементу строки (только чтение).
|
||||
//! \details
|
||||
//! \~english The function can't modify the elements.
|
||||
//! \~russian Функция не может изменять элементы.
|
||||
//! \sa forEach (modifiable)
|
||||
inline void forEach(std::function<void(const T &)> func) const {
|
||||
for (size_t i = 0; i < sz_; ++i) {
|
||||
func((*p_)[st_ + i]);
|
||||
}
|
||||
}
|
||||
|
||||
//! \~english Fills the row with copies of `value`.
|
||||
//! \~russian Заполняет строку копиями `value`.
|
||||
//! \sa PIVector::fill()
|
||||
inline void fill(const T & value) {
|
||||
for (size_t i = 0; i < sz_; ++i) {
|
||||
(*p_)[st_ + i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
//! \~english Checks if the row contains the element `e`.
|
||||
//! \~russian Проверяет, содержит ли строка элемент `e`.
|
||||
//! \sa PIVector::contains()
|
||||
inline bool contains(const T & e, ssize_t start = 0) const { return indexOf(e, start) != -1; }
|
||||
|
||||
//! \~english Counts occurrences of `e` in the row.
|
||||
//! \~russian Подсчитывает количество вхождений `e` в строке.
|
||||
//! \sa PIVector::entries()
|
||||
inline int entries(const T & e, ssize_t start = 0) const {
|
||||
if (start < 0) start = 0;
|
||||
int count = 0;
|
||||
for (size_t i = (size_t)start; i < sz_; ++i) {
|
||||
if ((*p_)[st_ + i] == e) ++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
//! \~english Counts elements in the row that pass the `test`.
|
||||
//! \~russian Подсчитывает элементы в строке, проходящие `test`.
|
||||
//! \sa PIVector::entries(std::function)
|
||||
inline int entries(std::function<bool(const T & e)> test, ssize_t start = 0) const {
|
||||
if (start < 0) start = 0;
|
||||
int count = 0;
|
||||
for (size_t i = (size_t)start; i < sz_; ++i) {
|
||||
if (test((*p_)[st_ + i])) ++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
//! \~english Tests if any element in the row passes the `test`.
|
||||
//! \~russian Проверяет, проходит ли какой-либо элемент в строке `test`.
|
||||
//! \sa PIVector::any()
|
||||
inline bool any(std::function<bool(const T & e)> test) const {
|
||||
for (size_t i = 0; i < sz_; ++i) {
|
||||
if (test((*p_)[st_ + i])) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//! \~english Tests if all elements in the row pass the `test`.
|
||||
//! \~russian Проверяет, проходят ли все элементы в строке `test`.
|
||||
//! \sa PIVector::every()
|
||||
inline bool every(std::function<bool(const T & e)> test) const {
|
||||
for (size_t i = 0; i < sz_; ++i) {
|
||||
if (!test((*p_)[st_ + i])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
//! \class Col
|
||||
//! \brief
|
||||
//! \~english Proxy class representing a single column in a \a PIVector2D for modification.
|
||||
//! \~russian Прокси-класс, представляющий один столбец в \a PIVector2D для модификации.
|
||||
//! \details
|
||||
//! \~english Objects of this class are returned by non-const \a col(). They provide column-wise access and operations similar to \a
|
||||
//! Row.
|
||||
//! \~russian Объекты этого класса возвращаются неконстантным методом \a col(). Они предоставляют доступ к столбцам и операции,
|
||||
//! аналогичные \a Row. \sa Row, ColConst
|
||||
class Col {
|
||||
friend class PIVector2D<T>;
|
||||
|
||||
private:
|
||||
inline Col(PIVector2D<T> * p, size_t col): p_(&(p->mat)) {
|
||||
step_ = p->cols_;
|
||||
col_ = col;
|
||||
sz_ = p->rows_;
|
||||
}
|
||||
PIVector<T> * p_;
|
||||
size_t step_, col_, sz_;
|
||||
|
||||
public:
|
||||
//! \~english Returns the size of the column (number of rows).
|
||||
//! \~russian Возвращает размер столбца (количество строк).
|
||||
inline size_t size() const { return sz_; }
|
||||
|
||||
//! \~english Accesses the element at the given row index within the column.
|
||||
//! \~russian Доступ к элементу по заданному индексу строки в столбце.
|
||||
//! \return Reference to the element.
|
||||
inline T & operator[](size_t index) { return (*p_)[index * step_ + col_]; }
|
||||
|
||||
//! \~english Const access to the element at the given row index within the column.
|
||||
//! \~russian Константный доступ к элементу по заданному индексу строки в столбце.
|
||||
inline const T & operator[](size_t index) const { return (*p_)[index * step_ + col_]; }
|
||||
|
||||
//! \~english Returns a pointer to the column data starting at an optional row offset.
|
||||
//! \~russian Возвращает указатель на данные столбца, начиная с опционального смещения по строкам.
|
||||
//! \details
|
||||
//! \~english Note that column elements are not stored contiguously in memory, so this pointer cannot be used to iterate over the
|
||||
//! whole column.
|
||||
//! \~russian Обратите внимание, что элементы столбца не хранятся в памяти непрерывно, поэтому этот указатель нельзя использовать
|
||||
//! для итерации по всему столбцу.
|
||||
inline T * data(size_t index = 0) { return p_->data(index * step_ + col_); }
|
||||
|
||||
//! \~english Returns a const pointer to the column data starting at an optional row offset.
|
||||
//! \~russian Возвращает константный указатель на данные столбца, начиная с опционального смещения по строкам.
|
||||
inline const T * data(size_t index = 0) const { return p_->data(index * step_ + col_); }
|
||||
|
||||
//! \~english Assigns the contents of another Col to this column.
|
||||
//! \~russian Присваивает этому столбцу содержимое другого столбца.
|
||||
inline Col & operator=(const Col & other) {
|
||||
if (p_ == other.p_ && col_ == other.col_) return *this;
|
||||
const size_t sz = piMin<size_t>(sz_, other.sz_);
|
||||
for (size_t i = 0; i < sz; ++i)
|
||||
(*p_)[i * step_ + col_] = other[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Assigns the contents of a \a PIVector to this column.
|
||||
//! \~russian Присваивает этому столбцу содержимое \a PIVector.
|
||||
inline Col & operator=(const PIVector<T> & other) {
|
||||
const size_t sz = piMin<size_t>(sz_, other.size());
|
||||
for (size_t i = 0; i < sz; ++i)
|
||||
(*p_)[i * step_ + col_] = other[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Converts the column to a \a PIVector.
|
||||
//! \~russian Преобразует столбец в \a PIVector.
|
||||
inline PIVector<T> toVector() const {
|
||||
PIVector<T> ret;
|
||||
ret.reserve(sz_);
|
||||
for (size_t i = 0; i < sz_; i++)
|
||||
ret << (*p_)[i * step_ + col_];
|
||||
return ret;
|
||||
}
|
||||
|
||||
//! \~english Returns the first index of element `e` in the row, starting from `start`.
|
||||
//! \~russian Возвращает первый индекс элемента `e` в строке, начиная с позиции `start`.
|
||||
//! \details
|
||||
//! \~english See \a PIVector::indexOf() for details on negative start handling.
|
||||
//! \~russian Подробнее об обработке отрицательного `start` см. \a PIVector::indexOf().
|
||||
//! \sa PIVector::indexOf()
|
||||
inline ssize_t indexOf(const T & e, ssize_t start = 0) const {
|
||||
if (start < 0) start = 0;
|
||||
for (size_t i = (size_t)start; i < sz_; ++i) {
|
||||
if ((*p_)[i * step_ + col_] == e) return (ssize_t)i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//! \~english Returns the last index of element `e` in the row, searching backwards from `start`.
|
||||
//! \~russian Возвращает последний индекс элемента `e` в строке, выполняя поиск в обратном направлении от `start`.
|
||||
//! \sa PIVector::lastIndexOf()
|
||||
inline ssize_t lastIndexOf(const T & e, ssize_t start = -1) const {
|
||||
ssize_t from = (start < 0 || (size_t)start >= sz_) ? (ssize_t)sz_ - 1 : start;
|
||||
for (ssize_t i = from; i >= 0; --i) {
|
||||
if ((*p_)[i * step_ + col_] == e) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//! \~english Returns the first index where the predicate `test` returns true, starting from `start`.
|
||||
//! \~russian Возвращает первый индекс, для которого предикат `test` возвращает true, начиная с `start`.
|
||||
//! \sa PIVector::indexWhere()
|
||||
inline ssize_t indexWhere(std::function<bool(const T & e)> test, ssize_t start = 0) const {
|
||||
if (start < 0) start = 0;
|
||||
for (size_t i = (size_t)start; i < sz_; ++i) {
|
||||
if (test((*p_)[i * step_ + col_])) return (ssize_t)i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//! \~english Returns the last index where the predicate `test` returns true, searching backwards from `start`.
|
||||
//! \~russian Возвращает последний индекс, для которого предикат `test` возвращает true,
|
||||
//! выполняя поиск в обратном направлении от `start`.
|
||||
//! \sa PIVector::lastIndexWhere()
|
||||
inline ssize_t lastIndexWhere(std::function<bool(const T & e)> test, ssize_t start = -1) const {
|
||||
ssize_t from = (start < 0 || (size_t)start >= sz_) ? (ssize_t)sz_ - 1 : start;
|
||||
for (ssize_t i = from; i >= 0; --i) {
|
||||
if (test((*p_)[i * step_ + col_])) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//! \~english Applies a function to each element of the column (modifiable).
|
||||
//! \~russian Применяет функцию к каждому элементу столбца (с возможностью изменения).
|
||||
//! \details
|
||||
//! \~english The function can modify the elements.
|
||||
//! \~russian Функция может изменять элементы.
|
||||
//! \sa PIVector::forEach()
|
||||
inline void forEach(std::function<void(T &)> func) {
|
||||
for (size_t i = 0; i < sz_; ++i) {
|
||||
func((*p_)[i * step_ + col_]);
|
||||
}
|
||||
}
|
||||
|
||||
//! \~english Applies a function to each element of the column (read-only).
|
||||
//! \~russian Применяет функцию к каждому элементу столбца (только чтение).
|
||||
//! \details
|
||||
//! \~english The function can't modify the elements.
|
||||
//! \~russian Функция не может изменять элементы.
|
||||
//! \sa forEach (modifiable)
|
||||
inline void forEach(std::function<void(const T &)> func) const {
|
||||
for (size_t i = 0; i < sz_; ++i) {
|
||||
func((*p_)[i * step_ + col_]);
|
||||
}
|
||||
}
|
||||
|
||||
//! \~english Fills the column with copies of `value`.
|
||||
//! \~russian Заполняет столбец копиями `value`.
|
||||
//! \sa PIVector::fill()
|
||||
inline void fill(const T & value) {
|
||||
for (size_t i = 0; i < sz_; ++i) {
|
||||
(*p_)[i * step_ + col_] = value;
|
||||
}
|
||||
}
|
||||
|
||||
//! \~english Checks if the column contains the element `e`.
|
||||
//! \~russian Проверяет, содержит ли столбец элемент `e`.
|
||||
//! \sa PIVector::contains()
|
||||
inline bool contains(const T & e, ssize_t start = 0) const { return indexOf(e, start) != -1; }
|
||||
|
||||
//! \~english Counts occurrences of `e` in the column.
|
||||
//! \~russian Подсчитывает количество вхождений `e` в столбце.
|
||||
//! \sa PIVector::entries()
|
||||
inline int entries(const T & e, ssize_t start = 0) const {
|
||||
if (start < 0) start = 0;
|
||||
int count = 0;
|
||||
for (size_t i = (size_t)start; i < sz_; ++i) {
|
||||
if ((*p_)[i * step_ + col_] == e) ++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
//! \~english Counts elements in the column that pass the `test`.
|
||||
//! \~russian Подсчитывает элементы в столбце, проходящие `test`.
|
||||
//! \sa PIVector::entries(std::function)
|
||||
inline int entries(std::function<bool(const T & e)> test, ssize_t start = 0) const {
|
||||
if (start < 0) start = 0;
|
||||
int count = 0;
|
||||
for (size_t i = (size_t)start; i < sz_; ++i) {
|
||||
if (test((*p_)[i * step_ + col_])) ++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
//! \~english Tests if any element in the column passes the `test`.
|
||||
//! \~russian Проверяет, проходит ли какой-либо элемент в столбце `test`.
|
||||
//! \sa PIVector::any()
|
||||
inline bool any(std::function<bool(const T & e)> test) const {
|
||||
for (size_t i = 0; i < sz_; ++i) {
|
||||
if (test((*p_)[i * step_ + col_])) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//! \~english Tests if all elements in the column pass the `test`.
|
||||
//! \~russian Проверяет, проходят ли все элементы в столбце `test`.
|
||||
//! \sa PIVector::every()
|
||||
inline bool every(std::function<bool(const T & e)> test) const {
|
||||
for (size_t i = 0; i < sz_; ++i) {
|
||||
if (!test((*p_)[i * step_ + col_])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
//! \class RowConst
|
||||
//! \brief
|
||||
@@ -618,19 +210,13 @@ public:
|
||||
class RowConst {
|
||||
friend class PIVector2D<T>;
|
||||
|
||||
private:
|
||||
inline RowConst(const PIVector2D<T> * p, size_t row): p_(&(p->mat)) {
|
||||
st_ = p->cols_ * row;
|
||||
sz_ = p->cols_;
|
||||
}
|
||||
protected:
|
||||
inline RowConst(const PIVector2D<T> * p, size_t row): p_(&(p->mat)), st_(p->cols_ * row), sz_(p->cols_) {}
|
||||
const PIVector<T> * p_;
|
||||
size_t st_, sz_;
|
||||
const size_t st_, sz_;
|
||||
|
||||
public:
|
||||
inline RowConst(const PIVector2D<T>::Row & r): p_(r.p_) {
|
||||
st_ = r.st_;
|
||||
sz_ = r.sz_;
|
||||
}
|
||||
inline RowConst(const PIVector2D<T>::Row & r): p_(r.p_), st_(r.st_), sz_(r.sz_) {}
|
||||
|
||||
//! \~english Size of the row (number of columns).
|
||||
//! \~russian Размер строки (количество столбцов).
|
||||
@@ -759,6 +345,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//! \class ColConst
|
||||
//! \brief
|
||||
//! \~english Proxy class representing a single read-only column in a \a PIVector2D.
|
||||
@@ -770,21 +357,13 @@ public:
|
||||
class ColConst {
|
||||
friend class PIVector2D<T>;
|
||||
|
||||
private:
|
||||
inline ColConst(const PIVector2D<T> * p, size_t col): p_(&(p->mat)) {
|
||||
step_ = p->cols_;
|
||||
col_ = col;
|
||||
sz_ = p->rows_;
|
||||
}
|
||||
protected:
|
||||
inline ColConst(const PIVector2D<T> * p, size_t col): p_(&(p->mat)), step_(p->cols_), col_(col), sz_(p->rows_) {}
|
||||
const PIVector<T> * p_;
|
||||
size_t step_, col_, sz_;
|
||||
const size_t step_, col_, sz_;
|
||||
|
||||
public:
|
||||
inline ColConst(const PIVector2D<T>::Col & c): p_(c.p_) {
|
||||
step_ = c.step_;
|
||||
col_ = c.col_;
|
||||
sz_ = c.sz_;
|
||||
}
|
||||
inline ColConst(const PIVector2D<T>::Col & c): p_(c.p_), step_(c.step_), col_(c.col_), sz_(c.sz_) {}
|
||||
|
||||
//! \~english Size of the column (number of rows).
|
||||
//! \~russian Размер столбца (количество строк).
|
||||
@@ -918,6 +497,172 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
//! \class Row
|
||||
//! \brief
|
||||
//! \~english Proxy class representing a single row in a \a PIVector2D for modification.
|
||||
//! \~russian Прокси-класс, представляющий одну строку в \a PIVector2D для модификации.
|
||||
//! \details
|
||||
//! \~english Objects of this class are returned by non-const \a operator[] or \a row().
|
||||
//! They provide array-like access to the elements of a specific row and allow operations such as assignment from another row or a \a
|
||||
//! PIVector, searching, filling, and iteration.
|
||||
//! \~russian Объекты этого класса возвращаются неконстантными операторами \a operator[] или методом \a row().
|
||||
//! Они предоставляют доступ к элементам конкретной строки, подобный массиву, и позволяют выполнять такие операции, как присваивание из
|
||||
//! другой строки или \a PIVector, поиск, заполнение и итерацию. \sa Col, RowConst
|
||||
class Row: public RowConst {
|
||||
friend class PIVector2D<T>;
|
||||
|
||||
private:
|
||||
inline Row(PIVector2D<T> * p, size_t row): RowConst(p, row), p_(&(p->mat)) {}
|
||||
PIVector<T> * p_;
|
||||
|
||||
public:
|
||||
using RowConst::operator[];
|
||||
using RowConst::data;
|
||||
using RowConst::size;
|
||||
|
||||
//! \~english Accesses the element at the given column index within the row.
|
||||
//! \~russian Доступ к элементу по заданному индексу столбца в строке.
|
||||
//! \details
|
||||
//! \~english No bounds checking is performed; use with caution.
|
||||
//! \~russian Проверка границ не выполняется; используйте с осторожностью.
|
||||
//! \sa PIVector::operator[]
|
||||
inline T & operator[](size_t index) { return (*p_)[this->st_ + index]; }
|
||||
|
||||
//! \~english Returns a pointer to the row data starting at an optional offset.
|
||||
//! \~russian Возвращает указатель на данные строки, начиная с опционального смещения.
|
||||
//! \details
|
||||
//! \~english The pointer can be used for direct memory operations. It remains valid as long as the underlying 2D array is not
|
||||
//! reallocated.
|
||||
//! \~russian Указатель можно использовать для прямых операций с памятью. Он остаётся действительным, пока не произойдёт
|
||||
//! перераспределение памяти внутреннего двумерного массива. \sa PIVector::data()
|
||||
inline T * data(size_t index = 0) { return p_->data(this->st_ + index); }
|
||||
|
||||
//! \~english Assigns the contents of another Row to this row.
|
||||
//! \~russian Присваивает этой строке содержимое другой строки.
|
||||
//! \details
|
||||
//! \~english Only the minimum of the two row sizes is copied; if this row is shorter, excess elements in `other` are ignored.
|
||||
//! \~russian Копируется только минимум из размеров двух строк; если эта строка короче, лишние элементы из `other` игнорируются.
|
||||
//! \sa PIVector::operator=
|
||||
inline Row & operator=(const Row & other) {
|
||||
if (p_ == other.p_ && this->st_ == other.st_) return *this;
|
||||
const size_t sz = piMin<size_t>(this->sz_, other.sz_);
|
||||
p_->_copyRaw(p_->data(this->st_), other.data(), sz);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Assigns the contents of a \a PIVector to this row.
|
||||
//! \~russian Присваивает этой строке содержимое \a PIVector.
|
||||
//! \details
|
||||
//! \~english Only the minimum of the row size and vector size is copied.
|
||||
//! \~russian Копируется только минимум из размера строки и размера вектора.
|
||||
//! \sa PIVector::operator=
|
||||
inline Row & operator=(const PIVector<T> & other) {
|
||||
const size_t sz = piMin<size_t>(this->sz_, other.size());
|
||||
p_->_copyRaw(p_->data(this->st_), other.data(), sz);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Applies a function to each element of the row (modifiable).
|
||||
//! \~russian Применяет функцию к каждому элементу строки (с возможностью изменения).
|
||||
//! \param func Function that takes a reference to T.
|
||||
//! \details
|
||||
//! \~english The function can modify the elements.
|
||||
//! \~russian Функция может изменять элементы.
|
||||
//! \sa PIVector::forEach()
|
||||
inline void forEach(std::function<void(T &)> func) {
|
||||
for (size_t i = 0; i < this->sz_; ++i) {
|
||||
func((*p_)[this->st_ + i]);
|
||||
}
|
||||
}
|
||||
|
||||
//! \~english Fills the row with copies of `value`.
|
||||
//! \~russian Заполняет строку копиями `value`.
|
||||
//! \sa PIVector::fill()
|
||||
inline void fill(const T & value) {
|
||||
for (size_t i = 0; i < this->sz_; ++i) {
|
||||
(*p_)[this->st_ + i] = value;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//! \class Col
|
||||
//! \brief
|
||||
//! \~english Proxy class representing a single column in a \a PIVector2D for modification.
|
||||
//! \~russian Прокси-класс, представляющий один столбец в \a PIVector2D для модификации.
|
||||
//! \details
|
||||
//! \~english Objects of this class are returned by non-const \a col(). They provide column-wise access and operations similar to \a
|
||||
//! Row.
|
||||
//! \~russian Объекты этого класса возвращаются неконстантным методом \a col(). Они предоставляют доступ к столбцам и операции,
|
||||
//! аналогичные \a Row. \sa Row, ColConst
|
||||
class Col: public ColConst {
|
||||
friend class PIVector2D<T>;
|
||||
|
||||
private:
|
||||
inline Col(PIVector2D<T> * p, size_t col): ColConst(p, col), p_(&(p->mat)) {}
|
||||
PIVector<T> * p_;
|
||||
|
||||
public:
|
||||
using ColConst::operator[];
|
||||
using ColConst::data;
|
||||
using ColConst::size;
|
||||
|
||||
//! \~english Accesses the element at the given row index within the column.
|
||||
//! \~russian Доступ к элементу по заданному индексу строки в столбце.
|
||||
//! \return Reference to the element.
|
||||
inline T & operator[](size_t index) { return (*p_)[index * this->step_ + this->col_]; }
|
||||
|
||||
//! \~english Returns a pointer to the column data starting at an optional row offset.
|
||||
//! \~russian Возвращает указатель на данные столбца, начиная с опционального смещения по строкам.
|
||||
//! \details
|
||||
//! \~english Note that column elements are not stored contiguously in memory, so this pointer cannot be used to iterate over the
|
||||
//! whole column.
|
||||
//! \~russian Обратите внимание, что элементы столбца не хранятся в памяти непрерывно, поэтому этот указатель нельзя использовать
|
||||
//! для итерации по всему столбцу.
|
||||
inline T * data(size_t index = 0) { return p_->data(index * this->step_ + this->col_); }
|
||||
|
||||
//! \~english Assigns the contents of another Col to this column.
|
||||
//! \~russian Присваивает этому столбцу содержимое другого столбца.
|
||||
inline Col & operator=(const Col & other) {
|
||||
if (p_ == other.p_ && this->col_ == other.col_) return *this;
|
||||
const size_t sz = piMin<size_t>(this->sz_, other.sz_);
|
||||
for (size_t i = 0; i < sz; ++i)
|
||||
(*p_)[i * this->step_ + this->col_] = other[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Assigns the contents of a \a PIVector to this column.
|
||||
//! \~russian Присваивает этому столбцу содержимое \a PIVector.
|
||||
inline Col & operator=(const PIVector<T> & other) {
|
||||
const size_t sz = piMin<size_t>(this->sz_, other.size());
|
||||
for (size_t i = 0; i < sz; ++i)
|
||||
(*p_)[i * this->step_ + this->col_] = other[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Applies a function to each element of the column (modifiable).
|
||||
//! \~russian Применяет функцию к каждому элементу столбца (с возможностью изменения).
|
||||
//! \details
|
||||
//! \~english The function can modify the elements.
|
||||
//! \~russian Функция может изменять элементы.
|
||||
//! \sa PIVector::forEach()
|
||||
inline void forEach(std::function<void(T &)> func) {
|
||||
for (size_t i = 0; i < this->sz_; ++i) {
|
||||
func((*p_)[i * this->step_ + this->col_]);
|
||||
}
|
||||
}
|
||||
|
||||
//! \~english Fills the column with copies of `value`.
|
||||
//! \~russian Заполняет столбец копиями `value`.
|
||||
//! \sa PIVector::fill()
|
||||
inline void fill(const T & value) {
|
||||
for (size_t i = 0; i < this->sz_; ++i) {
|
||||
(*p_)[i * this->step_ + this->col_] = value;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//! \~english Returns a reference to the element at the given row and column.
|
||||
//! \~russian Возвращает ссылку на элемент по заданной строке и столбцу.
|
||||
//! \details
|
||||
@@ -930,10 +675,33 @@ public:
|
||||
//! \~russian Возвращает константную ссылку на элемент по заданной строке и столбцу.
|
||||
inline const T & element(size_t row, size_t col) const { return mat[row * cols_ + col]; }
|
||||
|
||||
//! \~english Returns a const reference to the element at the given row and column (bounds-checked only in debug).
|
||||
//! \~russian Возвращает константную ссылку на элемент по заданной строке и столбцу (проверка границ только в отладочном режиме).
|
||||
//! \~english Returns a const reference to the element at the given row and column
|
||||
//! \~russian Возвращает константную ссылку на элемент по заданной строке и столбцу
|
||||
//! \details
|
||||
//! \~english No bounds checking is performed.
|
||||
//! \~russian Проверка границ не выполняется.
|
||||
inline const T & at(size_t row, size_t col) const { return mat[row * cols_ + col]; }
|
||||
|
||||
//! \~english Returns a reference to the element at the given Index.
|
||||
//! \~russian Возвращает ссылку на элемент по заданному Index.
|
||||
inline T & operator[](const Index & idx) { return element(idx.row, idx.col); }
|
||||
|
||||
//! \~english Returns a const reference to the element at the given Index.
|
||||
//! \~russian Возвращает константную ссылку на элемент по заданному Index.
|
||||
inline const T & operator[](const Index & idx) const { return element(idx.row, idx.col); }
|
||||
|
||||
//! \~english Returns a reference to the element at the given Index.
|
||||
//! \~russian Возвращает ссылку на элемент по заданному Index.
|
||||
inline T & element(const Index & idx) { return element(idx.row, idx.col); }
|
||||
|
||||
//! \~english Returns a const reference to the element at the given Index.
|
||||
//! \~russian Возвращает константную ссылку на элемент по заданному Index.
|
||||
inline const T & element(const Index & idx) const { return element(idx.row, idx.col); }
|
||||
|
||||
//! \~english Returns a const reference to the element at the given Index (bounds-checked only in debug).
|
||||
//! \~russian Возвращает константную ссылку на элемент по заданному Index (проверка границ только в отладочном режиме).
|
||||
inline const T & at(const Index & idx) const { return at(idx.row, idx.col); }
|
||||
|
||||
//! \~english Returns a proxy object for the row at the given index for modification.
|
||||
//! \~russian Возвращает прокси-объект для строки по заданному индексу для модификации.
|
||||
//! \sa row(), Col
|
||||
@@ -1009,11 +777,60 @@ public:
|
||||
//! \~russian Добавляет новую строку в конец массива из \a PIVector.
|
||||
inline PIVector2D<T> & addRow(const PIVector<T> & other) {
|
||||
if (cols_ == 0) cols_ = other.size();
|
||||
const size_t sz = piMin<size_t>(cols_, other.size());
|
||||
const size_t ps = mat.size();
|
||||
mat.resize(mat.size() + cols_);
|
||||
mat._copyRaw(mat.data(ps), other.data(), sz);
|
||||
mat.append(other);
|
||||
rows_++;
|
||||
mat.resize(rows_ * cols_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PIVector2D<T> & appendRows(size_t count, const T & f = T()) {
|
||||
if (count == 0) return *this;
|
||||
if (cols_ == 0) ++cols_;
|
||||
mat.resize(mat.size() + count * cols_, f);
|
||||
rows_ += count;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PIVector2D<T> & appendColumns(size_t count, const T & f = T()) {
|
||||
if (count == 0) return *this;
|
||||
if (rows_ == 0) {
|
||||
mat.resize(count, f);
|
||||
rows_ = 1;
|
||||
cols_ = count;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const size_t newCols = cols_ + count;
|
||||
mat.reserve(rows_ * newCols);
|
||||
for (size_t r = rows_; r > 0; --r) {
|
||||
mat.insert(r * cols_, f, count);
|
||||
}
|
||||
|
||||
cols_ = newCols;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PIVector2D<T> & deleteRows(size_t row_start, size_t count) {
|
||||
if (row_start >= rows_ || count == 0) return *this;
|
||||
mat.remove(row_start * cols_, cols_ * count);
|
||||
if (isEmpty()) {
|
||||
cols_ = 0;
|
||||
rows_ = 0;
|
||||
} else {
|
||||
rows_ -= count;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PIVector2D<T> & deleteColumns(size_t col_start, size_t count) {
|
||||
if (col_start >= cols_ || rows_ == 0) return *this;
|
||||
count = piMin(count, cols_ - col_start);
|
||||
if (count == 0) return *this;
|
||||
for (size_t r = 0; r < rows_; ++r) {
|
||||
mat.remove(r * (cols_ - count) + col_start, count);
|
||||
}
|
||||
cols_ -= count;
|
||||
mat.resize(rows_ * cols_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -1021,32 +838,25 @@ public:
|
||||
//! \~russian Добавляет новую строку в конец массива из \a ColConst.
|
||||
inline PIVector2D<T> & addColumn(const ColConst & other) {
|
||||
if (other.size() == 0) return *this;
|
||||
if (size() == 0) {
|
||||
_resizeRaw(other.size(), 1);
|
||||
if (isEmpty()) {
|
||||
mat.reserve(other.size());
|
||||
for (size_t r = 0; r < other.size(); ++r) {
|
||||
element(r, 0) = other[r];
|
||||
mat.append(other[r]);
|
||||
}
|
||||
rows_ = mat.size();
|
||||
cols_ = 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const size_t oldCols = cols_;
|
||||
const size_t newCols = oldCols + 1;
|
||||
const size_t newSize = rows_ * newCols;
|
||||
|
||||
mat._resizeRaw(newSize);
|
||||
|
||||
for (size_t r = rows_ - 1; r > 0; --r) {
|
||||
T * src = mat.data(r * oldCols);
|
||||
T * dst = mat.data(r * newCols);
|
||||
memmove(dst, src, oldCols * sizeof(T));
|
||||
if (r < other.size()) {
|
||||
mat._copyRaw(&(dst[oldCols]), &(other[r]), 1);
|
||||
const size_t newCols = cols_ + 1;
|
||||
mat.reserve(rows_ * newCols);
|
||||
for (size_t r = rows_; r > 0; --r) {
|
||||
if (r - 1 < other.size()) {
|
||||
mat.insert(r * cols_, other[r - 1]);
|
||||
} else {
|
||||
const T tmp = T();
|
||||
mat._copyRaw(&(dst[oldCols]), &tmp, 1);
|
||||
mat.insert(r * cols_);
|
||||
}
|
||||
}
|
||||
mat._copyRaw(mat.data(oldCols), &(other[0]), 1);
|
||||
|
||||
cols_ = newCols;
|
||||
return *this;
|
||||
@@ -1056,32 +866,22 @@ public:
|
||||
//! \~russian Добавляет новую строку в конец массива из \a PIVector.
|
||||
inline PIVector2D<T> & addColumn(const PIVector<T> & other) {
|
||||
if (other.size() == 0) return *this;
|
||||
if (size() == 0) {
|
||||
_resizeRaw(other.size(), 1);
|
||||
for (size_t r = 0; r < other.size(); ++r) {
|
||||
element(r, 0) = other[r];
|
||||
}
|
||||
if (isEmpty()) {
|
||||
mat.append(other);
|
||||
rows_ = mat.size();
|
||||
cols_ = 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const size_t oldCols = cols_;
|
||||
const size_t newCols = oldCols + 1;
|
||||
const size_t newSize = rows_ * newCols;
|
||||
|
||||
mat._resizeRaw(newSize);
|
||||
|
||||
for (size_t r = rows_ - 1; r > 0; --r) {
|
||||
T * src = mat.data(r * oldCols);
|
||||
T * dst = mat.data(r * newCols);
|
||||
memmove(dst, src, oldCols * sizeof(T));
|
||||
if (r < other.size()) {
|
||||
mat._copyRaw(&(dst[oldCols]), &(other[r]), 1);
|
||||
const size_t newCols = cols_ + 1;
|
||||
mat.reserve(rows_ * newCols);
|
||||
for (size_t r = rows_; r > 0; --r) {
|
||||
if (r - 1 < other.size()) {
|
||||
mat.insert(r * cols_, other[r - 1]);
|
||||
} else {
|
||||
const T tmp = T();
|
||||
mat._copyRaw(&(dst[oldCols]), &tmp, 1);
|
||||
mat.insert(r * cols_);
|
||||
}
|
||||
}
|
||||
mat._copyRaw(mat.data(oldCols), &(other[0]), 1);
|
||||
|
||||
cols_ = newCols;
|
||||
return *this;
|
||||
@@ -1101,15 +901,29 @@ public:
|
||||
//! \sa PIVector::resize()
|
||||
inline PIVector2D<T> & resize(size_t rows, size_t cols, const T & f = T()) {
|
||||
if (rows == rows_ && cols == cols_) return *this;
|
||||
PIVector2D<T> tmp(rows, cols, f);
|
||||
size_t copyRows = piMin(rows_, rows);
|
||||
size_t copyCols = piMin(cols_, cols);
|
||||
for (size_t r = 0; r < copyRows; ++r) {
|
||||
for (size_t c = 0; c < copyCols; ++c) {
|
||||
tmp.element(r, c) = element(r, c);
|
||||
}
|
||||
if (rows_ == 0 || cols_ == 0) {
|
||||
mat.resize(rows * cols, f);
|
||||
rows_ = rows;
|
||||
cols_ = cols;
|
||||
return *this;
|
||||
}
|
||||
if (rows != rows_ && cols == cols_) {
|
||||
mat.resize(rows * cols_, f);
|
||||
rows_ = rows;
|
||||
return *this;
|
||||
}
|
||||
if (cols > cols_) {
|
||||
appendColumns(cols - cols_, f);
|
||||
}
|
||||
if (rows > rows_) {
|
||||
appendRows(rows - rows_, f);
|
||||
}
|
||||
if (cols < cols_) {
|
||||
deleteColumns(cols, cols_ - cols);
|
||||
}
|
||||
if (rows < rows_) {
|
||||
deleteRows(rows, rows_ - rows);
|
||||
}
|
||||
swap(tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -1203,37 +1017,37 @@ public:
|
||||
//! \~english Returns the first index (row, col) of `e` in the 2D array.
|
||||
//! \~russian Возвращает первый индекс (строка, столбец) элемента `e` в двумерном массиве.
|
||||
//! \sa PIVector::indexOf()
|
||||
inline PIPair<ssize_t, ssize_t> indexOf(const T & e) const {
|
||||
inline Index indexOf(const T & e) const {
|
||||
ssize_t flat = mat.indexOf(e);
|
||||
if (flat < 0 || cols_ == 0) return PIPair<ssize_t, ssize_t>(-1, -1);
|
||||
return PIPair<ssize_t, ssize_t>(flat / cols_, flat % cols_);
|
||||
if (flat < 0 || cols_ == 0) return Index{-1, -1};
|
||||
return Index{flat / static_cast<ssize_t>(cols_), flat % static_cast<ssize_t>(cols_)};
|
||||
}
|
||||
|
||||
//! \~english Returns the first index (row, col) in the 2D array that passes the `test`.
|
||||
//! \~russian Возвращает первый индекс (строка, столбец) в двумерном массиве, проходящий `test`.
|
||||
//! \sa PIVector::indexWhere()
|
||||
inline PIPair<ssize_t, ssize_t> indexWhere(std::function<bool(const T & e)> test, ssize_t start = 0) const {
|
||||
inline Index indexWhere(std::function<bool(const T & e)> test, ssize_t start = 0) const {
|
||||
ssize_t flat = mat.indexWhere(test, start);
|
||||
if (flat < 0 || cols_ == 0) return PIPair<ssize_t, ssize_t>(-1, -1);
|
||||
return PIPair<ssize_t, ssize_t>(flat / cols_, flat % cols_);
|
||||
if (flat < 0 || cols_ == 0) return Index{-1, -1};
|
||||
return Index{flat / static_cast<ssize_t>(cols_), flat % static_cast<ssize_t>(cols_)};
|
||||
}
|
||||
|
||||
//! \~english Returns the last index (row, col) of `e` in the 2D array.
|
||||
//! \~russian Возвращает последний индекс (строка, столбец) элемента `e` в двумерном массиве.
|
||||
//! \sa PIVector::lastIndexOf()
|
||||
inline PIPair<ssize_t, ssize_t> lastIndexOf(const T & e, ssize_t start = -1) const {
|
||||
inline Index lastIndexOf(const T & e, ssize_t start = -1) const {
|
||||
ssize_t flat = mat.lastIndexOf(e, start);
|
||||
if (flat < 0 || cols_ == 0) return PIPair<ssize_t, ssize_t>(-1, -1);
|
||||
return PIPair<ssize_t, ssize_t>(flat / cols_, flat % cols_);
|
||||
if (flat < 0 || cols_ == 0) return Index{-1, -1};
|
||||
return Index{flat / static_cast<ssize_t>(cols_), flat % static_cast<ssize_t>(cols_)};
|
||||
}
|
||||
|
||||
//! \~english Returns the last index (row, col) in the 2D array that passes the `test`.
|
||||
//! \~russian Возвращает последний индекс (строка, столбец) в двумерном массиве, проходящий `test`.
|
||||
//! \sa PIVector::lastIndexWhere()
|
||||
inline PIPair<ssize_t, ssize_t> lastIndexWhere(std::function<bool(const T & e)> test, ssize_t start = -1) const {
|
||||
inline Index lastIndexWhere(std::function<bool(const T & e)> test, ssize_t start = -1) const {
|
||||
ssize_t flat = mat.lastIndexWhere(test, start);
|
||||
if (flat < 0 || cols_ == 0) return PIPair<ssize_t, ssize_t>(-1, -1);
|
||||
return PIPair<ssize_t, ssize_t>(flat / cols_, flat % cols_);
|
||||
if (flat < 0 || cols_ == 0) return Index{-1, -1};
|
||||
return Index{flat / static_cast<ssize_t>(cols_), flat % static_cast<ssize_t>(cols_)};
|
||||
}
|
||||
|
||||
|
||||
@@ -1335,8 +1149,8 @@ public:
|
||||
//! \sa PIVector::getRange()
|
||||
inline PIVector2D<T> getRange(size_t rowStart, size_t rowCount, size_t colStart, size_t colCount) const {
|
||||
if (rowStart >= rows_ || colStart >= cols_ || rowCount == 0 || colCount == 0) return PIVector2D<T>();
|
||||
size_t actualRowCount = piMin<size_t>(rowCount, rows_ - rowStart);
|
||||
size_t actualColCount = piMin<size_t>(colCount, cols_ - colStart);
|
||||
const size_t actualRowCount = piMin<size_t>(rowCount, rows_ - rowStart);
|
||||
const size_t actualColCount = piMin<size_t>(colCount, cols_ - colStart);
|
||||
|
||||
PIVector2D<T> result(actualRowCount, actualColCount);
|
||||
for (size_t r = 0; r < actualRowCount; ++r) {
|
||||
@@ -1430,18 +1244,10 @@ public:
|
||||
//! \~english Removes a row from the 2D array.
|
||||
//! \~russian Удаляет строку из двумерного массива.
|
||||
//! \details
|
||||
//! \~english The elements of the specified row are destroyed, and all subsequent rows are shifted up.
|
||||
//! If the last row is removed and the array becomes empty, \a cols() is set to 0.
|
||||
//! \~russian Элементы указанной строки уничтожаются, а все последующие строки сдвигаются вверх.
|
||||
//! Если удаляется последняя строка и массив становится пустым, \a cols() устанавливается в 0.
|
||||
//! \~english If the last row is removed and the array becomes empty, \a cols() is set to 0.
|
||||
//! \~russian Если удаляется последняя строка и массив становится пустым, \a cols() устанавливается в 0.
|
||||
//! \sa removeColumn(), PIVector::remove()
|
||||
inline PIVector2D<T> & removeRow(size_t row) {
|
||||
if (row >= rows_) return *this;
|
||||
mat.remove(row * cols_, cols_);
|
||||
rows_--;
|
||||
if (rows_ == 0) cols_ = 0;
|
||||
return *this;
|
||||
}
|
||||
inline PIVector2D<T> & removeRow(size_t row) { return deleteRows(row, 1); }
|
||||
|
||||
//! \~english Removes a column from the 2D array.
|
||||
//! \~russian Удаляет столбец из двумерного массива.
|
||||
@@ -1449,18 +1255,7 @@ public:
|
||||
//! \~english This operation is more expensive than removing a row because elements must be moved.
|
||||
//! \~russian Эта операция дороже, чем удаление строки, поскольку требуется перемещение элементов.
|
||||
//! \sa removeRow(), PIVector::remove()
|
||||
inline PIVector2D<T> & removeColumn(size_t col) {
|
||||
if (col >= cols_ || rows_ == 0) return *this;
|
||||
PIVector2D<T> result(rows_, cols_ - 1);
|
||||
for (size_t r = 0; r < rows_; ++r) {
|
||||
for (size_t c = 0, nc = 0; c < cols_; ++c) {
|
||||
if (c == col) continue;
|
||||
result.element(r, nc++) = element(r, c);
|
||||
}
|
||||
}
|
||||
swap(result);
|
||||
return *this;
|
||||
}
|
||||
inline PIVector2D<T> & removeColumn(size_t col) { return deleteColumns(col, 1); }
|
||||
|
||||
//! \~english Removes all rows that satisfy a condition.
|
||||
//! \~russian Удаляет все строки, удовлетворяющие условию.
|
||||
@@ -1517,10 +1312,13 @@ public:
|
||||
goodCols << c;
|
||||
}
|
||||
}
|
||||
PIVector2D<T> result(rows_, goodCols.size());
|
||||
PIVector2D<T> result;
|
||||
result._resizeRaw(rows_, goodCols.size());
|
||||
for (size_t r = 0; r < rows_; ++r) {
|
||||
const size_t start_dst = r * result.cols_;
|
||||
const size_t start_src = r * cols_;
|
||||
for (size_t gc = 0; gc < goodCols.size(); ++gc) {
|
||||
result.element(r, gc) = element(r, goodCols[gc]);
|
||||
result.mat._copyRaw(result.mat.data(start_dst + gc), mat.data(start_src + goodCols[gc]), 1);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
59
options.md
Normal file
59
options.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# PIP Build Options
|
||||
|
||||
## Основные опции сборки
|
||||
|
||||
### Стандартные опции (option())
|
||||
| Опция | Описание | По умолчанию |
|
||||
|-------|----------|--------------|
|
||||
| `ICU` | ICU support для конвертации кодовых страниц | ON (кроме Win/Android/Apple) |
|
||||
| `STD_IOSTREAM` | Поддержка std::iostream операторов | OFF |
|
||||
| `INTROSPECTION` | Сборка с интроспекцией | OFF |
|
||||
| `TESTS` | Сборка тестов | OFF |
|
||||
| `COVERAGE` | Сборка с информацией о покрытии | OFF |
|
||||
| `PIP_FFTW_F` | Поддержка FFTW для float | ON |
|
||||
| `PIP_FFTW_L` | Поддержка FFTW для long double | ON |
|
||||
| `PIP_FFTW_Q` | Поддержка FFTW для quad double | OFF |
|
||||
|
||||
### Опции модулей (PIP_BUILD_*)
|
||||
| Опция | Модуль |
|
||||
|-------|--------|
|
||||
| `PIP_BUILD_CONSOLE` | console |
|
||||
| `PIP_BUILD_CRYPT` | crypt (требует libsodium) |
|
||||
| `PIP_BUILD_COMPRESS` | compress (требует zlib) |
|
||||
| `PIP_BUILD_USB` | usb |
|
||||
| `PIP_BUILD_FFTW` | fftw |
|
||||
| `PIP_BUILD_OPENCL` | opencl |
|
||||
| `PIP_BUILD_IO_UTILS` | io_utils |
|
||||
| `PIP_BUILD_CLIENT_SERVER` | client_server |
|
||||
| `PIP_BUILD_CLOUD` | cloud |
|
||||
| `PIP_BUILD_LUA` | lua |
|
||||
| `PIP_BUILD_HTTP_CLIENT` | http_client (требует libcurl) |
|
||||
| `PIP_BUILD_HTTP_SERVER` | http_server (требует libmicrohttpd) |
|
||||
|
||||
### Дополнительные переменные
|
||||
| Переменная | Описание |
|
||||
|------------|----------|
|
||||
| `PIP_BUILD_DEBUG` | Сборка debug версии |
|
||||
| `PIP_FREERTOS` | Поддержка FreeRTOS |
|
||||
| `CROSSTOOLS` | Режим кросс-компиляции |
|
||||
| `LOCAL` | Локальная установка (bin/lib/include) |
|
||||
| `PIP_CONTAINERS_MIN_ALLOC` | Переопределить минимальный размер аллокации контейнеров |
|
||||
| `PIP_CONTAINERS_MAX_POT_ALLOC` | Переопределить максимальный размер (поддерживает X_KiB, X_MiB) |
|
||||
|
||||
### Примеры использования
|
||||
```bash
|
||||
# Базовая сборка с тестами
|
||||
cmake -B build -DTESTS=ON
|
||||
|
||||
# Сборка с покрытием и ICU
|
||||
cmake -B build -DTESTS=ON -DCOVERAGE=ON -DICU=ON
|
||||
|
||||
# Отключение отдельных модулей
|
||||
cmake -B build -DPIP_BUILD_CRYPT=OFF -DPIP_BUILD_OPENCL=OFF
|
||||
|
||||
# Переопределение параметров контейнеров
|
||||
cmake -B build -DPIP_CONTAINERS_MIN_ALLOC=64
|
||||
|
||||
# Локальная установка
|
||||
cmake -B build -DLOCAL=ON
|
||||
```
|
||||
337
plans/doxygen_docs.md
Normal file
337
plans/doxygen_docs.md
Normal file
@@ -0,0 +1,337 @@
|
||||
# План: Добавление документации Doxygen в заголовочные файлы PIP
|
||||
|
||||
## Обзор
|
||||
|
||||
Необходимо добавить базовую документацию Doxygen (`\brief`) во все публичные заголовочные файлы проекта. Каждый файл должен содержать:
|
||||
- Документацию в начале файла (`\file`, `\brief`, группа)
|
||||
- Документацию для каждого класса (`\class`, `\brief`)
|
||||
- Документацию для всех публичных методов (`\brief`)
|
||||
|
||||
## Стиль документации
|
||||
|
||||
Используется два стиля комментариев (оба поддерживаются):
|
||||
1. `//!` - однострочные комментарии (предпочтительно)
|
||||
2. `/*! ... */` - многострочные блоки
|
||||
|
||||
## Пример оформления (на основе pipair.h)
|
||||
|
||||
```cpp
|
||||
//! \addtogroup Containers
|
||||
//! \{
|
||||
//! \file pipair.h
|
||||
//! \brief
|
||||
//! \~english Declares \a PIPair
|
||||
//! \~russian Объявление \a PIPair
|
||||
//! \~\authors
|
||||
//! \~english Ivan Pelipenko peri4ko@yandex.ru; Andrey Bychkov work.a.b@yandex.ru
|
||||
//! \~russian Иван Пелипенко peri4ko@yandex.ru; Андрей Бычков work.a.b@yandex.ru
|
||||
//! \~\}
|
||||
/*
|
||||
Лицензия GPL
|
||||
*/
|
||||
|
||||
#ifndef PIPAIR_H
|
||||
#define PIPAIR_H
|
||||
|
||||
#include "picout.h"
|
||||
|
||||
//! \addtogroup Containers
|
||||
//! \{
|
||||
//! \class PIPair
|
||||
//! \brief
|
||||
//! \~english Class template that provides a way to store two heterogeneous objects as a single unit.
|
||||
//! \~russian Класс, который позволяет хранить два разнородных объекта как единое целое.
|
||||
//! \~\}
|
||||
//! \~\sa \a PIMap
|
||||
template<typename Type0, typename Type1>
|
||||
class PIPair {
|
||||
public:
|
||||
//! \~english Constructs an empty PIPair.
|
||||
//! \~russian Создает пустой PIPair.
|
||||
PIPair(): first(), second() {}
|
||||
|
||||
//! \~english Constructs PIPair from values `value0` and `value1`.
|
||||
//! \~russian Создает PIPair из `value0` и `value1`.
|
||||
PIPair(const Type0 & value0, const Type1 & value1) {
|
||||
first = value0;
|
||||
second = value1;
|
||||
}
|
||||
|
||||
//! \~english First element.
|
||||
//! \~russian Первый элемент.
|
||||
Type0 first;
|
||||
|
||||
//! \~english Second element.
|
||||
//! \~russian Второй элемент.
|
||||
Type1 second;
|
||||
};
|
||||
|
||||
//! \~english Compare operator with PIPair.
|
||||
//! \~russian Оператор сравнения с PIPair.
|
||||
template<typename Type0, typename Type1>
|
||||
inline bool operator==(const PIPair<Type0, Type1> & value0, const PIPair<Type0, Type1> & value1) {
|
||||
return (value0.first == value1.first) && (value0.second == value1.second);
|
||||
}
|
||||
|
||||
#endif // PIPAIR_H
|
||||
```
|
||||
|
||||
## Инструкции для агента (на один файл)
|
||||
|
||||
1. **Прочитать файл** и определить:
|
||||
- Группу модуля (Container, Types, Core, IO, Thread, Math и т.д.)
|
||||
- Все классы в файле
|
||||
- Все публичные методы каждого класса
|
||||
- Все свободные функции (non-member)
|
||||
|
||||
2. **Добавить документацию в начале файла** (если отсутствует):
|
||||
```cpp
|
||||
//! \addtogroup <GroupName>
|
||||
//! \{
|
||||
//! \file <filename>
|
||||
//! \brief
|
||||
//! \~english Brief description
|
||||
//! \~russian Краткое описание
|
||||
//! \~\}
|
||||
```
|
||||
|
||||
3. **Добавить документацию для каждого класса**:
|
||||
```cpp
|
||||
//! \class ClassName
|
||||
//! \brief
|
||||
//! \~english Class description
|
||||
//! \~russian Описание класса
|
||||
```
|
||||
|
||||
4. **Добавить документацию для методов**:
|
||||
```cpp
|
||||
//! \~english Method description.
|
||||
//! \~russian Описание метода.
|
||||
ReturnType methodName(params);
|
||||
```
|
||||
|
||||
5. **Проверить, что файл компилируется** после изменений
|
||||
|
||||
## Список файлов для обработки
|
||||
|
||||
### Containers (11 файлов)
|
||||
- libs/main/containers/picollections.h
|
||||
- libs/main/containers/picontainersmodule.h
|
||||
- libs/main/containers/pideque.h
|
||||
- libs/main/containers/pimap.h
|
||||
- libs/main/containers/pipair.h
|
||||
- libs/main/containers/piqueue.h
|
||||
- libs/main/containers/piset.h
|
||||
- libs/main/containers/pistack.h
|
||||
- libs/main/containers/pivector.h
|
||||
- libs/main/containers/pivector2d.h
|
||||
|
||||
### Core (11 файлов)
|
||||
- libs/main/core/pibase.h
|
||||
- libs/main/core/pibase_macros.h
|
||||
- libs/main/core/picoremodule.h
|
||||
- libs/main/core/picout.h
|
||||
- libs/main/core/piincludes.h
|
||||
- libs/main/core/piincludes_p.h
|
||||
- libs/main/core/piinit.h
|
||||
- libs/main/core/pimemoryblock.h
|
||||
- libs/main/core/piobject.h
|
||||
- libs/main/core/piobject_macros.h
|
||||
- libs/main/core/piwaitevent_p.h
|
||||
|
||||
### Types (17 файлов)
|
||||
- libs/main/types/pibitarray.h
|
||||
- libs/main/types/pibytearray.h
|
||||
- libs/main/types/pidatetime.h
|
||||
- libs/main/types/piflags.h
|
||||
- libs/main/types/pinetworkaddress.h
|
||||
- libs/main/types/pipropertystorage.h
|
||||
- libs/main/types/pisystemtime.h
|
||||
- libs/main/types/pitime.h
|
||||
- libs/main/types/pitypesmodule.h
|
||||
- libs/main/types/pivaluetree.h
|
||||
- libs/main/types/pivariant.h
|
||||
- libs/main/types/pivarianttypes.h
|
||||
- libs/main/types/pivariantsimple.h
|
||||
- libs/main/types/pinetworkaddress.h
|
||||
- libs/main/types/colors_p.h
|
||||
- libs/main/types/pipropertystorage.h
|
||||
|
||||
### Text (7 файлов)
|
||||
- libs/main/text/pichar.h
|
||||
- libs/main/text/piconstchars.h
|
||||
- libs/main/text/piregularexpression.h
|
||||
- libs/main/text/pistring.h
|
||||
- libs/main/text/pistringlist.h
|
||||
- libs/main/text/pitextmodule.h
|
||||
- libs/main/text/pitextstream.h
|
||||
|
||||
### IO Devices (20+ файлов)
|
||||
- libs/main/io_devices/pibinarylog.h
|
||||
- libs/main/io_devices/pican.h
|
||||
- libs/main/io_devices/piconfig.h
|
||||
- libs/main/io_devices/pidir.h
|
||||
- libs/main/io_devices/piethernet.h
|
||||
- libs/main/io_devices/pifile.h
|
||||
- libs/main/io_devices/pigpio.h
|
||||
- libs/main/io_devices/piiobytearray.h
|
||||
- libs/main/io_devices/piiodevice.h
|
||||
- libs/main/io_devices/piiodevicesmodule.h
|
||||
- libs/main/io_devices/piiostream.h
|
||||
- libs/main/io_devices/piiostring.h
|
||||
- libs/main/io_devicespipeer.h
|
||||
- libs/main/io_devices/piserial.h
|
||||
- libs/main/io_devices/pisharedmemory.h
|
||||
- libs/main/io_devices/pispi.h
|
||||
- libs/main/io_devices/pitransparentdevice.h
|
||||
- libs/main/io_devices/piusb.h
|
||||
|
||||
### Thread (18 файлов)
|
||||
- libs/main/thread/piblockingqueue.h
|
||||
- libs/main/thread/piconditionvar.h
|
||||
- libs/main/thread/pigrabberbase.h
|
||||
- libs/main/thread/pimutex.h
|
||||
- libs/main/thread/pipipelinethread.h
|
||||
- libs/main/thread/piprotectedvariable.h
|
||||
- libs/main/thread/pireadwritelock.h
|
||||
- libs/main/thread/pisemaphore.h
|
||||
- libs/main/thread/pispinlock.h
|
||||
- libs/main/thread/pithread.h
|
||||
- libs/main/thread/pithreadmodule.h
|
||||
- libs/main/thread/pithreadnotifier.h
|
||||
- libs/main/thread/pithreadpoolloop.h
|
||||
- libs/main/thread/pithreadpoolexecutor.h
|
||||
- libs/main/thread/pitimer.h
|
||||
|
||||
### Math (14 файлов)
|
||||
- libs/main/math/picrc.h
|
||||
- libs/main/math/pievaluator.h
|
||||
- libs/main/math/pifft.h
|
||||
- libs/main/math/pigeometry.h
|
||||
- libs/main/math/piline.h
|
||||
- libs/main/math/pimatcomplex.h
|
||||
- libs/main/math/pimatvector.h
|
||||
- libs/main/math/pimatmatrix.h
|
||||
- libs/main/math/pimathsolver.h
|
||||
- libs/main/math/pimathbase.h
|
||||
- libs/main/math/pimathmodule.h
|
||||
- libs/main/math/piquantaternion.h
|
||||
- libs/main/math/pirect.h
|
||||
- libs/main/math/pistatistic.h
|
||||
|
||||
### Crypt (3 файла)
|
||||
- libs/main/crypt/piauth.h
|
||||
- libs/main/crypt/picrypt.h
|
||||
- libs/main/crypt/picryptmodule.h
|
||||
|
||||
### Digest (1 файл)
|
||||
- libs/main/digest/pidigest.h
|
||||
|
||||
### Serialization (7 файлов)
|
||||
- libs/main/serialization/pibinarystream.h
|
||||
- libs/main/serialization/pichunkstream.h
|
||||
- libs/main/serialization/pijson.h
|
||||
- libs/main/serialization/pijsonserialization.h
|
||||
- libs/main/serialization/piserializationmodule.h
|
||||
- libs/main/serialization/pivaluetree_conversions.h
|
||||
- libs/main/serialization/pijson.h
|
||||
|
||||
### HTTP (6 файлов)
|
||||
- libs/main/http_client/pihttpclient.h
|
||||
- libs/main/http_client/pihttpclientmodule.h
|
||||
- libs/main/http_server/pihttpserver.h
|
||||
- libs/main/http_server/pihttpservermodule.h
|
||||
- libs/main/http_server/microhttpd_server.h
|
||||
- libs/main/http_common/pihttptypes.h
|
||||
|
||||
### State Machine (4 файла)
|
||||
- libs/main/state_machine/pistatemachinebase.h
|
||||
- libs/main/state_machine/pistatemachinestate.h
|
||||
- libs/main/state_machine/pistatemachinetransition.h
|
||||
- libs/main/state_machine/pistatemachinemodule.h
|
||||
|
||||
### System (11 файлов)
|
||||
- libs/main/system/pihidevice.h
|
||||
- libs/main/system/pilibrary.h
|
||||
- libs/main/system/piprocess.h
|
||||
- libs/main/system/piplugin.h
|
||||
- libs/main/system/pisignals.h
|
||||
- libs/main/system/pisysteminfo.h
|
||||
- libs/main/system/pisystemmodule.h
|
||||
- libs/main/system/pisystemtests.h
|
||||
|
||||
### Cloud (5 файлов)
|
||||
- libs/main/cloud/picloudbase.h
|
||||
- libs/main/cloud/picloudclient.h
|
||||
- libs/main/cloud/picloudmodule.h
|
||||
- libs/main/cloud/picloudserver.h
|
||||
- libs/main/cloud/picloudtcp.h
|
||||
|
||||
### Client/Server (4 файла)
|
||||
- libs/main/client_server/piclientserver_client.h
|
||||
- libs/main/client_server/piclientserver_client_base.h
|
||||
- libs/main/client_server/piclientserver_module.h
|
||||
- libs/main/client_server/piclientserver_server.h
|
||||
|
||||
### Console (9 файлов)
|
||||
- libs/main/console/piconsolemodule.h
|
||||
- libs/main/console/pikbdlistener.h
|
||||
- libs/main/console/piscreen.h
|
||||
- libs/main/console/piscreenconsole.h
|
||||
- libs/main/console/piscreendrawer.h
|
||||
- libs/main/console/piscreentile.h
|
||||
- libs/main/console/piscreentiles.h
|
||||
- libs/main/console/piscreentypes.h
|
||||
- libs/main/console/piterminal.h
|
||||
|
||||
### Resources (3 файла)
|
||||
- libs/main/resources/piresources.h
|
||||
- libs/main/resources/piresourcesstorage.h
|
||||
|
||||
### Application (3 файла)
|
||||
- libs/main/application/piapplication.h
|
||||
- libs/main/application/pimain.h
|
||||
|
||||
### Literals (6 файлов)
|
||||
- libs/main/literals/piliterals.h
|
||||
- libs/main/literals/piliterals_bytearray.h
|
||||
- libs/main/literals/piliterals_bytes.h
|
||||
- libs/main/literals/piliterals_regularexpression.h
|
||||
- libs/main/literals/piliterals_string.h
|
||||
- libs/main/literals/piliterals_time.h
|
||||
|
||||
### Geo (4 файла)
|
||||
- libs/main/geo/piellipsoidmodel.h
|
||||
- libs/main/geo/pigeomodule.h
|
||||
- libs/main/geo/pigeoposition.h
|
||||
|
||||
### Units (много файлов)
|
||||
- libs/main/units/piunits.h
|
||||
- libs/main/units/piunits_base.h
|
||||
- libs/main/units/piunits_class_angle.h
|
||||
- libs/main/units/piunits_class_distance.h
|
||||
- libs/main/units/piunits_class_information.h
|
||||
- libs/main/units/piunits_class_mass.h
|
||||
- libs/main/units/piunits_class_pressure.h
|
||||
- libs/main/units/piunits_class_temperature.h
|
||||
- libs/main/units/piunits_class_time.h
|
||||
- libs/main/units/piunits_prefix.h
|
||||
- libs/main/units/piunits_value.h
|
||||
|
||||
### Code (3 файла)
|
||||
- libs/main/code/picodeparser.h
|
||||
- libs/main/code/picodeinfo.h
|
||||
- libs/main/code/picodemodule.h
|
||||
|
||||
### Compression (1 файл)
|
||||
- libs/main/compress/picompress.h
|
||||
|
||||
### OpenCL (1 файл)
|
||||
- libs/main/opencl/piopencl.h
|
||||
|
||||
### Другие модули
|
||||
- libs/main/pip.h
|
||||
- libs/main/piplatform.h
|
||||
- libs/main/literals/piliterals.h
|
||||
- libs/main/code/picodeparser.h
|
||||
- libs/main/cloud/picloudtcp.h
|
||||
13
plans/doxygen_example.md
Normal file
13
plans/doxygen_example.md
Normal file
@@ -0,0 +1,13 @@
|
||||
Ключевые элементы документации
|
||||
|
||||
| Элемент | Описание |
|
||||
|---------|----------|
|
||||
| //! \~english | Описание на английском языке |
|
||||
| //! \~russian | Описание на русском языке |
|
||||
| //! \details | |
|
||||
| //! \~english | Детальное объяснение на английском языке |
|
||||
| //! \~russian | Детальное объяснение на русском языке |
|
||||
| //! \note | |
|
||||
| //! \~english | Важное примечание о сложности/поведении на английском языке |
|
||||
| //! \~russian | Важное примечание о сложности/поведении на русском языке |
|
||||
| //! \~\sa | Ссылки на связанные функции |
|
||||
@@ -1,70 +1,28 @@
|
||||
# План рефакторинга PIVector2D
|
||||
|
||||
## Этап 1: Выполнить наследование Row от RowConst, Col от ColConst
|
||||
## Этап 1: Сборка
|
||||
|
||||
### 1.1 Переместить RowConst перед Row
|
||||
- Найти местоположение RowConst (текущая позиция ~строка 610)
|
||||
- Переместить определение RowConst перед Row (до строки ~184)
|
||||
### 1.1 Собрать проект
|
||||
- [x] собери проект, при необходимости поправь ошибки
|
||||
|
||||
### 1.2 Переместить ColConst перед Col
|
||||
- Найти местоположение ColConst (текущая позиция ~строка 770)
|
||||
- Переместить определение ColConst перед Col (до строки ~402)
|
||||
## Этап 2: Проверить и поправить тесты
|
||||
|
||||
### 1.3 Изменить класс Row
|
||||
- Наследовать от RowConst: `class Row : public RowConst`
|
||||
- Убрать дублирующиеся методы (они унаследованы от RowConst):
|
||||
- size()
|
||||
- toVector()
|
||||
- operator[] (const версия)
|
||||
- data() (const версия)
|
||||
- indexOf()
|
||||
- lastIndexOf()
|
||||
- indexWhere()
|
||||
- lastIndexWhere()
|
||||
- forEach() (const версия)
|
||||
- contains()
|
||||
- entries()
|
||||
- any()
|
||||
- every()
|
||||
- Сохранить неконстантные методы:
|
||||
- operator[] (неконстантный)
|
||||
- data() (неконстантный)
|
||||
- operator=()
|
||||
- forEach() (неконстантный)
|
||||
- fill()
|
||||
|
||||
### 1.4 Изменить класс Col
|
||||
- Наследовать от ColConst: `class Col : public ColConst`
|
||||
- Аналогично убрать дублирующиеся методы
|
||||
|
||||
### 1.5 Проверить тесты
|
||||
- Запустить: `./pip_math_test --gtest_filter="*Vector2D*"`
|
||||
### 2.1 Запустить тесты
|
||||
- [x] Запустить: `./build/tests/pip_math_test --gtest_filter="*Vector2D*"`
|
||||
- [x] В случае ошибок внести правки в pivector2d.h
|
||||
|
||||
---
|
||||
|
||||
## Этап 2: Заменить PIPair<ssize_t, ssize_t> на PIVector2DIndex
|
||||
## Этап 3: Заменить PIPair<ssize_t, ssize_t> на PIVector2DIndex
|
||||
|
||||
### 2.1 Создать структуру PIVector2DIndex
|
||||
```cpp
|
||||
struct PIVector2DIndex {
|
||||
ssize_t row;
|
||||
ssize_t col;
|
||||
};
|
||||
```
|
||||
### 3.1 Создать структуру PIVector2DIndex
|
||||
- [x] Создано: `struct Index { ssize_t row; ssize_t col; };`
|
||||
|
||||
### 2.2 Обновить return types
|
||||
Методы для изменения:
|
||||
- indexOf() -> возвращает PIVector2DIndex вместо PIPair<ssize_t, ssize_t>
|
||||
- lastIndexOf()
|
||||
- indexWhere()
|
||||
- lastIndexWhere()
|
||||
### 3.2 Обновить return types
|
||||
- [x] indexOf() -> возвращает Index вместо PIPair<ssize_t, ssize_t>
|
||||
- [x] lastIndexOf()
|
||||
- [x] indexWhere()
|
||||
- [x] lastIndexWhere()
|
||||
|
||||
### 2.3 Обновить тесты и документацию
|
||||
|
||||
---
|
||||
|
||||
## Этап 3: Дополнительные улучшения (опционально)
|
||||
|
||||
- Добавить методы для работы с диапазонами
|
||||
- Оптимизировать методы удаления строк/столбцов
|
||||
- Добавить проверку границ в debug-режиме
|
||||
|
||||
@@ -379,6 +379,280 @@ TEST_F(Vector2DTest, addRow_with_shorter_vector_uses_min) {
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== APPEND ROWS TESTS ====================
|
||||
|
||||
TEST_F(Vector2DTest, appendRows_adds_rows_at_bottom) {
|
||||
size_t oldRows = vec.rows();
|
||||
size_t oldCols = vec.cols();
|
||||
|
||||
vec.appendRows(5, 42);
|
||||
|
||||
EXPECT_EQ(vec.rows(), oldRows + 5);
|
||||
EXPECT_EQ(vec.cols(), oldCols);
|
||||
|
||||
// Original data preserved
|
||||
for (size_t r = 0; r < oldRows; ++r) {
|
||||
for (size_t c = 0; c < oldCols; ++c) {
|
||||
EXPECT_EQ(vec.element(r, c), static_cast<int>(r * COLS_COUNT_INIT + c));
|
||||
}
|
||||
}
|
||||
|
||||
// New rows filled with 42
|
||||
for (size_t r = oldRows; r < vec.rows(); ++r) {
|
||||
for (size_t c = 0; c < oldCols; ++c) {
|
||||
EXPECT_EQ(vec.element(r, c), 42);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, appendRows_with_zero_count_does_nothing) {
|
||||
auto oldVec = vec;
|
||||
vec.appendRows(0);
|
||||
EXPECT_EQ(vec, oldVec);
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, appendRows_on_empty_matrix) {
|
||||
PIVector2D<int> empty;
|
||||
empty.appendRows(5, 99);
|
||||
EXPECT_TRUE(empty.isNotEmpty());
|
||||
EXPECT_EQ(empty.rows(), 5);
|
||||
EXPECT_EQ(empty.cols(), 1);
|
||||
EXPECT_EQ(empty.size(), empty.entries(99));
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, appendRows_with_default_value) {
|
||||
size_t oldRows = vec.rows();
|
||||
|
||||
vec.appendRows(3);
|
||||
|
||||
for (size_t r = oldRows; r < vec.rows(); ++r) {
|
||||
for (size_t c = 0; c < vec.cols(); ++c) {
|
||||
EXPECT_EQ(vec.element(r, c), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== APPEND COLUMNS TESTS ====================
|
||||
|
||||
TEST_F(Vector2DTest, appendColumns_adds_columns_at_right) {
|
||||
size_t oldRows = vec.rows();
|
||||
size_t oldCols = vec.cols();
|
||||
|
||||
vec.appendColumns(3, 99);
|
||||
|
||||
EXPECT_EQ(vec.rows(), oldRows);
|
||||
EXPECT_EQ(vec.cols(), oldCols + 3);
|
||||
|
||||
// Original data preserved in original columns
|
||||
for (size_t r = 0; r < oldRows; ++r) {
|
||||
for (size_t c = 0; c < oldCols; ++c) {
|
||||
EXPECT_EQ(vec.element(r, c), static_cast<int>(r * COLS_COUNT_INIT + c));
|
||||
}
|
||||
}
|
||||
|
||||
// New columns filled with 99
|
||||
for (size_t r = 0; r < oldRows; ++r) {
|
||||
for (size_t c = oldCols; c < vec.cols(); ++c) {
|
||||
EXPECT_EQ(vec.element(r, c), 99);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, appendColumns_with_zero_count_does_nothing) {
|
||||
auto oldVec = vec;
|
||||
vec.appendColumns(0);
|
||||
EXPECT_EQ(vec, oldVec);
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, appendColumns_on_empty_matrix) {
|
||||
PIVector2D<int> empty;
|
||||
empty.appendColumns(5, 99);
|
||||
EXPECT_TRUE(empty.isNotEmpty());
|
||||
EXPECT_EQ(empty.cols(), 5);
|
||||
EXPECT_EQ(empty.rows(), 1);
|
||||
EXPECT_EQ(empty.size(), empty.entries(99));
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, appendColumns_single_column) {
|
||||
auto oldVec = vec;
|
||||
|
||||
vec.appendColumns(1, 77);
|
||||
|
||||
EXPECT_EQ(vec.rows(), oldVec.rows());
|
||||
EXPECT_EQ(vec.cols(), oldVec.cols() + 1);
|
||||
|
||||
// Check original data
|
||||
for (size_t r = 0; r < vec.rows(); ++r) {
|
||||
for (size_t c = 0; c < oldVec.cols(); ++c) {
|
||||
EXPECT_EQ(vec.element(r, c), oldVec.element(r, c));
|
||||
}
|
||||
}
|
||||
|
||||
// Check new column
|
||||
for (size_t r = 0; r < vec.rows(); ++r) {
|
||||
EXPECT_EQ(vec.element(r, oldVec.cols()), 77);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== DELETE ROWS TESTS ====================
|
||||
|
||||
TEST_F(Vector2DTest, deleteRows_removes_rows_from_middle) {
|
||||
size_t oldRows = vec.rows();
|
||||
size_t oldCols = vec.cols();
|
||||
|
||||
vec.deleteRows(5, 3);
|
||||
|
||||
EXPECT_EQ(vec.rows(), oldRows - 3);
|
||||
EXPECT_EQ(vec.cols(), oldCols);
|
||||
|
||||
// Rows before deleted remain
|
||||
for (size_t r = 0; r < 5; ++r) {
|
||||
for (size_t c = 0; c < oldCols; ++c) {
|
||||
EXPECT_EQ(vec.element(r, c), static_cast<int>(r * COLS_COUNT_INIT + c));
|
||||
}
|
||||
}
|
||||
|
||||
// Rows after deleted shifted up
|
||||
for (size_t r = 5; r < vec.rows(); ++r) {
|
||||
for (size_t c = 0; c < oldCols; ++c) {
|
||||
EXPECT_EQ(vec.element(r, c), static_cast<int>((r + 3) * COLS_COUNT_INIT + c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, deleteRows_at_end_works) {
|
||||
size_t oldRows = vec.rows();
|
||||
size_t oldCols = vec.cols();
|
||||
|
||||
vec.deleteRows(oldRows - 2, 2);
|
||||
|
||||
EXPECT_EQ(vec.rows(), oldRows - 2);
|
||||
EXPECT_EQ(vec.cols(), oldCols);
|
||||
|
||||
// All remaining rows should have original content
|
||||
for (size_t r = 0; r < vec.rows(); ++r) {
|
||||
for (size_t c = 0; c < oldCols; ++c) {
|
||||
EXPECT_EQ(vec.element(r, c), static_cast<int>(r * COLS_COUNT_INIT + c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, deleteRows_beyond_bounds_is_limited) {
|
||||
size_t oldRows = vec.rows();
|
||||
size_t oldCols = vec.cols();
|
||||
size_t count = 10;
|
||||
|
||||
vec.deleteRows(oldRows - 2, count);
|
||||
|
||||
EXPECT_EQ(vec.rows(), oldRows - count);
|
||||
EXPECT_EQ(vec.cols(), oldCols);
|
||||
|
||||
// All remaining rows should have original content
|
||||
for (size_t r = 0; r < oldRows; ++r) {
|
||||
for (size_t c = 0; c < vec.cols(); ++c) {
|
||||
EXPECT_EQ(vec.element(r, c), static_cast<int>(r * COLS_COUNT_INIT + c));
|
||||
}
|
||||
}
|
||||
|
||||
// All new rows should have original content
|
||||
for (size_t r = oldRows; r < vec.rows(); ++r) {
|
||||
for (size_t c = 0; c < vec.cols(); ++c) {
|
||||
EXPECT_EQ(vec.element(r, c), static_cast<int>((r+count) * COLS_COUNT_INIT + c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, deleteRows_invalid_start_does_nothing) {
|
||||
auto oldVec = vec;
|
||||
vec.deleteRows(oldVec.rows() + 10, 2);
|
||||
EXPECT_EQ(vec, oldVec);
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, deleteRows_zero_count_does_nothing) {
|
||||
auto oldVec = vec;
|
||||
vec.deleteRows(5, 0);
|
||||
EXPECT_EQ(vec, oldVec);
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, deleteRows_all_rows_creates_empty) {
|
||||
vec.deleteRows(0, vec.rows());
|
||||
EXPECT_TRUE(vec.isEmpty());
|
||||
EXPECT_EQ(vec.rows(), 0);
|
||||
EXPECT_EQ(vec.cols(), 0);
|
||||
}
|
||||
|
||||
// ==================== DELETE COLUMNS TESTS ====================
|
||||
|
||||
TEST_F(Vector2DTest, deleteColumns_removes_columns_from_middle) {
|
||||
size_t oldRows = vec.rows();
|
||||
size_t oldCols = vec.cols();
|
||||
|
||||
vec.deleteColumns(4, 3);
|
||||
|
||||
EXPECT_EQ(vec.rows(), oldRows);
|
||||
EXPECT_EQ(vec.cols(), oldCols - 3);
|
||||
|
||||
// Columns before deleted remain
|
||||
for (size_t r = 0; r < oldRows; ++r) {
|
||||
for (size_t c = 0; c < 4; ++c) {
|
||||
EXPECT_EQ(vec.element(r, c), static_cast<int>(r * COLS_COUNT_INIT + c));
|
||||
}
|
||||
}
|
||||
|
||||
// Columns after deleted shifted left
|
||||
for (size_t r = 0; r < oldRows; ++r) {
|
||||
for (size_t c = 4; c < vec.cols(); ++c) {
|
||||
EXPECT_EQ(vec.element(r, c), static_cast<int>(r * COLS_COUNT_INIT + c + 3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, deleteColumns_at_end_works) {
|
||||
size_t oldRows = vec.rows();
|
||||
size_t oldCols = vec.cols();
|
||||
|
||||
vec.deleteColumns(oldCols - 2, 2);
|
||||
|
||||
EXPECT_EQ(vec.rows(), oldRows);
|
||||
EXPECT_EQ(vec.cols(), oldCols - 2);
|
||||
|
||||
// All remaining columns should have original content
|
||||
for (size_t r = 0; r < oldRows; ++r) {
|
||||
for (size_t c = 0; c < vec.cols(); ++c) {
|
||||
EXPECT_EQ(vec.element(r, c), static_cast<int>(r * COLS_COUNT_INIT + c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, deleteColumns_beyond_bounds_is_limited) {
|
||||
size_t oldRows = vec.rows();
|
||||
size_t oldCols = vec.cols();
|
||||
|
||||
vec.deleteColumns(oldCols - 2, 10);
|
||||
|
||||
EXPECT_EQ(vec.rows(), oldRows);
|
||||
EXPECT_EQ(vec.cols(), oldCols - 2);
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, deleteColumns_invalid_start_does_nothing) {
|
||||
auto oldVec = vec;
|
||||
vec.deleteColumns(oldVec.cols() + 10, 2);
|
||||
EXPECT_EQ(vec, oldVec);
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, deleteColumns_zero_count_does_nothing) {
|
||||
auto oldVec = vec;
|
||||
vec.deleteColumns(5, 0);
|
||||
EXPECT_EQ(vec, oldVec);
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, deleteColumns_all_columns_preserves_rows) {
|
||||
vec.deleteColumns(0, vec.cols());
|
||||
EXPECT_EQ(vec.rows(), ROWS_COUNT_INIT);
|
||||
EXPECT_EQ(vec.cols(), 0);
|
||||
EXPECT_EQ(vec.size(), 0);
|
||||
}
|
||||
|
||||
// ==================== ADD COLUMN TESTS ====================
|
||||
|
||||
TEST_F(Vector2DTest, addColumn_appends_column_to_empty) {
|
||||
@@ -400,7 +674,7 @@ TEST_F(Vector2DTest, addColumn_appends_column_to_existing) {
|
||||
size_t oldRows = vec.rows();
|
||||
size_t oldCols = vec.cols();
|
||||
|
||||
PIVector<int> newCol(oldRows, 999);
|
||||
PIVector<int> newCol(oldRows, [](size_t i){return -900 - (int)i;});
|
||||
vec.addColumn(newCol);
|
||||
|
||||
EXPECT_EQ(vec.rows(), oldRows);
|
||||
@@ -415,7 +689,7 @@ TEST_F(Vector2DTest, addColumn_appends_column_to_existing) {
|
||||
|
||||
// Check new column
|
||||
for (size_t r = 0; r < oldRows; ++r) {
|
||||
EXPECT_EQ(vec.element(r, oldCols), 999);
|
||||
EXPECT_EQ(vec.element(r, oldCols), -900 - (int)r);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -497,7 +771,6 @@ TEST_F(Vector2DTest, addColumn_with_Col_proxy_works) {
|
||||
}
|
||||
for (size_t r = 0; r < vec.rows(); ++r) {
|
||||
// EXPECT_EQ(vec.element(r, oldVec.cols()), int());
|
||||
piCout << r << vec.cols() << oldVec.cols() << colIndex;
|
||||
EXPECT_EQ(vec.element(r, oldVec.cols()), oldVec.element(r, colIndex));
|
||||
}
|
||||
}
|
||||
@@ -952,36 +1225,36 @@ TEST_F(Vector2DTest, forEach_modifying_changes_elements) {
|
||||
|
||||
TEST_F(Vector2DTest, indexOf_returns_correct_pair) {
|
||||
auto p = vec.indexOf(vec.element(10, 15));
|
||||
EXPECT_EQ(p.first, 10);
|
||||
EXPECT_EQ(p.second, 15);
|
||||
EXPECT_EQ(p.row, 10);
|
||||
EXPECT_EQ(p.col, 15);
|
||||
p = vec.indexOf(-999);
|
||||
EXPECT_EQ(p.first, -1);
|
||||
EXPECT_EQ(p.second, -1);
|
||||
EXPECT_EQ(p.row, -1);
|
||||
EXPECT_EQ(p.col, -1);
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, indexWhere_returns_correct_pair) {
|
||||
vec.element(5, 5) = -42;
|
||||
auto isTarget = [](const int & e) { return e == -42; };
|
||||
auto p = vec.indexWhere(isTarget);
|
||||
EXPECT_EQ(p.first, 5);
|
||||
EXPECT_EQ(p.second, 5);
|
||||
EXPECT_EQ(p.row, 5);
|
||||
EXPECT_EQ(p.col, 5);
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, lastIndexOf_works) {
|
||||
int val = vec.element(10, 10);
|
||||
vec.element(20, 20) = val; // duplicate
|
||||
auto p = vec.lastIndexOf(val);
|
||||
EXPECT_EQ(p.first, 20);
|
||||
EXPECT_EQ(p.second, 20);
|
||||
EXPECT_EQ(p.row, 20);
|
||||
EXPECT_EQ(p.col, 20);
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, lastIndexWhere_works) {
|
||||
auto isLarge = [](const int & e) { return e > 500; };
|
||||
auto p = vec.lastIndexWhere(isLarge);
|
||||
EXPECT_GE(p.first, 0);
|
||||
EXPECT_GE(p.second, 0);
|
||||
EXPECT_GE(p.row, 0);
|
||||
EXPECT_GE(p.col, 0);
|
||||
// The last element with value >500 should be the largest index
|
||||
size_t lastFlat = p.first * vec.cols() + p.second;
|
||||
size_t lastFlat = p.row * vec.cols() + p.col;
|
||||
size_t expectedLastFlat = vec.size() - 1;
|
||||
EXPECT_EQ(lastFlat, expectedLastFlat);
|
||||
}
|
||||
@@ -1431,3 +1704,94 @@ TEST_F(Vector2DTest, iostream_operator_works) {
|
||||
// No assertion, just ensure it runs
|
||||
}
|
||||
#endif
|
||||
|
||||
// ==================== INDEX STRUCTURE ACCESS TESTS ====================
|
||||
TEST_F(Vector2DTest, operator_bracket_with_index_allows_read_access) {
|
||||
PIVector2D<int>::Index idx = {5, 7};
|
||||
int value = vec[idx];
|
||||
int expected = vec.element(5, 7);
|
||||
EXPECT_EQ(value, expected);
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, operator_bracket_with_index_allows_write_access) {
|
||||
PIVector2D<int>::Index idx = {10, 15};
|
||||
vec[idx] = 999;
|
||||
EXPECT_EQ(vec.element(10, 15), 999);
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, operator_bracket_with_const_index_works) {
|
||||
const auto & constVec = vec;
|
||||
PIVector2D<int>::Index idx = {3, 12};
|
||||
int value = constVec[idx];
|
||||
int expected = vec.element(3, 12);
|
||||
EXPECT_EQ(value, expected);
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, element_function_with_index_works) {
|
||||
PIVector2D<int>::Index idx = {8, 20};
|
||||
int value = vec.element(idx);
|
||||
int expected = vec.element(8, 20);
|
||||
EXPECT_EQ(value, expected);
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, element_function_with_index_modifies_value) {
|
||||
PIVector2D<int>::Index idx = {12, 8};
|
||||
vec.element(idx) = 555;
|
||||
EXPECT_EQ(vec.element(12, 8), 555);
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, element_function_with_const_index_works) {
|
||||
const auto & constVec = vec;
|
||||
PIVector2D<int>::Index idx = {7, 5};
|
||||
int value = constVec.element(idx);
|
||||
int expected = vec.element(7, 5);
|
||||
EXPECT_EQ(value, expected);
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, at_function_with_index_works) {
|
||||
PIVector2D<int>::Index idx = {4, 11};
|
||||
int value = vec.at(idx);
|
||||
int expected = vec.at(4, 11);
|
||||
EXPECT_EQ(value, expected);
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, index_structure_with_brace_initialization_works) {
|
||||
vec[{0, 0}] = 100;
|
||||
EXPECT_EQ(vec.element(0, 0), 100);
|
||||
|
||||
vec[{static_cast<ssize_t>(ROWS_COUNT_INIT - 1), static_cast<ssize_t>(COLS_COUNT_INIT - 1)}] = 200;
|
||||
EXPECT_EQ(vec.element(ROWS_COUNT_INIT - 1, COLS_COUNT_INIT - 1), 200);
|
||||
}
|
||||
|
||||
TEST(Vector2DIndexTest, default_constructor_initializes_to_invalid) {
|
||||
PIVector2D<int>::Index idx;
|
||||
EXPECT_TRUE(idx.isNotValid());
|
||||
EXPECT_FALSE(idx.isValid());
|
||||
EXPECT_EQ(idx.row, -1);
|
||||
EXPECT_EQ(idx.col, -1);
|
||||
}
|
||||
|
||||
TEST(Vector2DIndexTest, parameterized_constructor_initializes_correctly) {
|
||||
PIVector2D<int>::Index idx(5, 10);
|
||||
EXPECT_TRUE(idx.isValid());
|
||||
EXPECT_FALSE(idx.isNotValid());
|
||||
EXPECT_EQ(idx.row, 5);
|
||||
EXPECT_EQ(idx.col, 10);
|
||||
}
|
||||
|
||||
TEST(Vector2DIndexTest, isValid_returns_true_for_non_negative_values) {
|
||||
PIVector2D<int>::Index idx(0, 0);
|
||||
EXPECT_TRUE(idx.isValid());
|
||||
EXPECT_FALSE(idx.isNotValid());
|
||||
}
|
||||
|
||||
TEST(Vector2DIndexTest, isNotValid_returns_true_for_negative_values) {
|
||||
PIVector2D<int>::Index idx1;
|
||||
EXPECT_TRUE(idx1.isNotValid());
|
||||
|
||||
PIVector2D<int>::Index idx2(-1, 5);
|
||||
EXPECT_TRUE(idx2.isNotValid());
|
||||
|
||||
PIVector2D<int>::Index idx3(5, -1);
|
||||
EXPECT_TRUE(idx3.isNotValid());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user