add more funcs

This commit is contained in:
2026-02-17 21:40:36 +03:00
parent 9029bcf099
commit 8ecec6b914
2 changed files with 196 additions and 119 deletions

View File

@@ -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 Аккумулирует значение по всем элементам.

View File

@@ -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);
}
}
}