add more funcs
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
#ifndef PIVECTOR2D_H
|
||||
#define PIVECTOR2D_H
|
||||
|
||||
#include "pipair.h"
|
||||
#include "pivector.h"
|
||||
|
||||
//! \addtogroup Containers
|
||||
@@ -77,12 +78,6 @@ public:
|
||||
//! \param rows Number of rows.
|
||||
//! \param cols Number of columns.
|
||||
//! \param v The source 1D vector. Its size must be at least `rows * cols`.
|
||||
//! \~english \param rows Количество строк.
|
||||
//! \~russian \param rows Количество строк.
|
||||
//! \~english \param cols Количество столбцов.
|
||||
//! \~russian \param cols Количество столбцов.
|
||||
//! \~english \param v Исходный одномерный вектор. Его размер должен быть не меньше `rows * cols`.
|
||||
//! \~russian \param v Исходный одномерный вектор. Его размер должен быть не меньше `rows * cols`.
|
||||
inline PIVector2D(size_t rows, size_t cols, const PIVector<T> & v): rows_(rows), cols_(cols), mat(v) { mat.resize(rows * cols); }
|
||||
|
||||
//! \~english Move constructs a 2D array from an existing 1D vector, reshaping it.
|
||||
@@ -90,19 +85,11 @@ public:
|
||||
//! \param rows Number of rows.
|
||||
//! \param cols Number of columns.
|
||||
//! \param v The source 1D vector (rvalue reference). Its size must be at least `rows * cols`.
|
||||
//! \~english \param rows Количество строк.
|
||||
//! \~russian \param rows Количество строк.
|
||||
//! \~english \param cols Количество столбцов.
|
||||
//! \~russian \param cols Количество столбцов.
|
||||
//! \~english \param v Исходный одномерный вектор (rvalue-ссылка). Его размер должен быть не меньше `rows * cols`.
|
||||
//! \~russian \param v Исходный одномерный вектор (rvalue-ссылка). Его размер должен быть не меньше `rows * cols`.
|
||||
inline PIVector2D(size_t rows, size_t cols, PIVector<T> && v): rows_(rows), cols_(cols), mat(std::move(v)) { mat.resize(rows * cols); }
|
||||
|
||||
//! \~english Constructs a 2D array from a vector of vectors (jagged array). Assumes all inner vectors have the same size.
|
||||
//! \~russian Создает двумерный массив из вектора векторов (рваного массива). Предполагается, что все внутренние векторы имеют
|
||||
//! одинаковый размер. \param v The source vector of vectors.
|
||||
//! \~english \param v Исходный вектор векторов.
|
||||
//! \~russian \param v Исходный вектор векторов.
|
||||
inline PIVector2D(const PIVector<PIVector<T>> & v) {
|
||||
rows_ = v.size();
|
||||
if (rows_) {
|
||||
@@ -205,6 +192,36 @@ public:
|
||||
//! \~english Converts the row to a \a PIVector.
|
||||
//! \~russian Преобразует строку в \a PIVector.
|
||||
inline PIVector<T> toVector() const { return PIVector<T>(p_->data(st_), sz_); }
|
||||
|
||||
// --- Поиск в строке ---
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
//! \class Col
|
||||
@@ -272,6 +289,36 @@ public:
|
||||
ret << (*p_)[i * step_ + col_];
|
||||
return ret;
|
||||
}
|
||||
|
||||
// --- Поиск в столбце ---
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
//! \class RowConst
|
||||
@@ -305,6 +352,36 @@ public:
|
||||
//! \~english Converts the row to a \a PIVector.
|
||||
//! \~russian Преобразует строку в \a PIVector.
|
||||
inline PIVector<T> toVector() const { return PIVector<T>(p_->data(st_), sz_); }
|
||||
|
||||
// --- Поиск в строке (только чтение) ---
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
//! \class ColConst
|
||||
@@ -345,6 +422,36 @@ public:
|
||||
ret << (*p_)[i * step_ + col_];
|
||||
return ret;
|
||||
}
|
||||
|
||||
// --- Поиск в столбце (только чтение) ---
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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 Returns a reference to the element at the given row and column.
|
||||
@@ -549,22 +656,39 @@ public:
|
||||
inline int entries(std::function<bool(const T & e)> test, ssize_t start = 0) const { return mat.entries(test, start); }
|
||||
|
||||
|
||||
// TODO: next 4 functions implement in to RowConst and ColConst and rewtite thisto return index as PIPair<ssize_t row, ssize_t col>
|
||||
//! \~english Returns the first index of `e` in the flat vector.
|
||||
//! \~russian Возвращает первый индекс `e` в плоском векторе.
|
||||
inline ssize_t indexOf(const T & e, ssize_t start = 0) const { return mat.indexOf(e, start); }
|
||||
//! \~english Returns the first index in the flat vector that passes the `test`.
|
||||
//! \~russian Возвращает первый индекс в плоском векторе, проходящий `test`.
|
||||
inline ssize_t indexWhere(std::function<bool(const T & e)> test, ssize_t start = 0) const { return mat.indexWhere(test, start); }
|
||||
//! \~english Returns the last index of `e` in the flat vector.
|
||||
//! \~russian Возвращает последний индекс `e` в плоском векторе.
|
||||
inline ssize_t lastIndexOf(const T & e, ssize_t start = -1) const { return mat.lastIndexOf(e, start); }
|
||||
//! \~english Returns the last index in the flat vector that passes the `test`.
|
||||
//! \~russian Возвращает последний индекс в плоском векторе, проходящий `test`.
|
||||
inline ssize_t lastIndexWhere(std::function<bool(const T & e)> test, ssize_t start = -1) const {
|
||||
return mat.lastIndexWhere(test, start);
|
||||
//! \~english Returns the first index (row, col) of `e` in the 2D array.
|
||||
//! \~russian Возвращает первый индекс (строка, столбец) элемента `e` в двумерном массиве.
|
||||
inline PIPair<ssize_t, ssize_t> indexOf(const T & e, ssize_t start = 0) const {
|
||||
ssize_t flat = mat.indexOf(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_);
|
||||
}
|
||||
|
||||
//! \~english Returns the first index (row, col) in the 2D array that passes the `test`.
|
||||
//! \~russian Возвращает первый индекс (строка, столбец) в двумерном массиве, проходящий `test`.
|
||||
inline PIPair<ssize_t, ssize_t> 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_);
|
||||
}
|
||||
|
||||
//! \~english Returns the last index (row, col) of `e` in the 2D array.
|
||||
//! \~russian Возвращает последний индекс (строка, столбец) элемента `e` в двумерном массиве.
|
||||
inline PIPair<ssize_t, ssize_t> 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_);
|
||||
}
|
||||
|
||||
//! \~english Returns the last index (row, col) in the 2D array that passes the `test`.
|
||||
//! \~russian Возвращает последний индекс (строка, столбец) в двумерном массиве, проходящий `test`.
|
||||
inline PIPair<ssize_t, ssize_t> 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_);
|
||||
}
|
||||
|
||||
|
||||
//! \~english Tests if any element in the flat vector passes the `test`.
|
||||
//! \~russian Проверяет, проходит ли какой-либо элемент в плоском векторе `test`.
|
||||
inline bool any(std::function<bool(const T & e)> test) const { return mat.any(test); }
|
||||
@@ -591,22 +715,17 @@ public:
|
||||
//! \~russian То же, что и \a fill().
|
||||
inline PIVector2D<T> & assign(const T & e = T()) { return fill(e); }
|
||||
|
||||
|
||||
// TODO: rewrite with size_t rows, size_t cols arguments
|
||||
//! \~english Assigns a new size to the underlying flat vector and resets the 2D structure to 1 row.
|
||||
//! \~russian Присваивает новый размер внутреннему плоскому вектору и сбрасывает 2D-структуру до 1 строки.
|
||||
inline PIVector2D<T> & assign(size_t new_size, const T & f) {
|
||||
mat.assign(new_size, f);
|
||||
if (mat.isEmpty()) {
|
||||
rows_ = cols_ = 0;
|
||||
} else {
|
||||
rows_ = 1;
|
||||
cols_ = mat.size();
|
||||
}
|
||||
//! \~english Assigns new size and fills with value.
|
||||
//! \~russian Задаёт новый размер и заполняет значением.
|
||||
inline PIVector2D<T> & assign(size_t rows, size_t cols, const T & f = T()) {
|
||||
mat.assign(rows * cols, f);
|
||||
rows_ = rows;
|
||||
cols_ = cols;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// TODO: fix for different rows and cols count
|
||||
|
||||
// TODO: исправить - при транспонировании количество строк становится количеством столбцов и наоборот
|
||||
//! \~english Returns a transposed 2D array (rows become columns and vice versa).
|
||||
//! \~russian Возвращает транспонированный двумерный массив (строки становятся столбцами и наоборот).
|
||||
inline PIVector2D<T> transposed() const {
|
||||
@@ -620,17 +739,16 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO: переписать по возможности избегая копирования данных, в идеале использовать piSwap
|
||||
//! \~english Reverses the order of rows in place.
|
||||
//! \~russian Изменяет порядок строк на обратный на месте.
|
||||
inline PIVector2D<T> & reverseRows() {
|
||||
const size_t half = rows_ / 2;
|
||||
for (size_t i = 0; i < half; ++i) {
|
||||
Row r1 = row(i);
|
||||
Row r2 = row(rows_ - 1 - i);
|
||||
PIVector<T> temp = r1.toVector();
|
||||
r1 = r2.toVector();
|
||||
r2 = temp;
|
||||
T * row1 = data(i * cols_);
|
||||
T * row2 = data((rows_ - 1 - i) * cols_);
|
||||
for (size_t j = 0; j < cols_; ++j) {
|
||||
piSwap(row1[j], row2[j]);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -685,42 +803,33 @@ public:
|
||||
return PIVector2D<ST>(rows_, cols_, std::move(mappedMat));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
//! \~english Executes a read-only function for each element.
|
||||
//! \~russian Выполняет функцию только для чтения для каждого элемента.
|
||||
inline void forEach(std::function<void(const T &)> f) const { mat.forEach(f); }
|
||||
|
||||
//! \~english Executes a function for each element, allowing modification.
|
||||
//! \~russian Выполняет функцию для каждого элемента, позволяя их изменять.
|
||||
inline PIVector2D<T> & forEach(std::function<void(T &)> f) {
|
||||
mat.forEach(f);
|
||||
return *this;
|
||||
// --- Итерация по строкам и столбцам ---
|
||||
//! \~english Applies a function to each row (modifiable).
|
||||
//! \~russian Применяет функцию к каждой строке (с возможностью изменения).
|
||||
inline PIVector2D<T> & forEachRow(std::function<void(Row)> f) {
|
||||
for (size_t r = 0; r < rows_; ++r)
|
||||
f(row(r));
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Executes a read-only function (with row and col indices) for each element.
|
||||
//! \~russian Выполняет функцию только для чтения (с индексами строки и столбца) для каждого элемента.
|
||||
inline void forEachIndexed(std::function<void(size_t row, size_t col, const T &)> f) const {
|
||||
for (size_t r = 0; r < rows_; ++r) {
|
||||
for (size_t c = 0; c < cols_; ++c) {
|
||||
f(r, c, element(r, c));
|
||||
}
|
||||
}
|
||||
//! \~english Applies a function to each row (read-only).
|
||||
//! \~russian Применяет функцию к каждой строке (только чтение).
|
||||
inline void forEachRow(std::function<void(RowConst)> f) const {
|
||||
for (size_t r = 0; r < rows_; ++r)
|
||||
f(row(r));
|
||||
}
|
||||
|
||||
//! \~english Executes a function (with row and col indices) for each element, allowing modification.
|
||||
//! \~russian Выполняет функцию (с индексами строки и столбца) для каждого элемента, позволяя их изменять.
|
||||
inline PIVector2D<T> & forEachIndexed(std::function<void(size_t row, size_t col, T &)> f) {
|
||||
for (size_t r = 0; r < rows_; ++r) {
|
||||
for (size_t c = 0; c < cols_; ++c) {
|
||||
f(r, c, element(r, c));
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
//! \~english Applies a function to each column (modifiable).
|
||||
//! \~russian Применяет функцию к каждому столбцу (с возможностью изменения).
|
||||
inline PIVector2D<T> & forEachColumn(std::function<void(Col)> f) {
|
||||
for (size_t c = 0; c < cols_; ++c)
|
||||
f(col(c));
|
||||
return *this;
|
||||
}
|
||||
//! \~english Applies a function to each column (read-only).
|
||||
//! \~russian Применяет функцию к каждому столбцу (только чтение).
|
||||
inline void forEachColumn(std::function<void(ColConst)> f) const {
|
||||
for (size_t c = 0; c < cols_; ++c)
|
||||
f(col(c));
|
||||
}
|
||||
*/
|
||||
// TODO: Переделать закомментаренные выше функции на функции forEachRow, forEachColumn
|
||||
|
||||
|
||||
//! \~english Accumulates a value across all elements.
|
||||
//! \~russian Аккумулирует значение по всем элементам.
|
||||
|
||||
@@ -411,40 +411,6 @@ TEST_F(Vector2DTest, entries_with_predicate_counts_matches) {
|
||||
EXPECT_EQ(vec.entries(isEven), evenCount);
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, indexOf_finds_first_occurrence) {
|
||||
int firstTarget = 5 * COLS_COUNT_INIT + 10;
|
||||
EXPECT_EQ(vec.indexOf(firstTarget), static_cast<ssize_t>(firstTarget));
|
||||
|
||||
// Add duplicate later
|
||||
vec.asPlainVector()[20 * COLS_COUNT_INIT + 15] = firstTarget;
|
||||
EXPECT_EQ(vec.indexOf(firstTarget), static_cast<ssize_t>(firstTarget)); // Still first
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, indexOf_with_start_works) {
|
||||
int target = 15 * COLS_COUNT_INIT + 20;
|
||||
EXPECT_EQ(vec.indexOf(target, target + 1), -1);
|
||||
EXPECT_EQ(vec.indexOf(target, target), static_cast<ssize_t>(target));
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, indexWhere_finds_first_match) {
|
||||
auto isLarge = [](const int & e) { return e > 500; };
|
||||
ssize_t expected = 501; // First element > 500
|
||||
EXPECT_EQ(vec.indexWhere(isLarge), expected);
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, lastIndexOf_finds_last_occurrence) {
|
||||
// Add duplicate later
|
||||
int target = 8 * COLS_COUNT_INIT + 8;
|
||||
vec.asPlainVector()[25 * COLS_COUNT_INIT + 25] = target;
|
||||
|
||||
EXPECT_EQ(vec.lastIndexOf(target), static_cast<ssize_t>(25 * COLS_COUNT_INIT + 25));
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, lastIndexWhere_finds_last_match) {
|
||||
auto isLarge = [](const int & e) { return e > 900; };
|
||||
ssize_t expected = vec.size() - 1; // Last element
|
||||
EXPECT_EQ(vec.lastIndexWhere(isLarge), expected);
|
||||
}
|
||||
|
||||
// ==================== STATISTICS AND CONDITIONS TESTS ====================
|
||||
TEST_F(Vector2DTest, any_returns_true_if_any_match) {
|
||||
@@ -495,11 +461,13 @@ TEST_F(Vector2DTest, assign_is_alias_for_fill) {
|
||||
}
|
||||
|
||||
TEST_F(Vector2DTest, assign_with_size_resets_to_single_row) {
|
||||
vec.assign(10, 77);
|
||||
EXPECT_EQ(vec.rows(), 1);
|
||||
EXPECT_EQ(vec.cols(), 10);
|
||||
for (size_t c = 0; c < 10; ++c) {
|
||||
EXPECT_EQ(vec.element(0, c), 77);
|
||||
vec.assign(3, 4, 77);
|
||||
EXPECT_EQ(vec.rows(), 3);
|
||||
EXPECT_EQ(vec.cols(), 4);
|
||||
for (size_t r = 0; r < vec.rows(); ++r) {
|
||||
for (size_t c = 0; c < vec.cols(); ++c) {
|
||||
EXPECT_EQ(vec.element(r, c), 77);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user