From 97c14870c0e00da58f82f330d87f57d2b1704083 Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Tue, 17 Feb 2026 22:27:25 +0300 Subject: [PATCH 01/29] Add col and row funcs an tests --- libs/main/containers/pivector2d.h | 256 +++++++++++++++++++++++++++++- tests/math/testpivector2d.cpp | 237 +++++++++++++++++++++++++++ 2 files changed, 489 insertions(+), 4 deletions(-) diff --git a/libs/main/containers/pivector2d.h b/libs/main/containers/pivector2d.h index 7bd8a990..809277e8 100644 --- a/libs/main/containers/pivector2d.h +++ b/libs/main/containers/pivector2d.h @@ -193,7 +193,6 @@ public: //! \~russian Преобразует строку в \a PIVector. inline PIVector toVector() const { return PIVector(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) { @@ -201,6 +200,7 @@ public: } 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) { @@ -208,6 +208,7 @@ public: } return -1; } + inline ssize_t indexWhere(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; for (size_t i = (size_t)start; i < sz_; ++i) { @@ -215,6 +216,7 @@ public: } return -1; } + inline ssize_t lastIndexWhere(std::function 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) { @@ -222,6 +224,74 @@ public: } return -1; } + + //! \~english Applies a function to each element of the row (modifiable). + //! \~russian Применяет функцию к каждому элементу строки (с возможностью изменения). + inline void forEach(std::function 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 Применяет функцию к каждому элементу строки (только чтение). + inline void forEach(std::function func) const { + for (size_t i = 0; i < sz_; ++i) { + func((*p_)[st_ + i]); + } + } + + //! \~english Fills the row with copies of `value`. + //! \~russian Заполняет строку копиями `value`. + 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`. + 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` в строке. + 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`. + inline int entries(std::function 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`. + inline bool any(std::function 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`. + inline bool every(std::function test) const { + for (size_t i = 0; i < sz_; ++i) { + if (!test((*p_)[st_ + i])) return false; + } + return true; + } }; //! \class Col @@ -290,7 +360,6 @@ public: 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) { @@ -298,6 +367,7 @@ public: } 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) { @@ -305,6 +375,7 @@ public: } return -1; } + inline ssize_t indexWhere(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; for (size_t i = (size_t)start; i < sz_; ++i) { @@ -312,6 +383,7 @@ public: } return -1; } + inline ssize_t lastIndexWhere(std::function 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) { @@ -319,6 +391,74 @@ public: } return -1; } + + //! \~english Applies a function to each element of the column (modifiable). + //! \~russian Применяет функцию к каждому элементу столбца (с возможностью изменения). + inline void forEach(std::function 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 Применяет функцию к каждому элементу столбца (только чтение). + inline void forEach(std::function 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`. + 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`. + 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` в столбце. + 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`. + inline int entries(std::function 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`. + inline bool any(std::function 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`. + inline bool every(std::function test) const { + for (size_t i = 0; i < sz_; ++i) { + if (!test((*p_)[i * step_ + col_])) return false; + } + return true; + } }; //! \class RowConst @@ -353,7 +493,6 @@ public: //! \~russian Преобразует строку в \a PIVector. inline PIVector toVector() const { return PIVector(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) { @@ -361,6 +500,7 @@ public: } 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) { @@ -368,6 +508,7 @@ public: } return -1; } + inline ssize_t indexWhere(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; for (size_t i = (size_t)start; i < sz_; ++i) { @@ -375,6 +516,7 @@ public: } return -1; } + inline ssize_t lastIndexWhere(std::function 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) { @@ -382,6 +524,58 @@ public: } return -1; } + + //! \~english Applies a function to each element of the row (read-only). + //! \~russian Применяет функцию к каждому элементу строки (только чтение). + inline void forEach(std::function func) const { + for (size_t i = 0; i < sz_; ++i) { + func((*p_)[st_ + i]); + } + } + + //! \~english Checks if the row contains the element `e`. + //! \~russian Проверяет, содержит ли строка элемент `e`. + 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` в строке. + 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`. + inline int entries(std::function 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`. + inline bool any(std::function 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`. + inline bool every(std::function test) const { + for (size_t i = 0; i < sz_; ++i) { + if (!test((*p_)[st_ + i])) return false; + } + return true; + } }; //! \class ColConst @@ -423,7 +617,6 @@ public: 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) { @@ -431,6 +624,7 @@ public: } 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) { @@ -438,6 +632,7 @@ public: } return -1; } + inline ssize_t indexWhere(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; for (size_t i = (size_t)start; i < sz_; ++i) { @@ -445,6 +640,7 @@ public: } return -1; } + inline ssize_t lastIndexWhere(std::function 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) { @@ -452,6 +648,58 @@ public: } return -1; } + + //! \~english Applies a function to each element of the column (read-only). + //! \~russian Применяет функцию к каждому элементу столбца (только чтение). + inline void forEach(std::function func) const { + for (size_t i = 0; i < sz_; ++i) { + func((*p_)[i * step_ + col_]); + } + } + + //! \~english Checks if the column contains the element `e`. + //! \~russian Проверяет, содержит ли столбец элемент `e`. + 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` в столбце. + 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`. + inline int entries(std::function 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`. + inline bool any(std::function 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`. + inline bool every(std::function test) const { + for (size_t i = 0; i < sz_; ++i) { + if (!test((*p_)[i * step_ + col_])) return false; + } + return true; + } }; //! \~english Returns a reference to the element at the given row and column. diff --git a/tests/math/testpivector2d.cpp b/tests/math/testpivector2d.cpp index 538348d7..aef6c86b 100644 --- a/tests/math/testpivector2d.cpp +++ b/tests/math/testpivector2d.cpp @@ -993,6 +993,243 @@ TEST(Vector2DEdgeTest, single_element_vector) { EXPECT_EQ(single.element(0, 0), 42); } +// ==================== PROXY ADDITIONAL OPERATIONS TESTS ==================== +TEST_F(Vector2DTest, row_proxy_forEach_modifies_elements) { + auto row = vec[5]; + row.forEach([](int & e) { e += 100; }); + for (size_t c = 0; c < COLS_COUNT_INIT; ++c) { + EXPECT_EQ(vec.element(5, c), 5 * COLS_COUNT_INIT + c + 100); + } +} + +TEST_F(Vector2DTest, row_proxy_forEach_const_iterates) { + const auto & constVec = vec; + auto row = constVec[5]; + size_t count = 0; + row.forEach([&count](const int &) { ++count; }); + EXPECT_EQ(count, COLS_COUNT_INIT); +} + +TEST_F(Vector2DTest, row_proxy_fill_sets_all_elements) { + auto row = vec[12]; + row.fill(999); + for (size_t c = 0; c < COLS_COUNT_INIT; ++c) { + EXPECT_EQ(vec.element(12, c), 999); + } +} + +TEST_F(Vector2DTest, row_proxy_contains_finds_element) { + auto row = vec[8]; + EXPECT_TRUE(row.contains(vec.element(8, 10))); + EXPECT_FALSE(row.contains(-999)); +} + +TEST_F(Vector2DTest, row_proxy_entries_counts_occurrences) { + auto row = vec[15]; + // Add a duplicate + int val = vec.element(15, 5); + vec.element(15, 20) = val; + EXPECT_EQ(row.entries(val), 2); + EXPECT_EQ(row.entries(-999), 0); +} + +TEST_F(Vector2DTest, row_proxy_entries_with_predicate_counts_matches) { + auto row = vec[20]; + auto isEven = [](const int & e) { return e % 2 == 0; }; + int expected = 0; + for (size_t c = 0; c < COLS_COUNT_INIT; ++c) { + if (row[c] % 2 == 0) ++expected; + } + EXPECT_EQ(row.entries(isEven), expected); +} + +TEST_F(Vector2DTest, row_proxy_any_returns_true_if_any_match) { + auto row = vec[25]; + auto isNegative = [](const int & e) { return e < 0; }; + EXPECT_FALSE(row.any(isNegative)); + auto isPositive = [](const int & e) { return e >= 0; }; + EXPECT_TRUE(row.any(isPositive)); +} + +TEST_F(Vector2DTest, row_proxy_every_returns_true_if_all_match) { + auto row = vec[30]; + auto isLessThanMax = [&](const int & e) { return e < static_cast(vec.size()); }; + EXPECT_TRUE(row.every(isLessThanMax)); + auto isEven = [](const int & e) { return e % 2 == 0; }; + EXPECT_FALSE(row.every(isEven)); +} + +// ---------------------------------------------------------------------------- +TEST_F(Vector2DTest, col_proxy_forEach_modifies_elements) { + auto col = vec.col(7); + col.forEach([](int & e) { e += 50; }); + for (size_t r = 0; r < ROWS_COUNT_INIT; ++r) { + EXPECT_EQ(vec.element(r, 7), r * COLS_COUNT_INIT + 7 + 50); + } +} + +TEST_F(Vector2DTest, col_proxy_forEach_const_iterates) { + const auto & constVec = vec; + auto col = constVec.col(9); + size_t count = 0; + col.forEach([&count](const int &) { ++count; }); + EXPECT_EQ(count, ROWS_COUNT_INIT); +} + +TEST_F(Vector2DTest, col_proxy_fill_sets_all_elements) { + auto col = vec.col(11); + col.fill(777); + for (size_t r = 0; r < ROWS_COUNT_INIT; ++r) { + EXPECT_EQ(vec.element(r, 11), 777); + } +} + +TEST_F(Vector2DTest, col_proxy_contains_finds_element) { + auto col = vec.col(13); + EXPECT_TRUE(col.contains(vec.element(5, 13))); + EXPECT_FALSE(col.contains(-999)); +} + +TEST_F(Vector2DTest, col_proxy_entries_counts_occurrences) { + auto col = vec.col(17); + int val = vec.element(3, 17); + vec.element(22, 17) = val; // duplicate + EXPECT_EQ(col.entries(val), 2); + EXPECT_EQ(col.entries(-999), 0); +} + +TEST_F(Vector2DTest, col_proxy_entries_with_predicate_counts_matches) { + auto col = vec.col(19); + auto isOdd = [](const int & e) { return e % 2 != 0; }; + int expected = 0; + for (size_t r = 0; r < ROWS_COUNT_INIT; ++r) { + if (col[r] % 2 != 0) ++expected; + } + EXPECT_EQ(col.entries(isOdd), expected); +} + +TEST_F(Vector2DTest, col_proxy_any_returns_true_if_any_match) { + auto col = vec.col(21); + auto isNegative = [](const int & e) { return e < 0; }; + EXPECT_FALSE(col.any(isNegative)); + auto isPositive = [](const int & e) { return e >= 0; }; + EXPECT_TRUE(col.any(isPositive)); +} + +TEST_F(Vector2DTest, col_proxy_every_returns_true_if_all_match) { + auto col = vec.col(23); + auto isLessThanMax = [&](const int & e) { return e < static_cast(vec.size()); }; + EXPECT_TRUE(col.every(isLessThanMax)); + auto isEven = [](const int & e) { return e % 2 == 0; }; + EXPECT_FALSE(col.every(isEven)); +} + +// ---------------------------------------------------------------------------- +TEST_F(Vector2DTest, rowconst_proxy_forEach_iterates) { + const auto & constVec = vec; + auto row = constVec[5]; + size_t count = 0; + row.forEach([&count](const int &) { ++count; }); + EXPECT_EQ(count, COLS_COUNT_INIT); +} + +TEST_F(Vector2DTest, rowconst_proxy_contains_finds_element) { + const auto & constVec = vec; + auto row = constVec[6]; + EXPECT_TRUE(row.contains(vec.element(6, 10))); + EXPECT_FALSE(row.contains(-999)); +} + +TEST_F(Vector2DTest, rowconst_proxy_entries_counts_occurrences) { + const auto & constVec = vec; + auto row = constVec[7]; + int val = vec.element(7, 5); + // We can't modify through const proxy, but duplicates already exist from previous tests + EXPECT_GE(row.entries(val), 1); // at least one +} + +TEST_F(Vector2DTest, rowconst_proxy_entries_with_predicate_counts_matches) { + const auto & constVec = vec; + auto row = constVec[9]; + auto isEven = [](const int & e) { return e % 2 == 0; }; + int expected = 0; + for (size_t c = 0; c < COLS_COUNT_INIT; ++c) { + if (vec.element(9, c) % 2 == 0) ++expected; + } + EXPECT_EQ(row.entries(isEven), expected); +} + +TEST_F(Vector2DTest, rowconst_proxy_any_returns_true_if_any_match) { + const auto & constVec = vec; + auto row = constVec[10]; + auto isNegative = [](const int & e) { return e < 0; }; + EXPECT_FALSE(row.any(isNegative)); + auto isPositive = [](const int & e) { return e >= 0; }; + EXPECT_TRUE(row.any(isPositive)); +} + +TEST_F(Vector2DTest, rowconst_proxy_every_returns_true_if_all_match) { + const auto & constVec = vec; + auto row = constVec[11]; + auto isLessThanMax = [&](const int & e) { return e < static_cast(vec.size()); }; + EXPECT_TRUE(row.every(isLessThanMax)); + auto isEven = [](const int & e) { return e % 2 == 0; }; + EXPECT_FALSE(row.every(isEven)); +} + +// ---------------------------------------------------------------------------- +TEST_F(Vector2DTest, colconst_proxy_forEach_iterates) { + const auto & constVec = vec; + auto col = constVec.col(25); + size_t count = 0; + col.forEach([&count](const int &) { ++count; }); + EXPECT_EQ(count, ROWS_COUNT_INIT); +} + +TEST_F(Vector2DTest, colconst_proxy_contains_finds_element) { + const auto & constVec = vec; + auto col = constVec.col(27); + EXPECT_TRUE(col.contains(vec.element(4, 27))); + EXPECT_FALSE(col.contains(-999)); +} + +TEST_F(Vector2DTest, colconst_proxy_entries_counts_occurrences) { + const auto & constVec = vec; + auto col = constVec.col(29); + int val = vec.element(8, 29); + EXPECT_GE(col.entries(val), 1); +} + +TEST_F(Vector2DTest, colconst_proxy_entries_with_predicate_counts_matches) { + const auto & constVec = vec; + auto col = constVec.col(31); + auto isOdd = [](const int & e) { return e % 2 != 0; }; + int expected = 0; + for (size_t r = 0; r < ROWS_COUNT_INIT; ++r) { + if (vec.element(r, 31) % 2 != 0) ++expected; + } + EXPECT_EQ(col.entries(isOdd), expected); +} + +TEST_F(Vector2DTest, colconst_proxy_any_returns_true_if_any_match) { + const auto & constVec = vec; + auto col = constVec.col(33); + auto isNegative = [](const int & e) { return e < 0; }; + EXPECT_FALSE(col.any(isNegative)); + auto isPositive = [](const int & e) { return e >= 0; }; + EXPECT_TRUE(col.any(isPositive)); +} + +TEST_F(Vector2DTest, colconst_proxy_every_returns_true_if_all_match) { + const auto & constVec = vec; + auto col = constVec.col(0); + auto isLessThanMax = [&](const int & e) { return e < static_cast(vec.size()); }; + EXPECT_TRUE(col.every(isLessThanMax)); + auto isNotEven = [](const int & e) { return e % 2 != 0; }; + col.forEach([](const int & v) { piCout << v; }); + EXPECT_FALSE(col.every(isNotEven)); +} + // ==================== OUTPUT TESTS ==================== TEST_F(Vector2DTest, picout_operator_works) { // Just test that it compiles and doesn't crash -- 2.43.0 From 7f894e77bb9dc62762643b1a6ed6979bf8c3148a Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Wed, 18 Feb 2026 13:46:09 +0300 Subject: [PATCH 02/29] add more tests --- tests/math/testpivector2d.cpp | 45 +++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tests/math/testpivector2d.cpp b/tests/math/testpivector2d.cpp index aef6c86b..29831aab 100644 --- a/tests/math/testpivector2d.cpp +++ b/tests/math/testpivector2d.cpp @@ -652,6 +652,51 @@ TEST_F(Vector2DTest, transposed_returns_correct_dimensions) { } } +TEST(Vector2DTransposeTest, emptyMatrix_returnsEmpty) { + PIVector2D empty; + auto transposed = empty.transposed(); + EXPECT_TRUE(transposed.isEmpty()); + EXPECT_EQ(transposed.rows(), 0); + EXPECT_EQ(transposed.cols(), 0); +} + +TEST(Vector2DTransposeTest, singleElement_returnsSame) { + PIVector2D single(1, 1, 42); + auto transposed = single.transposed(); + EXPECT_EQ(transposed.rows(), 1); + EXPECT_EQ(transposed.cols(), 1); + EXPECT_EQ(transposed.element(0, 0), 42); +} + +TEST(Vector2DTransposeTest, oneRow_becomesOneColumn) { + PIVector2D rowVec(1, 5); + for (size_t c = 0; c < 5; ++c) rowVec.element(0, c) = static_cast(c); + auto transposed = rowVec.transposed(); + EXPECT_EQ(transposed.rows(), 5); + EXPECT_EQ(transposed.cols(), 1); + for (size_t r = 0; r < 5; ++r) { + EXPECT_EQ(transposed.element(r, 0), static_cast(r)); + } +} + +TEST(Vector2DTransposeTest, oneColumn_becomesOneRow) { + PIVector2D colVec(5, 1); + for (size_t r = 0; r < 5; ++r) colVec.element(r, 0) = static_cast(r); + auto transposed = colVec.transposed(); + EXPECT_EQ(transposed.rows(), 1); + EXPECT_EQ(transposed.cols(), 5); + for (size_t c = 0; c < 5; ++c) { + EXPECT_EQ(transposed.element(0, c), static_cast(c)); + } +} + +TEST_F(Vector2DTest, transposed_doesNotModifyOriginal) { + auto original = vec; // копия для сравнения + auto transposed = vec.transposed(); + // Проверяем, что исходный массив не изменился + EXPECT_EQ(vec, original); +} + TEST_F(Vector2DTest, reverseRows_reverses_row_order) { auto original = vec; vec.reverseRows(); -- 2.43.0 From 95d3c9c658e568fc592593e1aab8d117187600d3 Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Wed, 18 Feb 2026 14:59:08 +0300 Subject: [PATCH 03/29] add more comments --- libs/main/containers/pivector2d.h | 411 +++++++++++++++++++++++++++--- 1 file changed, 375 insertions(+), 36 deletions(-) diff --git a/libs/main/containers/pivector2d.h b/libs/main/containers/pivector2d.h index 809277e8..a0abede9 100644 --- a/libs/main/containers/pivector2d.h +++ b/libs/main/containers/pivector2d.h @@ -47,26 +47,30 @@ //! строками можно работать как с объектами \a PIVector, что позволяет изменять отдельные элементы или присваивать целые строки. Нельзя //! напрямую добавлять или удалять элементы, чтобы изменить размеры массива после создания (используйте \a resize(), \a addRow(), \a //! removeRow(), \a removeColumn() для этого), но можно изменять значения существующих элементов. - +//! \sa PIVector template class PIVector2D { public: - //! \~english Constructs an empty 2D array. - //! \~russian Создает пустой двумерный массив. + //! \~english Constructs an empty 2D array. No memory is allocated. + //! \~russian Создаёт пустой двумерный массив. Память не выделяется. + //! \details + //! \~english After this constructor, \a rows() and \a cols() return 0, and \a isEmpty() returns true. + //! \~russian После этого конструктора \a rows() и \a cols() возвращают 0, а \a isEmpty() возвращает true. + //! \sa PIVector::PIVector() inline PIVector2D() { rows_ = cols_ = 0; } //! \~english Constructs a 2D array with the given dimensions, filled with copies of `f`. - //! \~russian Создает двумерный массив заданного размера, заполненный копиями `f`. + //! \~russian Создаёт двумерный массив заданного размера, заполненный копиями `f`. //! \param rows Number of rows. //! \param cols Number of columns. - //! \param f Value to fill the array with. - //! \~english \param rows Количество строк. - //! \~russian \param rows Количество строк. - //! \~english \param cols Количество столбцов. - //! \~russian \param cols Количество столбцов. - //! \~english \param f Значение для заполнения массива. - //! \~russian \param f Значение для заполнения массива. + //! \param f Value to fill the array with. Defaults to default-constructed T. + //! \details + //! \~english The underlying storage is a single contiguous block of memory of size `rows * cols`. + //! All elements are initialized with the value `f`. + //! \~russian Внутреннее хранилище представляет собой единый непрерывный блок памяти размером `rows * cols`. + //! Все элементы инициализируются значением `f`. + //! \sa PIVector::PIVector(size_t, const T&) inline PIVector2D(size_t rows, size_t cols, const T & f = T()) { rows_ = rows; cols_ = cols; @@ -74,10 +78,18 @@ public: } //! \~english Constructs a 2D array from an existing 1D vector, reshaping it. - //! \~russian Создает двумерный массив из существующего одномерного вектора, изменяя его форму. + //! \~russian Создаёт двумерный массив из существующего одномерного вектора, изменяя его форму. //! \param rows Number of rows. //! \param cols Number of columns. //! \param v The source 1D vector. Its size must be at least `rows * cols`. + //! \details + //! \~english The constructor copies the data from `v` into the internal flat vector. + //! If `v` is larger than `rows * cols`, the excess elements are ignored (the vector is truncated). + //! If `v` is smaller, the behaviour is undefined (an assertion may fail in debug mode). + //! \~russian Конструктор копирует данные из `v` во внутренний плоский вектор. + //! Если `v` больше, чем `rows * cols`, лишние элементы игнорируются (вектор обрезается). + //! Если `v` меньше, поведение не определено (в отладочном режиме может сработать assertion). + //! \sa PIVector::PIVector(const PIVector&), reshape() inline PIVector2D(size_t rows, size_t cols, const PIVector & v): rows_(rows), cols_(cols), mat(v) { mat.resize(rows * cols); } //! \~english Move constructs a 2D array from an existing 1D vector, reshaping it. @@ -85,11 +97,21 @@ 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`. + //! \details + //! \~english The data is moved from `v` into the internal flat vector, avoiding a copy. + //! After construction, `v` is left in a valid but unspecified state. + //! \~russian Данные перемещаются из `v` во внутренний плоский вектор, что позволяет избежать копирования. + //! После завершения конструктора `v` остаётся в корректном, но неопределённом состоянии. + //! \sa PIVector::PIVector(PIVector&&) inline PIVector2D(size_t rows, size_t cols, PIVector && 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. + //! \~russian Создаёт двумерный массив из вектора векторов (рваного массива). Предполагается, что все внутренние векторы имеют + //! одинаковый размер. \param v The source vector of vectors. \details + //! \~english If the input is empty, the constructed array is also empty. Otherwise, the number of columns is taken from the size of the + //! first inner vector. All inner vectors are concatenated in the internal flat storage. + //! \~russian Если входной массив пуст, создаётся пустой двумерный массив. В противном случае количество столбцов берётся из размера + //! первого внутреннего вектора. Все внутренние векторы конкатенируются во внутреннем плоском хранилище. \sa PIVector::append() inline PIVector2D(const PIVector> & v) { rows_ = v.size(); if (rows_) { @@ -103,36 +125,67 @@ public: if (mat.isEmpty()) rows_ = cols_ = 0; } - //! \~english Number of rows. - //! \~russian Количество строк. + //! \~english Returns the number of rows in the 2D array. + //! \~russian Возвращает количество строк в двумерном массиве. + //! \return Number of rows. + //! \details + //! \~english The result is always non-negative. If the array is empty, returns 0. + //! \~russian Результат всегда неотрицательный. Если массив пуст, возвращает 0. + //! \sa cols(), size(), PIVector::size() inline size_t rows() const { return rows_; } - //! \~english Number of columns. - //! \~russian Количество столбцов. + //! \~english Returns the number of columns in the 2D array. + //! \~russian Возвращает количество столбцов в двумерном массиве. + //! \return Number of columns. + //! \details + //! \~english The result is always non-negative. If the array is empty, returns 0. + //! \~russian Результат всегда неотрицательный. Если массив пуст, возвращает 0. + //! \sa rows(), size(), PIVector::size() inline size_t cols() const { return cols_; } - //! \~english Total number of elements (`rows * cols`). - //! \~russian Общее количество элементов (`строки * столбцы`). + //! \~english Returns the total number of elements (`rows * cols`). + //! \~russian Возвращает общее количество элементов (`строки * столбцы`). + //! \return Total number of elements. + //! \details + //! \~english This is equivalent to the size of the underlying flat vector. + //! \~russian Это эквивалентно размеру внутреннего плоского вектора. + //! \sa rows(), cols(), PIVector::size() inline size_t size() const { return mat.size(); } - //! \~english Total number of elements as signed value. - //! \~russian Общее количество элементов в виде знакового числа. + //! \~english Returns the total number of elements as a signed value. + //! \~russian Возвращает общее количество элементов в виде знакового числа. + //! \return Signed size. + //! \sa size(), PIVector::size_s() inline ssize_t size_s() const { return mat.size_s(); } - //! \~english Total number of elements. - //! \~russian Общее количество элементов. + //! \~english Returns the total number of elements (same as \a size()). + //! \~russian Возвращает общее количество элементов (то же, что и \a size()). + //! \return Total number of elements. + //! \sa size(), PIVector::length() inline size_t length() const { return mat.length(); } - //! \~english Number of elements that the underlying container has currently allocated space for. - //! \~russian Количество элементов, для которого сейчас выделена память во внутреннем контейнере. + //! \~english Returns the number of elements that the underlying container has currently allocated space for. + //! \~russian Возвращает количество элементов, для которого сейчас выделена память во внутреннем контейнере. + //! \return Capacity of the flat vector. + //! \details + //! \~english This value may be larger than \a size(). It indicates how many elements can be added before a reallocation is needed. + //! \~russian Это значение может быть больше, чем \a size(). Оно показывает, сколько элементов можно добавить до того, как потребуется + //! перераспределение памяти. \sa reserve(), PIVector::capacity() inline size_t capacity() const { return mat.capacity(); } //! \~english Checks if the array has no elements. //! \~russian Проверяет, пуст ли массив. + //! \return \c true if the array is empty, \c false otherwise. + //! \details + //! \~english An empty array has both rows and columns equal to 0. + //! \~russian Пустой массив имеет и строки, и столбцы равные 0. + //! \sa isNotEmpty(), PIVector::isEmpty() inline bool isEmpty() const { return mat.isEmpty(); } - //! \~english Checks if the array has elements. + //! \~english Checks if the array has at least one element. //! \~russian Проверяет, не пуст ли массив. + //! \return \c true if the array is not empty, \c false otherwise. + //! \sa isEmpty(), PIVector::isNotEmpty() inline bool isNotEmpty() const { return mat.isNotEmpty(); } @@ -140,6 +193,13 @@ public: //! \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; @@ -152,28 +212,55 @@ public: size_t st_, sz_; public: - //! \~english Size of the row (number of columns). - //! \~russian Размер строки (количество столбцов). + //! \~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 Доступ к элементу по заданному индексу столбца в строке. + //! \param index Column index (must be less than size()). + //! \return Reference to the element. + //! \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 Константный доступ к элементу по заданному индексу столбца в строке. + //! \param index Column index (must be less than size()). + //! \return Const reference to the element. + //! \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 Возвращает указатель на данные строки, начиная с опционального смещения. + //! \param index Offset within the row (default 0). + //! \return Pointer to the first element at the given offset. + //! \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 Возвращает константный указатель на данные строки, начиная с опционального смещения. + //! \param index Offset within the row (default 0). + //! \return Const pointer. + //! \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 Присваивает этой строке содержимое другой строки. + //! \param other Source row. + //! \return Reference to this row. + //! \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(sz_, other.sz_); @@ -183,6 +270,12 @@ public: //! \~english Assigns the contents of a \a PIVector to this row. //! \~russian Присваивает этой строке содержимое \a PIVector. + //! \param other Source vector. + //! \return Reference to this row. + //! \details + //! \~english Only the minimum of the row size and vector size is copied. + //! \~russian Копируется только минимум из размера строки и размера вектора. + //! \sa PIVector::operator= inline Row & operator=(const PIVector & other) { const size_t sz = piMin(sz_, other.size()); p_->_copyRaw(p_->data(st_), other.data(), sz); @@ -191,8 +284,19 @@ public: //! \~english Converts the row to a \a PIVector. //! \~russian Преобразует строку в \a PIVector. + //! \return A new \a PIVector containing a copy of the row elements. + //! \sa PIVector::PIVector(const T*, size_t) inline PIVector toVector() const { return PIVector(p_->data(st_), sz_); } + //! \~english Returns the first index of element `e` in the row, starting from `start`. + //! \~russian Возвращает первый индекс элемента `e` в строке, начиная с позиции `start`. + //! \param e Element to search for. + //! \param start Starting index (negative values count from the end). Default 0. + //! \return Index if found, -1 otherwise. + //! \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) { @@ -201,6 +305,12 @@ public: return -1; } + //! \~english Returns the last index of element `e` in the row, searching backwards from `start`. + //! \~russian Возвращает последний индекс элемента `e` в строке, выполняя поиск в обратном направлении от `start`. + //! \param e Element to search for. + //! \param start Starting index (negative values count from the end). Default -1 (last element). + //! \return Index if found, -1 otherwise. + //! \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) { @@ -209,6 +319,12 @@ public: return -1; } + //! \~english Returns the first index where the predicate `test` returns true, starting from `start`. + //! \~russian Возвращает первый индекс, для которого предикат `test` возвращает true, начиная с `start`. + //! \param test Predicate function: `bool(const T&)`. + //! \param start Starting index (negative values count from the end). Default 0. + //! \return Index if found, -1 otherwise. + //! \sa PIVector::indexWhere() inline ssize_t indexWhere(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; for (size_t i = (size_t)start; i < sz_; ++i) { @@ -217,6 +333,10 @@ public: return -1; } + //! \~english Returns the last index where the predicate `test` returns true, searching backwards from `start`. + //! \~russian Возвращает последний индекс, для которого предикат `test` возвращает true, выполняя поиск в обратном направлении от + //! `start`. \param test Predicate function: `bool(const T&)`. \param start Starting index (negative values count from the end). + //! Default -1. \return Index if found, -1 otherwise. \sa PIVector::lastIndexWhere() inline ssize_t lastIndexWhere(std::function 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) { @@ -227,6 +347,11 @@ public: //! \~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 func) { for (size_t i = 0; i < sz_; ++i) { func((*p_)[st_ + i]); @@ -235,6 +360,8 @@ public: //! \~english Applies a function to each element of the row (read-only). //! \~russian Применяет функцию к каждому элементу строки (только чтение). + //! \param func Function that takes a const reference to T. + //! \sa forEach (modifiable) inline void forEach(std::function func) const { for (size_t i = 0; i < sz_; ++i) { func((*p_)[st_ + i]); @@ -243,6 +370,8 @@ public: //! \~english Fills the row with copies of `value`. //! \~russian Заполняет строку копиями `value`. + //! \param value Value to fill with. + //! \sa PIVector::fill() inline void fill(const T & value) { for (size_t i = 0; i < sz_; ++i) { (*p_)[st_ + i] = value; @@ -251,10 +380,18 @@ public: //! \~english Checks if the row contains the element `e`. //! \~russian Проверяет, содержит ли строка элемент `e`. + //! \param e Element to check. + //! \param start Starting index (negative allowed). Default 0. + //! \return \c true if found, \c false otherwise. + //! \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` в строке. + //! \param e Element to count. + //! \param start Starting index (negative allowed). Default 0. + //! \return Number of occurrences. + //! \sa PIVector::entries() inline int entries(const T & e, ssize_t start = 0) const { if (start < 0) start = 0; int count = 0; @@ -266,6 +403,10 @@ public: //! \~english Counts elements in the row that pass the `test`. //! \~russian Подсчитывает элементы в строке, проходящие `test`. + //! \param test Predicate function. + //! \param start Starting index (negative allowed). Default 0. + //! \return Count of matching elements. + //! \sa PIVector::entries(std::function) inline int entries(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; int count = 0; @@ -277,6 +418,9 @@ public: //! \~english Tests if any element in the row passes the `test`. //! \~russian Проверяет, проходит ли какой-либо элемент в строке `test`. + //! \param test Predicate function. + //! \return \c true if at least one element satisfies the predicate. + //! \sa PIVector::any() inline bool any(std::function test) const { for (size_t i = 0; i < sz_; ++i) { if (test((*p_)[st_ + i])) return true; @@ -286,6 +430,9 @@ public: //! \~english Tests if all elements in the row pass the `test`. //! \~russian Проверяет, проходят ли все элементы в строке `test`. + //! \param test Predicate function. + //! \return \c true if all elements satisfy the predicate. + //! \sa PIVector::every() inline bool every(std::function test) const { for (size_t i = 0; i < sz_; ++i) { if (!test((*p_)[st_ + i])) return false; @@ -298,6 +445,11 @@ public: //! \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; @@ -311,12 +463,14 @@ public: size_t step_, col_, sz_; public: - //! \~english Size of the column (number of rows). - //! \~russian Размер столбца (количество строк). + //! \~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 Доступ к элементу по заданному индексу строки в столбце. + //! \param index Row index. + //! \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. @@ -325,6 +479,13 @@ public: //! \~english Returns a pointer to the column data starting at an optional row offset. //! \~russian Возвращает указатель на данные столбца, начиная с опционального смещения по строкам. + //! \param index Row offset (default 0). + //! \return Pointer to the element at the given row. + //! \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. @@ -333,6 +494,8 @@ public: //! \~english Assigns the contents of another Col to this column. //! \~russian Присваивает этому столбцу содержимое другого столбца. + //! \param other Source column. + //! \return Reference to this column. inline Col & operator=(const Col & other) { if (p_ == other.p_ && col_ == other.col_) return *this; const size_t sz = piMin(sz_, other.sz_); @@ -343,6 +506,8 @@ public: //! \~english Assigns the contents of a \a PIVector to this column. //! \~russian Присваивает этому столбцу содержимое \a PIVector. + //! \param other Source vector. + //! \return Reference to this column. inline Col & operator=(const PIVector & other) { const size_t sz = piMin(sz_, other.size()); for (size_t i = 0; i < sz; ++i) @@ -352,6 +517,7 @@ public: //! \~english Converts the column to a \a PIVector. //! \~russian Преобразует столбец в \a PIVector. + //! \return A new \a PIVector containing a copy of the column elements. inline PIVector toVector() const { PIVector ret; ret.reserve(sz_); @@ -360,6 +526,8 @@ public: return ret; } + //! \~english Returns the first index (row) where element `e` appears in the column. + //! \~russian Возвращает первый индекс (строку), в которой элемент `e` появляется в столбце. 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) { @@ -368,6 +536,7 @@ public: return -1; } + //! \~english Returns the last index (row) where element `e` appears in the column. 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) { @@ -376,6 +545,7 @@ public: return -1; } + //! \~english Returns the first row index where the predicate `test` returns true. inline ssize_t indexWhere(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; for (size_t i = (size_t)start; i < sz_; ++i) { @@ -384,6 +554,7 @@ public: return -1; } + //! \~english Returns the last row index where the predicate `test` returns true. inline ssize_t lastIndexWhere(std::function 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) { @@ -465,6 +636,10 @@ public: //! \brief //! \~english Proxy class representing a single read-only row in a \a PIVector2D. //! \~russian Прокси-класс, представляющий одну строку в \a PIVector2D только для чтения. + //! \details + //! \~english Returned by const \a operator[] or \a row(). Provides const access to row elements. + //! \~russian Возвращается константными версиями \a operator[] или \a row(). Предоставляет константный доступ к элементам строки. + //! \sa Row, ColConst class RowConst { friend class PIVector2D; @@ -501,6 +676,7 @@ public: return -1; } + //! \~english Searches for element `e` backwards (see Row::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) { @@ -509,6 +685,7 @@ public: return -1; } + //! \~english Searches with predicate (see Row::indexWhere). inline ssize_t indexWhere(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; for (size_t i = (size_t)start; i < sz_; ++i) { @@ -517,6 +694,7 @@ public: return -1; } + //! \~english Searches with predicate backwards (see Row::lastIndexWhere). inline ssize_t lastIndexWhere(std::function 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) { @@ -582,6 +760,10 @@ public: //! \brief //! \~english Proxy class representing a single read-only column in a \a PIVector2D. //! \~russian Прокси-класс, представляющий один столбец в \a PIVector2D только для чтения. + //! \details + //! \~english Returned by const \a col(). Provides const access to column elements. + //! \~russian Возвращается константной версией \a col(). Предоставляет константный доступ к элементам столбца. + //! \sa Col, RowConst class ColConst { friend class PIVector2D; @@ -617,6 +799,7 @@ public: return ret; } + //! \~english Searches for element `e` (see Col::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) { @@ -625,6 +808,7 @@ public: return -1; } + //! \~english Searches for element `e` backwards (see Col::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) { @@ -633,6 +817,7 @@ public: return -1; } + //! \~english Searches with predicate (see Col::indexWhere). inline ssize_t indexWhere(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; for (size_t i = (size_t)start; i < sz_; ++i) { @@ -641,6 +826,7 @@ public: return -1; } + //! \~english Searches with predicate backwards (see Col::lastIndexWhere). inline ssize_t lastIndexWhere(std::function 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) { @@ -704,6 +890,13 @@ public: //! \~english Returns a reference to the element at the given row and column. //! \~russian Возвращает ссылку на элемент по заданной строке и столбцу. + //! \param row Row index. + //! \param col Column index. + //! \return Reference to the element. + //! \details + //! \~english No bounds checking is performed. + //! \~russian Проверка границ не выполняется. + //! \sa at() (const version), PIVector::operator[] inline T & element(size_t row, size_t col) { return mat[row * cols_ + col]; } //! \~english Returns a const reference to the element at the given row and column. @@ -716,6 +909,9 @@ public: //! \~english Returns a proxy object for the row at the given index for modification. //! \~russian Возвращает прокси-объект для строки по заданному индексу для модификации. + //! \param index Row index. + //! \return Row proxy. + //! \sa row(), Col inline Row operator[](size_t index) { return Row(this, index); } //! \~english Returns a proxy object for the row at the given index for read-only access. @@ -724,6 +920,9 @@ public: //! \~english Returns a pointer to the underlying flat data starting at an optional offset. //! \~russian Возвращает указатель на внутренние плоские данные, начиная с опционального смещения. + //! \param index Flat index offset. + //! \return Pointer to data. + //! \sa PIVector::data() inline T * data(size_t index = 0) { return mat.data(index); } //! \~english Returns a const pointer to the underlying flat data starting at an optional offset. @@ -733,6 +932,7 @@ public: //! \~english Returns a proxy object for the row at the given index for modification. //! \~russian Возвращает прокси-объект для строки по заданному индексу для модификации. + //! \sa operator[] inline Row row(size_t index) { return Row(this, index); } //! \~english Returns a proxy object for the row at the given index for read-only access. @@ -741,6 +941,9 @@ public: //! \~english Returns a proxy object for the column at the given index for modification. //! \~russian Возвращает прокси-объект для столбца по заданному индексу для модификации. + //! \param index Column index. + //! \return Column proxy. + //! \sa col() const inline Col col(size_t index) { return Col(this, index); } //! \~english Returns a proxy object for the column at the given index for read-only access. @@ -750,6 +953,9 @@ public: //! \~english Replaces a row with the contents of another Row object. //! \~russian Заменяет строку содержимым другого объекта Row. + //! \param row Row index. + //! \param other Source row. + //! \return Reference to this 2D array. inline PIVector2D & setRow(size_t row, const Row & other) { const size_t sz = piMin(cols_, other.sz_); mat._copyRaw(mat.data(cols_ * row), other.data(), sz); @@ -774,6 +980,14 @@ public: //! \~english Appends a new row to the bottom of the array from another Row object. //! \~russian Добавляет новую строку в конец массива из другого объекта Row. + //! \param other Source row. + //! \return Reference to this array. + //! \details + //! \~english If the array was empty, its column count is set to the size of the source row. + //! Otherwise, only `min(cols(), other.size())` elements are copied; the rest of the new row is default-initialized. + //! \~russian Если массив был пуст, количество столбцов устанавливается равным размеру исходной строки. + //! В противном случае копируется только `min(cols(), other.size())` элементов; остальные элементы новой строки инициализируются по + //! умолчанию. \sa PIVector::push_back() inline PIVector2D & addRow(const Row & other) { if (cols_ == 0) cols_ = other.sz_; const size_t sz = piMin(cols_, other.sz_); @@ -810,11 +1024,20 @@ public: //! \~english Resizes the 2D array to new dimensions. //! \~russian Изменяет размер двумерного массива. + //! \param rows New number of rows. + //! \param cols New number of columns. + //! \param f Value to fill newly created elements (if growing). Defaults to default-constructed T. + //! \return Reference to this array. //! \details - //! \~english If the new dimensions are larger, new elements are filled with `f`. - //! If they are smaller, the array is truncated. - //! \~russian Если новые размеры больше, новые элементы заполняются `f`. - //! Если они меньше, массив обрезается. + //! \~english If the new dimensions are larger, new elements are appended and filled with copies of `f`. + //! If they are smaller, the array is truncated (excess elements are destroyed). The underlying memory may be reallocated. + //! \~russian Если новые размеры больше текущих, новые элементы добавляются в конец и заполняются копиями `f`. + //! Если новые размеры меньше, массив усекается (лишние элементы уничтожаются). Внутренняя память может быть перераспределена. + //! \code + //! PIVector2D mat(2, 3, 0); // 2x3 matrix filled with 0 + //! mat.resize(3, 4, 1); // becomes 3x4, new elements filled with 1 + //! \endcode + //! \sa PIVector::resize() inline PIVector2D & resize(size_t rows, size_t cols, const T & f = T()) { if (rows == rows_ && cols == cols_) return *this; PIVector2D tmp(rows, cols, f); @@ -831,6 +1054,9 @@ public: //! \~english Equality operator. //! \~russian Оператор равенства. + //! \param t Another 2D array. + //! \return \c true if both arrays have the same dimensions and all elements are equal. + //! \sa PIVector::operator== inline bool operator==(const PIVector2D & t) const { if (cols_ != t.cols_ || rows_ != t.rows_) return false; return mat == t.mat; @@ -842,6 +1068,11 @@ public: //! \~english Converts the 2D array to a vector of vectors (PIVector>). //! \~russian Преобразует двумерный массив в вектор векторов (PIVector>). + //! \return A new vector where each element is a \a PIVector representing a row. + //! \details + //! \~english Each row vector is a copy of the corresponding row. + //! \~russian Каждый вектор-строка является копией соответствующей строки. + //! \sa fromVectors(), PIVector::PIVector(const T*, size_t) inline PIVector> toVectors() const { PIVector> ret; ret.reserve(rows_); @@ -864,6 +1095,11 @@ public: //! \~english Swaps this 2D array with another. //! \~russian Меняет местами этот двумерный массив с другим. + //! \param other Another array. + //! \details + //! \~english Swaps the flat vectors and the dimension members. Very fast, no memory allocation. + //! \~russian Обменивает внутренние плоские векторы и члены, хранящие размеры. Очень быстро, без выделения памяти. + //! \sa PIVector::swap() inline void swap(PIVector2D & other) { mat.swap(other.mat); piSwap(rows_, other.rows_); @@ -881,6 +1117,10 @@ public: //! \~english Clears the array, removing all elements and setting dimensions to 0. //! \~russian Очищает массив, удаляя все элементы и устанавливая размеры в 0. + //! \details + //! \~english The capacity of the underlying flat vector may remain unchanged. + //! \~russian Ёмкость внутреннего плоского вектора может остаться неизменной. + //! \sa PIVector::clear() inline void clear() { rows_ = cols_ = 0; mat.clear(); @@ -889,23 +1129,31 @@ public: //! \~english Checks if the underlying flat vector contains the element `e`. //! \~russian Проверяет, содержит ли внутренний плоский вектор элемент `e`. + //! \sa PIVector::contains() inline bool contains(const T & e, ssize_t start = 0) const { return mat.contains(e, start); } //! \~english Checks if the underlying flat vector contains all elements of `v`. //! \~russian Проверяет, содержит ли внутренний плоский вектор все элементы `v`. + //! \sa PIVector::contains(const PIVector&) inline bool contains(const PIVector & v, ssize_t start = 0) const { return mat.contains(v, start); } //! \~english Counts occurrences of `e` in the underlying flat vector. //! \~russian Подсчитывает количество вхождений `e` во внутреннем плоском векторе. + //! \sa PIVector::entries() inline int entries(const T & e, ssize_t start = 0) const { return mat.entries(e, start); } //! \~english Counts elements in the flat vector that pass the `test`. //! \~russian Подсчитывает элементы в плоском векторе, проходящие `test`. + //! \sa PIVector::entries(std::function) inline int entries(std::function test, ssize_t start = 0) const { return mat.entries(test, start); } //! \~english Returns the first index (row, col) of `e` in the 2D array. //! \~russian Возвращает первый индекс (строка, столбец) элемента `e` в двумерном массиве. + //! \param e Element to search for. + //! \param start Starting flat index (negative allowed). Default 0. + //! \return A \a PIPair where first is row, second is column. If not found, both are -1. + //! \sa PIVector::indexOf() inline PIPair indexOf(const T & e, ssize_t start = 0) const { ssize_t flat = mat.indexOf(e, start); if (flat < 0 || cols_ == 0) return PIPair(-1, -1); @@ -914,6 +1162,7 @@ public: //! \~english Returns the first index (row, col) in the 2D array that passes the `test`. //! \~russian Возвращает первый индекс (строка, столбец) в двумерном массиве, проходящий `test`. + //! \sa PIVector::indexWhere() inline PIPair indexWhere(std::function test, ssize_t start = 0) const { ssize_t flat = mat.indexWhere(test, start); if (flat < 0 || cols_ == 0) return PIPair(-1, -1); @@ -922,6 +1171,7 @@ public: //! \~english Returns the last index (row, col) of `e` in the 2D array. //! \~russian Возвращает последний индекс (строка, столбец) элемента `e` в двумерном массиве. + //! \sa PIVector::lastIndexOf() inline PIPair lastIndexOf(const T & e, ssize_t start = -1) const { ssize_t flat = mat.lastIndexOf(e, start); if (flat < 0 || cols_ == 0) return PIPair(-1, -1); @@ -930,6 +1180,7 @@ public: //! \~english Returns the last index (row, col) in the 2D array that passes the `test`. //! \~russian Возвращает последний индекс (строка, столбец) в двумерном массиве, проходящий `test`. + //! \sa PIVector::lastIndexWhere() inline PIPair lastIndexWhere(std::function test, ssize_t start = -1) const { ssize_t flat = mat.lastIndexWhere(test, start); if (flat < 0 || cols_ == 0) return PIPair(-1, -1); @@ -939,14 +1190,18 @@ public: //! \~english Tests if any element in the flat vector passes the `test`. //! \~russian Проверяет, проходит ли какой-либо элемент в плоском векторе `test`. + //! \sa PIVector::any() inline bool any(std::function test) const { return mat.any(test); } //! \~english Tests if all elements in the flat vector pass the `test`. //! \~russian Проверяет, проходят ли все элементы в плоском векторе `test`. + //! \sa PIVector::every() inline bool every(std::function test) const { return mat.every(test); } //! \~english Fills the entire 2D array with copies of `e`. //! \~russian Заполняет весь двумерный массив копиями `e`. + //! \return Reference to this array. + //! \sa PIVector::fill() inline PIVector2D & fill(const T & e = T()) { mat.fill(e); return *this; @@ -954,6 +1209,9 @@ public: //! \~english Fills the entire 2D array using a generator function `f` based on flat index. //! \~russian Заполняет весь двумерный массив, используя функцию-генератор `f` на основе плоского индекса. + //! \param f Function taking a size_t flat index and returning a value of type T. + //! \return Reference to this array. + //! \sa PIVector::fill(std::function) inline PIVector2D & fill(std::function f) { mat.fill(f); return *this; @@ -965,6 +1223,7 @@ public: //! \~english Assigns new size and fills with value. //! \~russian Задаёт новый размер и заполняет значением. + //! \sa PIVector::assign(size_t, const T&) inline PIVector2D & assign(size_t rows, size_t cols, const T & f = T()) { mat.assign(rows * cols, f); rows_ = rows; @@ -973,9 +1232,16 @@ public: } - // TODO: исправить - при транспонировании количество строк становится количеством столбцов и наоборот //! \~english Returns a transposed 2D array (rows become columns and vice versa). //! \~russian Возвращает транспонированный двумерный массив (строки становятся столбцами и наоборот). + //! \return A new 2D array with dimensions (cols, rows). + //! \details + //! \~english The element at (r, c) in the original becomes at (c, r) in the result. + //! \~russian Элемент (r, c) исходного массива становится элементом (c, r) в результате. + //! \code + //! PIVector2D mat(2, 3, ...); + //! auto t = mat.transposed(); // now 3x2 + //! \endcode inline PIVector2D transposed() const { if (isEmpty()) return PIVector2D(); PIVector2D result(cols_, rows_); @@ -989,6 +1255,8 @@ public: //! \~english Reverses the order of rows in place. //! \~russian Изменяет порядок строк на обратный на месте. + //! \return Reference to this array. + //! \sa reverseColumns(), PIVector::reverse() inline PIVector2D & reverseRows() { const size_t half = rows_ / 2; for (size_t i = 0; i < half; ++i) { @@ -1003,6 +1271,8 @@ public: //! \~english Reverses the order of columns in each row in place. //! \~russian Изменяет порядок столбцов в каждой строке на обратный на месте. + //! \return Reference to this array. + //! \sa reverseRows(), PIVector::reverse() inline PIVector2D & reverseColumns() { for (size_t r = 0; r < rows_; ++r) { Row currentRow = row(r); @@ -1016,6 +1286,15 @@ public: //! \~english Returns a sub-2D array (a range of rows and columns). //! \~russian Возвращает подмассив (диапазон строк и столбцов). + //! \param rowStart Starting row index. + //! \param rowCount Number of rows to take. + //! \param colStart Starting column index. + //! \param colCount Number of columns to take. + //! \return A new 2D array containing the specified range. + //! \details + //! \~english If the range exceeds the array boundaries, it is clipped. If rowCount or colCount is 0, an empty array is returned. + //! \~russian Если диапазон выходит за границы массива, он обрезается. Если rowCount или colCount равны 0, возвращается пустой массив. + //! \sa PIVector::getRange() inline PIVector2D 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(); size_t actualRowCount = piMin(rowCount, rows_ - rowStart); @@ -1032,6 +1311,13 @@ public: //! \~english Applies a function to each element and returns a new 2D array of a different type. //! \~russian Применяет функцию к каждому элементу и возвращает новый двумерный массив другого типа. + //! \tparam ST Target element type. + //! \param f Mapping function: `ST(const T&)`. + //! \return A new \a PIVector2D with the same dimensions. + //! \details + //! \~english The original array is not modified. + //! \~russian Исходный массив не изменяется. + //! \sa PIVector::map() template inline PIVector2D map(std::function f) const { return PIVector2D(rows_, cols_, mat.template map(f)); @@ -1039,6 +1325,10 @@ public: //! \~english Applies a function (with row and col indices) to each element and returns a new 2D array. //! \~russian Применяет функцию (с индексами строки и столбца) к каждому элементу и возвращает новый двумерный массив. + //! \tparam ST Target element type. + //! \param f Function: `ST(size_t row, size_t col, const T&)`. + //! \return A new \a PIVector2D. + //! \sa PIVector::mapIndexed() template inline PIVector2D mapIndexed(std::function f) const { PIVector mappedMat; @@ -1054,6 +1344,9 @@ public: // --- Итерация по строкам и столбцам --- //! \~english Applies a function to each row (modifiable). //! \~russian Применяет функцию к каждой строке (с возможностью изменения). + //! \param f Function taking a \a Row. + //! \return Reference to this array. + //! \sa forEachRow() const, PIVector::forEach() inline PIVector2D & forEachRow(std::function f) { for (size_t r = 0; r < rows_; ++r) f(row(r)); @@ -1061,12 +1354,15 @@ public: } //! \~english Applies a function to each row (read-only). //! \~russian Применяет функцию к каждой строке (только чтение). + //! \param f Function taking a \a RowConst. inline void forEachRow(std::function f) const { for (size_t r = 0; r < rows_; ++r) f(row(r)); } //! \~english Applies a function to each column (modifiable). //! \~russian Применяет функцию к каждому столбцу (с возможностью изменения). + //! \param f Function taking a \a Col. + //! \return Reference to this array. inline PIVector2D & forEachColumn(std::function f) { for (size_t c = 0; c < cols_; ++c) f(col(c)); @@ -1074,6 +1370,7 @@ public: } //! \~english Applies a function to each column (read-only). //! \~russian Применяет функцию к каждому столбцу (только чтение). + //! \param f Function taking a \a ColConst. inline void forEachColumn(std::function f) const { for (size_t c = 0; c < cols_; ++c) f(col(c)); @@ -1081,6 +1378,11 @@ public: //! \~english Accumulates a value across all elements. //! \~russian Аккумулирует значение по всем элементам. + //! \tparam ST Accumulator type. + //! \param f Reduction function: `ST(const T&, const ST&)`. + //! \param initial Initial accumulator value. Defaults to default-constructed ST. + //! \return The accumulated result. + //! \sa PIVector::reduce() template inline ST reduce(std::function f, const ST & initial = ST()) const { return mat.template reduce(f, initial); @@ -1088,6 +1390,11 @@ public: //! \~english Accumulates a value across all elements with indices. //! \~russian Аккумулирует значение по всем элементам с индексами. + //! \tparam ST Accumulator type. + //! \param f Function: `ST(size_t row, size_t col, const T&, const ST&)`. + //! \param initial Initial accumulator value. + //! \return The accumulated result. + //! \sa PIVector::reduceIndexed() template inline ST reduceIndexed(std::function f, const ST & initial = ST()) const { ST ret(initial); @@ -1101,6 +1408,14 @@ public: //! \~english Removes a row from the 2D array. //! \~russian Удаляет строку из двумерного массива. + //! \param row Index of row to remove (must be less than rows()). + //! \return Reference to this array. + //! \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. + //! \sa removeColumn(), PIVector::remove() inline PIVector2D & removeRow(size_t row) { if (row >= rows_) return *this; size_t startIdx = row * cols_; @@ -1112,6 +1427,12 @@ public: //! \~english Removes a column from the 2D array. //! \~russian Удаляет столбец из двумерного массива. + //! \param col Index of column to remove (must be less than cols()). + //! \return Reference to this array. + //! \details + //! \~english This operation is more expensive than removing a row because elements must be moved. + //! \~russian Эта операция дороже, чем удаление строки, поскольку требуется перемещение элементов. + //! \sa removeRow(), PIVector::remove() inline PIVector2D & removeColumn(size_t col) { if (col >= cols_ || rows_ == 0) return *this; PIVector2D result(rows_, cols_ - 1); @@ -1127,6 +1448,12 @@ public: //! \~english Removes all rows that satisfy a condition. //! \~russian Удаляет все строки, удовлетворяющие условию. + //! \param test Predicate taking a \a RowConst. + //! \return Reference to this array. + //! \details + //! \~english Rows are removed from the bottom to avoid index shifting issues. + //! \~russian Строки удаляются снизу вверх, чтобы избежать проблем со смещением индексов. + //! \sa removeColumnsWhere(), PIVector::removeWhere() inline PIVector2D & removeRowsWhere(std::function test) { ssize_t r = rows_ - 1; while (r >= 0) { @@ -1140,6 +1467,9 @@ public: //! \~english Removes all columns that satisfy a condition. //! \~russian Удаляет все столбцы, удовлетворяющие условию. + //! \param test Predicate taking a \a ColConst. + //! \return Reference to this array. + //! \sa removeRowsWhere() inline PIVector2D & removeColumnsWhere(std::function test) { ssize_t c = cols_ - 1; while (c >= 0) { @@ -1154,6 +1484,9 @@ public: //! \~english Returns a new 2D array containing only the rows that pass the test. //! \~russian Возвращает новый двумерный массив, содержащий только строки, прошедшие проверку. + //! \param test Predicate taking a \a RowConst. + //! \return Filtered array. + //! \sa filterColumns(), PIVector::filter() inline PIVector2D filterRows(std::function test) const { PIVector2D result; for (size_t r = 0; r < rows_; ++r) { @@ -1167,6 +1500,9 @@ public: //! \~english Returns a new 2D array containing only the columns that pass the test. //! \~russian Возвращает новый двумерный массив, содержащий только столбцы, прошедшие проверку. + //! \param test Predicate taking a \a ColConst. + //! \return Filtered array. + //! \sa filterRows() inline PIVector2D filterColumns(std::function test) const { if (isEmpty()) return PIVector2D(); PIVector goodCols; @@ -1186,6 +1522,9 @@ public: //! \~english Returns a new 2D array (as a single row) containing only the elements that pass the test. //! \~russian Возвращает новый двумерный массив (в виде одной строки), содержащий только элементы, прошедшие проверку. + //! \param test Predicate taking a const T&. + //! \return A 1xN 2D array with the filtered elements (or empty). + //! \sa PIVector::filter() inline PIVector2D filterElements(std::function test) const { PIVector filtered = mat.filter(test); if (filtered.isEmpty()) return PIVector2D(); -- 2.43.0 From 52c400915dab1ed2a46a47c4c08149b0d0248102 Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Wed, 18 Feb 2026 17:09:26 +0300 Subject: [PATCH 04/29] fix doc --- libs/main/containers/pivector2d.h | 180 +++++++++++++++++++++++++++--- 1 file changed, 164 insertions(+), 16 deletions(-) diff --git a/libs/main/containers/pivector2d.h b/libs/main/containers/pivector2d.h index a0abede9..895f7293 100644 --- a/libs/main/containers/pivector2d.h +++ b/libs/main/containers/pivector2d.h @@ -43,11 +43,11 @@ //! (use \a resize(), \a addRow(), \a removeRow(), \a removeColumn() instead), but you can modify the values of existing elements. //! \~russian //! Этот класс используется для хранения двумерного массива элементов любого типа в виде единого непрерывного блока памяти (обычного -//! PIVector). Доступ к элементам осуществляется с помощью операторов `[][]`, где первый индекс — это строка, а второй — столбец. Со +//! \a PIVector). Доступ к элементам осуществляется с помощью операторов `[][]`, где первый индекс — это строка, а второй — столбец. Со //! строками можно работать как с объектами \a PIVector, что позволяет изменять отдельные элементы или присваивать целые строки. Нельзя //! напрямую добавлять или удалять элементы, чтобы изменить размеры массива после создания (используйте \a resize(), \a addRow(), \a //! removeRow(), \a removeColumn() для этого), но можно изменять значения существующих элементов. -//! \sa PIVector + template class PIVector2D { @@ -85,10 +85,10 @@ public: //! \details //! \~english The constructor copies the data from `v` into the internal flat vector. //! If `v` is larger than `rows * cols`, the excess elements are ignored (the vector is truncated). - //! If `v` is smaller, the behaviour is undefined (an assertion may fail in debug mode). + //! If `v` is smaller, other values filled whith default cunstructor T() //! \~russian Конструктор копирует данные из `v` во внутренний плоский вектор. //! Если `v` больше, чем `rows * cols`, лишние элементы игнорируются (вектор обрезается). - //! Если `v` меньше, поведение не определено (в отладочном режиме может сработать assertion). + //! Если `v` меньше, остальные значения будут заполнены из конструктора по умолчанию T() //! \sa PIVector::PIVector(const PIVector&), reshape() inline PIVector2D(size_t rows, size_t cols, const PIVector & v): rows_(rows), cols_(cols), mat(v) { mat.resize(rows * cols); } @@ -361,6 +361,9 @@ public: //! \~english Applies a function to each element of the row (read-only). //! \~russian Применяет функцию к каждому элементу строки (только чтение). //! \param func Function that takes a const reference to T. + //! \details + //! \~english The function can't modify the elements. + //! \~russian Функция не может изменять элементы. //! \sa forEach (modifiable) inline void forEach(std::function func) const { for (size_t i = 0; i < sz_; ++i) { @@ -526,8 +529,15 @@ public: return ret; } - //! \~english Returns the first index (row) where element `e` appears in the column. - //! \~russian Возвращает первый индекс (строку), в которой элемент `e` появляется в столбце. + //! \~english Returns the first index of element `e` in the row, starting from `start`. + //! \~russian Возвращает первый индекс элемента `e` в строке, начиная с позиции `start`. + //! \param e Element to search for. + //! \param start Starting index (negative values count from the end). Default 0. + //! \return Index if found, -1 otherwise. + //! \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) { @@ -536,7 +546,12 @@ public: return -1; } - //! \~english Returns the last index (row) where element `e` appears in the column. + //! \~english Returns the last index of element `e` in the row, searching backwards from `start`. + //! \~russian Возвращает последний индекс элемента `e` в строке, выполняя поиск в обратном направлении от `start`. + //! \param e Element to search for. + //! \param start Starting index (negative values count from the end). Default -1 (last element). + //! \return Index if found, -1 otherwise. + //! \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) { @@ -545,7 +560,12 @@ public: return -1; } - //! \~english Returns the first row index where the predicate `test` returns true. + //! \~english Returns the first index where the predicate `test` returns true, starting from `start`. + //! \~russian Возвращает первый индекс, для которого предикат `test` возвращает true, начиная с `start`. + //! \param test Predicate function: `bool(const T&)`. + //! \param start Starting index (negative values count from the end). Default 0. + //! \return Index if found, -1 otherwise. + //! \sa PIVector::indexWhere() inline ssize_t indexWhere(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; for (size_t i = (size_t)start; i < sz_; ++i) { @@ -554,7 +574,10 @@ public: return -1; } - //! \~english Returns the last row index where the predicate `test` returns true. + //! \~english Returns the last index where the predicate `test` returns true, searching backwards from `start`. + //! \~russian Возвращает последний индекс, для которого предикат `test` возвращает true, выполняя поиск в обратном направлении от + //! `start`. \param test Predicate function: `bool(const T&)`. \param start Starting index (negative values count from the end). + //! Default -1. \return Index if found, -1 otherwise. \sa PIVector::lastIndexWhere() inline ssize_t lastIndexWhere(std::function 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) { @@ -565,6 +588,11 @@ public: //! \~english Applies a function to each element of the column (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 func) { for (size_t i = 0; i < sz_; ++i) { func((*p_)[i * step_ + col_]); @@ -573,6 +601,11 @@ public: //! \~english Applies a function to each element of the column (read-only). //! \~russian Применяет функцию к каждому элементу столбца (только чтение). + //! \param func Function that takes a const reference to T. + //! \details + //! \~english The function can't modify the elements. + //! \~russian Функция не может изменять элементы. + //! \sa forEach (modifiable) inline void forEach(std::function func) const { for (size_t i = 0; i < sz_; ++i) { func((*p_)[i * step_ + col_]); @@ -581,6 +614,8 @@ public: //! \~english Fills the column with copies of `value`. //! \~russian Заполняет столбец копиями `value`. + //! \param value Value to fill with. + //! \sa PIVector::fill() inline void fill(const T & value) { for (size_t i = 0; i < sz_; ++i) { (*p_)[i * step_ + col_] = value; @@ -589,10 +624,18 @@ public: //! \~english Checks if the column contains the element `e`. //! \~russian Проверяет, содержит ли столбец элемент `e`. + //! \param e Element to check. + //! \param start Starting index (negative allowed). Default 0. + //! \return \c true if found, \c false otherwise. + //! \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` в столбце. + //! \param e Element to count. + //! \param start Starting index (negative allowed). Default 0. + //! \return Number of occurrences. + //! \sa PIVector::entries() inline int entries(const T & e, ssize_t start = 0) const { if (start < 0) start = 0; int count = 0; @@ -604,6 +647,10 @@ public: //! \~english Counts elements in the column that pass the `test`. //! \~russian Подсчитывает элементы в столбце, проходящие `test`. + //! \param test Predicate function. + //! \param start Starting index (negative allowed). Default 0. + //! \return Count of matching elements. + //! \sa PIVector::entries(std::function) inline int entries(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; int count = 0; @@ -615,6 +662,9 @@ public: //! \~english Tests if any element in the column passes the `test`. //! \~russian Проверяет, проходит ли какой-либо элемент в столбце `test`. + //! \param test Predicate function. + //! \return \c true if at least one element satisfies the predicate. + //! \sa PIVector::any() inline bool any(std::function test) const { for (size_t i = 0; i < sz_; ++i) { if (test((*p_)[i * step_ + col_])) return true; @@ -624,6 +674,9 @@ public: //! \~english Tests if all elements in the column pass the `test`. //! \~russian Проверяет, проходят ли все элементы в столбце `test`. + //! \param test Predicate function. + //! \return \c true if all elements satisfy the predicate. + //! \sa PIVector::every() inline bool every(std::function test) const { for (size_t i = 0; i < sz_; ++i) { if (!test((*p_)[i * step_ + col_])) return false; @@ -668,6 +721,15 @@ public: //! \~russian Преобразует строку в \a PIVector. inline PIVector toVector() const { return PIVector(p_->data(st_), sz_); } + //! \~english Returns the first index of element `e` in the row, starting from `start`. + //! \~russian Возвращает первый индекс элемента `e` в строке, начиная с позиции `start`. + //! \param e Element to search for. + //! \param start Starting index (negative values count from the end). Default 0. + //! \return Index if found, -1 otherwise. + //! \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) { @@ -676,7 +738,12 @@ public: return -1; } - //! \~english Searches for element `e` backwards (see Row::lastIndexOf). + //! \~english Returns the last index of element `e` in the row, searching backwards from `start`. + //! \~russian Возвращает последний индекс элемента `e` в строке, выполняя поиск в обратном направлении от `start`. + //! \param e Element to search for. + //! \param start Starting index (negative values count from the end). Default -1 (last element). + //! \return Index if found, -1 otherwise. + //! \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) { @@ -685,7 +752,12 @@ public: return -1; } - //! \~english Searches with predicate (see Row::indexWhere). + //! \~english Returns the first index where the predicate `test` returns true, starting from `start`. + //! \~russian Возвращает первый индекс, для которого предикат `test` возвращает true, начиная с `start`. + //! \param test Predicate function: `bool(const T&)`. + //! \param start Starting index (negative values count from the end). Default 0. + //! \return Index if found, -1 otherwise. + //! \sa PIVector::indexWhere() inline ssize_t indexWhere(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; for (size_t i = (size_t)start; i < sz_; ++i) { @@ -694,7 +766,10 @@ public: return -1; } - //! \~english Searches with predicate backwards (see Row::lastIndexWhere). + //! \~english Returns the last index where the predicate `test` returns true, searching backwards from `start`. + //! \~russian Возвращает последний индекс, для которого предикат `test` возвращает true, выполняя поиск в обратном направлении от + //! `start`. \param test Predicate function: `bool(const T&)`. \param start Starting index (negative values count from the end). + //! Default -1. \return Index if found, -1 otherwise. \sa PIVector::lastIndexWhere() inline ssize_t lastIndexWhere(std::function 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) { @@ -705,6 +780,11 @@ public: //! \~english Applies a function to each element of the row (read-only). //! \~russian Применяет функцию к каждому элементу строки (только чтение). + //! \param func Function that takes a const reference to T. + //! \details + //! \~english The function can't modify the elements. + //! \~russian Функция не может изменять элементы. + //! \sa forEach (modifiable) inline void forEach(std::function func) const { for (size_t i = 0; i < sz_; ++i) { func((*p_)[st_ + i]); @@ -713,10 +793,18 @@ public: //! \~english Checks if the row contains the element `e`. //! \~russian Проверяет, содержит ли строка элемент `e`. + //! \param e Element to check. + //! \param start Starting index (negative allowed). Default 0. + //! \return \c true if found, \c false otherwise. + //! \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` в строке. + //! \param e Element to count. + //! \param start Starting index (negative allowed). Default 0. + //! \return Number of occurrences. + //! \sa PIVector::entries() inline int entries(const T & e, ssize_t start = 0) const { if (start < 0) start = 0; int count = 0; @@ -728,6 +816,10 @@ public: //! \~english Counts elements in the row that pass the `test`. //! \~russian Подсчитывает элементы в строке, проходящие `test`. + //! \param test Predicate function. + //! \param start Starting index (negative allowed). Default 0. + //! \return Count of matching elements. + //! \sa PIVector::entries(std::function) inline int entries(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; int count = 0; @@ -739,6 +831,9 @@ public: //! \~english Tests if any element in the row passes the `test`. //! \~russian Проверяет, проходит ли какой-либо элемент в строке `test`. + //! \param test Predicate function. + //! \return \c true if at least one element satisfies the predicate. + //! \sa PIVector::any() inline bool any(std::function test) const { for (size_t i = 0; i < sz_; ++i) { if (test((*p_)[st_ + i])) return true; @@ -748,6 +843,9 @@ public: //! \~english Tests if all elements in the row pass the `test`. //! \~russian Проверяет, проходят ли все элементы в строке `test`. + //! \param test Predicate function. + //! \return \c true if all elements satisfy the predicate. + //! \sa PIVector::every() inline bool every(std::function test) const { for (size_t i = 0; i < sz_; ++i) { if (!test((*p_)[st_ + i])) return false; @@ -799,7 +897,15 @@ public: return ret; } - //! \~english Searches for element `e` (see Col::indexOf). + //! \~english Returns the first index of element `e` in the row, starting from `start`. + //! \~russian Возвращает первый индекс элемента `e` в строке, начиная с позиции `start`. + //! \param e Element to search for. + //! \param start Starting index (negative values count from the end). Default 0. + //! \return Index if found, -1 otherwise. + //! \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) { @@ -808,7 +914,12 @@ public: return -1; } - //! \~english Searches for element `e` backwards (see Col::lastIndexOf). + //! \~english Returns the last index of element `e` in the row, searching backwards from `start`. + //! \~russian Возвращает последний индекс элемента `e` в строке, выполняя поиск в обратном направлении от `start`. + //! \param e Element to search for. + //! \param start Starting index (negative values count from the end). Default -1 (last element). + //! \return Index if found, -1 otherwise. + //! \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) { @@ -817,7 +928,12 @@ public: return -1; } - //! \~english Searches with predicate (see Col::indexWhere). + //! \~english Returns the first index where the predicate `test` returns true, starting from `start`. + //! \~russian Возвращает первый индекс, для которого предикат `test` возвращает true, начиная с `start`. + //! \param test Predicate function: `bool(const T&)`. + //! \param start Starting index (negative values count from the end). Default 0. + //! \return Index if found, -1 otherwise. + //! \sa PIVector::indexWhere() inline ssize_t indexWhere(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; for (size_t i = (size_t)start; i < sz_; ++i) { @@ -826,7 +942,10 @@ public: return -1; } - //! \~english Searches with predicate backwards (see Col::lastIndexWhere). + //! \~english Returns the last index where the predicate `test` returns true, searching backwards from `start`. + //! \~russian Возвращает последний индекс, для которого предикат `test` возвращает true, выполняя поиск в обратном направлении от + //! `start`. \param test Predicate function: `bool(const T&)`. \param start Starting index (negative values count from the end). + //! Default -1. \return Index if found, -1 otherwise. \sa PIVector::lastIndexWhere() inline ssize_t lastIndexWhere(std::function 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) { @@ -837,6 +956,11 @@ public: //! \~english Applies a function to each element of the column (read-only). //! \~russian Применяет функцию к каждому элементу столбца (только чтение). + //! \param func Function that takes a const reference to T. + //! \details + //! \~english The function can't modify the elements. + //! \~russian Функция не может изменять элементы. + //! \sa forEach (modifiable) inline void forEach(std::function func) const { for (size_t i = 0; i < sz_; ++i) { func((*p_)[i * step_ + col_]); @@ -845,10 +969,18 @@ public: //! \~english Checks if the column contains the element `e`. //! \~russian Проверяет, содержит ли столбец элемент `e`. + //! \param e Element to check. + //! \param start Starting index (negative allowed). Default 0. + //! \return \c true if found, \c false otherwise. + //! \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` в столбце. + //! \param e Element to count. + //! \param start Starting index (negative allowed). Default 0. + //! \return Number of occurrences. + //! \sa PIVector::entries() inline int entries(const T & e, ssize_t start = 0) const { if (start < 0) start = 0; int count = 0; @@ -860,6 +992,10 @@ public: //! \~english Counts elements in the column that pass the `test`. //! \~russian Подсчитывает элементы в столбце, проходящие `test`. + //! \param test Predicate function. + //! \param start Starting index (negative allowed). Default 0. + //! \return Count of matching elements. + //! \sa PIVector::entries(std::function) inline int entries(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; int count = 0; @@ -871,6 +1007,9 @@ public: //! \~english Tests if any element in the column passes the `test`. //! \~russian Проверяет, проходит ли какой-либо элемент в столбце `test`. + //! \param test Predicate function. + //! \return \c true if at least one element satisfies the predicate. + //! \sa PIVector::any() inline bool any(std::function test) const { for (size_t i = 0; i < sz_; ++i) { if (test((*p_)[i * step_ + col_])) return true; @@ -880,6 +1019,9 @@ public: //! \~english Tests if all elements in the column pass the `test`. //! \~russian Проверяет, проходят ли все элементы в столбце `test`. + //! \param test Predicate function. + //! \return \c true if all elements satisfy the predicate. + //! \sa PIVector::every() inline bool every(std::function test) const { for (size_t i = 0; i < sz_; ++i) { if (!test((*p_)[i * step_ + col_])) return false; @@ -1129,11 +1271,17 @@ public: //! \~english Checks if the underlying flat vector contains the element `e`. //! \~russian Проверяет, содержит ли внутренний плоский вектор элемент `e`. + //! \param e Element to check. + //! \param start Starting index (negative allowed). Default 0. + //! \return \c true if found, \c false otherwise. //! \sa PIVector::contains() inline bool contains(const T & e, ssize_t start = 0) const { return mat.contains(e, start); } //! \~english Checks if the underlying flat vector contains all elements of `v`. //! \~russian Проверяет, содержит ли внутренний плоский вектор все элементы `v`. + //! \param e Element to check. + //! \param start Starting index (negative allowed). Default 0. + //! \return \c true if found, \c false otherwise. //! \sa PIVector::contains(const PIVector&) inline bool contains(const PIVector & v, ssize_t start = 0) const { return mat.contains(v, start); } -- 2.43.0 From 39c1be6bc0fcce383e0892e7d656b67c0a373fd1 Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Wed, 18 Feb 2026 20:03:27 +0300 Subject: [PATCH 05/29] fix filterElements --- libs/main/containers/pivector2d.h | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/libs/main/containers/pivector2d.h b/libs/main/containers/pivector2d.h index 895f7293..537ded76 100644 --- a/libs/main/containers/pivector2d.h +++ b/libs/main/containers/pivector2d.h @@ -1668,16 +1668,12 @@ public: return result; } - //! \~english Returns a new 2D array (as a single row) containing only the elements that pass the test. - //! \~russian Возвращает новый двумерный массив (в виде одной строки), содержащий только элементы, прошедшие проверку. + //! \~english Returns a new plain array containing only the elements that pass the test. + //! \~russian Возвращает новый одноменый массив, содержащий только элементы, прошедшие проверку. //! \param test Predicate taking a const T&. - //! \return A 1xN 2D array with the filtered elements (or empty). + //! \return PIVector with the filtered elements (or empty). //! \sa PIVector::filter() - inline PIVector2D filterElements(std::function test) const { - PIVector filtered = mat.filter(test); - if (filtered.isEmpty()) return PIVector2D(); - return PIVector2D(1, filtered.size(), filtered); - } + inline PIVector filterElements(std::function test) const { return mat.filter(test); } protected: size_t rows_, cols_; -- 2.43.0 From 87a29bc8bc975d8f1091bd6a51643352ada0e4ce Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Wed, 18 Feb 2026 20:03:47 +0300 Subject: [PATCH 06/29] addColumn --- libs/main/containers/pivector2d.h | 89 +++++++++++++++--- tests/math/testpivector2d.cpp | 149 +++++++++++++++++++++++++++++- 2 files changed, 222 insertions(+), 16 deletions(-) diff --git a/libs/main/containers/pivector2d.h b/libs/main/containers/pivector2d.h index 537ded76..ed8d0dc6 100644 --- a/libs/main/containers/pivector2d.h +++ b/libs/main/containers/pivector2d.h @@ -705,6 +705,11 @@ public: size_t st_, sz_; public: + inline RowConst(const PIVector2D::Row & r): p_(r.p_) { + st_ = r.st_; + sz_ = r.sz_; + } + //! \~english Size of the row (number of columns). //! \~russian Размер строки (количество столбцов). inline size_t size() const { return sz_; } @@ -875,6 +880,12 @@ public: size_t step_, col_, sz_; public: + inline ColConst(const PIVector2D::Col & c): p_(c.p_) { + step_ = c.step_; + col_ = c.col_; + sz_ = c.sz_; + } + //! \~english Size of the column (number of rows). //! \~russian Размер столбца (количество строк). inline size_t size() const { return sz_; } @@ -1130,18 +1141,6 @@ public: //! \~russian Если массив был пуст, количество столбцов устанавливается равным размеру исходной строки. //! В противном случае копируется только `min(cols(), other.size())` элементов; остальные элементы новой строки инициализируются по //! умолчанию. \sa PIVector::push_back() - inline PIVector2D & addRow(const Row & other) { - if (cols_ == 0) cols_ = other.sz_; - const size_t sz = piMin(cols_, other.sz_); - const size_t ps = mat.size(); - mat.resize(mat.size() + cols_); - mat._copyRaw(mat.data(ps), other.data(), sz); - rows_++; - return *this; - } - - //! \~english Appends a new row to the bottom of the array from a read-only RowConst object. - //! \~russian Добавляет новую строку в конец массива из объекта RowConst только для чтения. inline PIVector2D & addRow(const RowConst & other) { if (cols_ == 0) cols_ = other.sz_; const size_t sz = piMin(cols_, other.sz_); @@ -1164,6 +1163,72 @@ public: return *this; } + //! \~english Appends a new column to the right of the array from a \a PIVector. + //! \~russian Добавляет новую строку в конец массива из \a PIVector. + inline PIVector2D & addColumn(const ColConst & 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]; + } + 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()) { + dst[oldCols] = other[r]; + } else { + dst[oldCols] = T(); + } + } + mat[oldCols] = other[0]; + + cols_ = newCols; + return *this; + } + + inline PIVector2D & addColumn(const PIVector & 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]; + } + 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()) { + dst[oldCols] = other[r]; + } else { + dst[oldCols] = T(); + } + } + mat[oldCols] = other[0]; + + cols_ = newCols; + return *this; + } + //! \~english Resizes the 2D array to new dimensions. //! \~russian Изменяет размер двумерного массива. //! \param rows New number of rows. diff --git a/tests/math/testpivector2d.cpp b/tests/math/testpivector2d.cpp index 29831aab..c8d3bb87 100644 --- a/tests/math/testpivector2d.cpp +++ b/tests/math/testpivector2d.cpp @@ -379,6 +379,146 @@ TEST_F(Vector2DTest, addRow_with_shorter_vector_uses_min) { } } +// ==================== ADD COLUMN TESTS ==================== + +TEST_F(Vector2DTest, addColumn_appends_column_to_empty) { + PIVector2D empty; + PIVector newCol(5); + for (size_t i = 0; i < 5; ++i) + newCol[i] = static_cast(100 + i); + + empty.addColumn(newCol); + + EXPECT_EQ(empty.rows(), 5); + EXPECT_EQ(empty.cols(), 1); + for (size_t r = 0; r < 5; ++r) { + EXPECT_EQ(empty.element(r, 0), static_cast(100 + r)); + } +} + +TEST_F(Vector2DTest, addColumn_appends_column_to_existing) { + size_t oldRows = vec.rows(); + size_t oldCols = vec.cols(); + + PIVector newCol(oldRows, 999); + vec.addColumn(newCol); + + EXPECT_EQ(vec.rows(), oldRows); + EXPECT_EQ(vec.cols(), oldCols + 1); + + // Check that old data is 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(r * COLS_COUNT_INIT + c)); + } + } + + // Check new column + for (size_t r = 0; r < oldRows; ++r) { + EXPECT_EQ(vec.element(r, oldCols), 999); + } +} + +TEST_F(Vector2DTest, addColumn_with_shorter_vector_uses_min) { + size_t oldRows = vec.rows(); + size_t oldCols = vec.cols(); + size_t shortLen = oldRows - 10; + PIVector shortCol(shortLen, 777); + + vec.addColumn(shortCol); + + EXPECT_EQ(vec.cols(), oldCols + 1); + + // First shortLen rows should be 777 + for (size_t r = 0; r < shortLen; ++r) { + EXPECT_EQ(vec.element(r, oldCols), 777); + } + // Remaining rows should be default-initialized (0) + for (size_t r = shortLen; r < oldRows; ++r) { + EXPECT_EQ(vec.element(r, oldCols), 0); + } +} + +TEST_F(Vector2DTest, addColumn_with_longer_vector_truncates) { + size_t oldRows = vec.rows(); + size_t oldCols = vec.cols(); + size_t longLen = oldRows + 10; + PIVector longCol(longLen, 555); + + vec.addColumn(longCol); + + EXPECT_EQ(vec.cols(), oldCols + 1); + + // All rows should be 555 (only first oldRows elements are used) + for (size_t r = 0; r < oldRows; ++r) { + EXPECT_EQ(vec.element(r, oldCols), 555); + } +} + +TEST_F(Vector2DTest, addColumn_with_empty_source_does_nothing_on_empty) { + PIVector2D empty; + PIVector emptyCol; + + empty.addColumn(emptyCol); + EXPECT_TRUE(empty.isEmpty()); + EXPECT_EQ(empty.rows(), 0); + EXPECT_EQ(empty.cols(), 0); +} + +TEST_F(Vector2DTest, addColumn_with_empty_source_adds_default_column) { + auto oldVec = vec; + + vec.addColumn({}); + + EXPECT_EQ(vec.cols(), oldVec.cols()); + EXPECT_EQ(vec.rows(), oldVec.rows()); + + for (size_t r = 0; r < oldVec.rows(); ++r) { + for (size_t c = 0; c < oldVec.cols(); ++c) { + EXPECT_EQ(vec.element(r, c), oldVec.element(r, c)); + } + } +} + +TEST_F(Vector2DTest, addColumn_with_Col_proxy_works) { + auto oldVec = vec; + const size_t colIndex = 5; + + auto srcCol = oldVec.col(colIndex); + vec.addColumn(srcCol); + + EXPECT_EQ(vec.cols(), oldVec.cols() + 1); + EXPECT_EQ(vec.rows(), oldVec.rows()); + + for (size_t r = 0; r < oldVec.rows(); ++r) { + for (size_t c = 0; c < oldVec.cols(); ++c) { + EXPECT_EQ(vec.element(r, c), oldVec.element(r, c)); + } + } + 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)); + } +} + +TEST_F(Vector2DTest, addColumn_with_ColConst_proxy_works) { + size_t oldRows = vec.rows(); + size_t oldCols = vec.cols(); + + const auto & constVec = vec; + auto srcCol = constVec.col(7); + // Need a non-const array to add to + PIVector2D mutableVec = vec; // copy + mutableVec.addColumn(srcCol); + + EXPECT_EQ(mutableVec.cols(), oldCols + 1); + + for (size_t r = 0; r < oldRows; ++r) { + EXPECT_EQ(mutableVec.element(r, oldCols), vec.element(r, 7)); + } +} + // ==================== RESIZE TESTS ==================== class Vector2DResizeTest: public Vector2DTest { protected: @@ -670,7 +810,8 @@ TEST(Vector2DTransposeTest, singleElement_returnsSame) { TEST(Vector2DTransposeTest, oneRow_becomesOneColumn) { PIVector2D rowVec(1, 5); - for (size_t c = 0; c < 5; ++c) rowVec.element(0, c) = static_cast(c); + for (size_t c = 0; c < 5; ++c) + rowVec.element(0, c) = static_cast(c); auto transposed = rowVec.transposed(); EXPECT_EQ(transposed.rows(), 5); EXPECT_EQ(transposed.cols(), 1); @@ -681,7 +822,8 @@ TEST(Vector2DTransposeTest, oneRow_becomesOneColumn) { TEST(Vector2DTransposeTest, oneColumn_becomesOneRow) { PIVector2D colVec(5, 1); - for (size_t r = 0; r < 5; ++r) colVec.element(r, 0) = static_cast(r); + for (size_t r = 0; r < 5; ++r) + colVec.element(r, 0) = static_cast(r); auto transposed = colVec.transposed(); EXPECT_EQ(transposed.rows(), 1); EXPECT_EQ(transposed.cols(), 5); @@ -691,7 +833,7 @@ TEST(Vector2DTransposeTest, oneColumn_becomesOneRow) { } TEST_F(Vector2DTest, transposed_doesNotModifyOriginal) { - auto original = vec; // копия для сравнения + auto original = vec; // копия для сравнения auto transposed = vec.transposed(); // Проверяем, что исходный массив не изменился EXPECT_EQ(vec, original); @@ -1271,7 +1413,6 @@ TEST_F(Vector2DTest, colconst_proxy_every_returns_true_if_all_match) { auto isLessThanMax = [&](const int & e) { return e < static_cast(vec.size()); }; EXPECT_TRUE(col.every(isLessThanMax)); auto isNotEven = [](const int & e) { return e % 2 != 0; }; - col.forEach([](const int & v) { piCout << v; }); EXPECT_FALSE(col.every(isNotEven)); } -- 2.43.0 From d8cadce026c4245edea37700eaf0b1b94b9370d8 Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Wed, 18 Feb 2026 20:26:38 +0300 Subject: [PATCH 07/29] code style --- libs/main/containers/pivector2d.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libs/main/containers/pivector2d.h b/libs/main/containers/pivector2d.h index ed8d0dc6..c9832e0b 100644 --- a/libs/main/containers/pivector2d.h +++ b/libs/main/containers/pivector2d.h @@ -1554,7 +1554,6 @@ public: return PIVector2D(rows_, cols_, std::move(mappedMat)); } - // --- Итерация по строкам и столбцам --- //! \~english Applies a function to each row (modifiable). //! \~russian Применяет функцию к каждой строке (с возможностью изменения). //! \param f Function taking a \a Row. @@ -1565,6 +1564,7 @@ public: f(row(r)); return *this; } + //! \~english Applies a function to each row (read-only). //! \~russian Применяет функцию к каждой строке (только чтение). //! \param f Function taking a \a RowConst. @@ -1572,6 +1572,7 @@ public: for (size_t r = 0; r < rows_; ++r) f(row(r)); } + //! \~english Applies a function to each column (modifiable). //! \~russian Применяет функцию к каждому столбцу (с возможностью изменения). //! \param f Function taking a \a Col. @@ -1581,6 +1582,7 @@ public: f(col(c)); return *this; } + //! \~english Applies a function to each column (read-only). //! \~russian Применяет функцию к каждому столбцу (только чтение). //! \param f Function taking a \a ColConst. -- 2.43.0 From 98d93865f0811c3f5ac85b36cd5262ff3ff9fd72 Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Wed, 18 Feb 2026 22:00:21 +0300 Subject: [PATCH 08/29] review fixes --- libs/main/containers/pivector.h | 30 ++- libs/main/containers/pivector2d.h | 296 ++++-------------------------- libs/main/system/pihidevice.cpp | 8 +- tests/math/testpivector2d.cpp | 8 +- 4 files changed, 71 insertions(+), 271 deletions(-) diff --git a/libs/main/containers/pivector.h b/libs/main/containers/pivector.h index 59f0786d..96e85f9c 100644 --- a/libs/main/containers/pivector.h +++ b/libs/main/containers/pivector.h @@ -835,8 +835,8 @@ public: //! piCout << v.contains({1,4}); // true //! piCout << v.contains({1,5}); // false //! \endcode - //! \~\sa \a every(), \a any(), \a entries(), \a forEach() - inline bool contains(const PIVector & v, ssize_t start = 0) const { + //! \~\sa \a every(), \a any(), \a entries(), \a forEach(), \a contains() + inline bool containsAll(const PIVector & v, ssize_t start = 0) const { if (start < 0) { start = piv_size + start; if (start < 0) start = 0; @@ -854,6 +854,24 @@ public: return true; } + //! \~english Tests if any element of `v` exists in the array. + //! \~russian Проверяет наличие хотя бы одного из элементов `v` в массиве. + //! \~\sa \a containsAll(), \a contains() + inline bool containsAny(const PIVector & v, ssize_t start = 0) const { + if (start < 0) { + start = piv_size + start; + if (start < 0) start = 0; + } + for (const T & e: v) { + for (size_t i = start; i < piv_size; ++i) { + if (e == piv_data[i]) { + return true; + } + } + } + return false; + } + //! \~english Count elements equal `e` in the array. //! \~russian Подсчитывает количество элементов, совпадающих с элементом `e` в массиве. //! \~\details @@ -1349,8 +1367,8 @@ public: alloc(piv_size + v.piv_size); if (os > 0) { memmove(reinterpret_cast(piv_data + index + v.piv_size), - reinterpret_cast(piv_data + index), - os * sizeof(T)); + reinterpret_cast(piv_data + index), + os * sizeof(T)); } newT(piv_data + index, v.piv_data, v.piv_size); return *this; @@ -1372,8 +1390,8 @@ public: alloc(piv_size + init_list.size()); if (os > 0) { memmove(reinterpret_cast(piv_data + index + init_list.size()), - reinterpret_cast(piv_data + index), - os * sizeof(T)); + reinterpret_cast(piv_data + index), + os * sizeof(T)); } newT(piv_data + index, init_list.begin(), init_list.size()); return *this; diff --git a/libs/main/containers/pivector2d.h b/libs/main/containers/pivector2d.h index c9832e0b..f30b2bcd 100644 --- a/libs/main/containers/pivector2d.h +++ b/libs/main/containers/pivector2d.h @@ -62,9 +62,6 @@ public: //! \~english Constructs a 2D array with the given dimensions, filled with copies of `f`. //! \~russian Создаёт двумерный массив заданного размера, заполненный копиями `f`. - //! \param rows Number of rows. - //! \param cols Number of columns. - //! \param f Value to fill the array with. Defaults to default-constructed T. //! \details //! \~english The underlying storage is a single contiguous block of memory of size `rows * cols`. //! All elements are initialized with the value `f`. @@ -79,9 +76,6 @@ public: //! \~english Constructs a 2D array from an existing 1D vector, reshaping it. //! \~russian Создаёт двумерный массив из существующего одномерного вектора, изменяя его форму. - //! \param rows Number of rows. - //! \param cols Number of columns. - //! \param v The source 1D vector. Its size must be at least `rows * cols`. //! \details //! \~english The constructor copies the data from `v` into the internal flat vector. //! If `v` is larger than `rows * cols`, the excess elements are ignored (the vector is truncated). @@ -94,9 +88,6 @@ public: //! \~english Move constructs a 2D array from an existing 1D vector, reshaping it. //! \~russian Конструктор перемещения из существующего одномерного вектора, изменяя его форму. - //! \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`. //! \details //! \~english The data is moved from `v` into the internal flat vector, avoiding a copy. //! After construction, `v` is left in a valid but unspecified state. @@ -107,7 +98,8 @@ public: //! \~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. \details + //! одинаковый размер. + //! \details //! \~english If the input is empty, the constructed array is also empty. Otherwise, the number of columns is taken from the size of the //! first inner vector. All inner vectors are concatenated in the internal flat storage. //! \~russian Если входной массив пуст, создаётся пустой двумерный массив. В противном случае количество столбцов берётся из размера @@ -220,8 +212,6 @@ public: //! \~english Accesses the element at the given column index within the row. //! \~russian Доступ к элементу по заданному индексу столбца в строке. - //! \param index Column index (must be less than size()). - //! \return Reference to the element. //! \details //! \~english No bounds checking is performed in release builds; use with caution. //! \~russian В релизной сборке проверка границ не выполняется; используйте с осторожностью. @@ -230,15 +220,11 @@ public: //! \~english Const access to the element at the given column index within the row. //! \~russian Константный доступ к элементу по заданному индексу столбца в строке. - //! \param index Column index (must be less than size()). - //! \return Const reference to the element. //! \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 Возвращает указатель на данные строки, начиная с опционального смещения. - //! \param index Offset within the row (default 0). - //! \return Pointer to the first element at the given offset. //! \details //! \~english The pointer can be used for direct memory operations. It remains valid as long as the underlying 2D array is not //! reallocated. @@ -248,15 +234,11 @@ public: //! \~english Returns a const pointer to the row data starting at an optional offset. //! \~russian Возвращает константный указатель на данные строки, начиная с опционального смещения. - //! \param index Offset within the row (default 0). - //! \return Const pointer. //! \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 Присваивает этой строке содержимое другой строки. - //! \param other Source row. - //! \return Reference to this row. //! \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` игнорируются. @@ -270,8 +252,6 @@ public: //! \~english Assigns the contents of a \a PIVector to this row. //! \~russian Присваивает этой строке содержимое \a PIVector. - //! \param other Source vector. - //! \return Reference to this row. //! \details //! \~english Only the minimum of the row size and vector size is copied. //! \~russian Копируется только минимум из размера строки и размера вектора. @@ -284,15 +264,11 @@ public: //! \~english Converts the row to a \a PIVector. //! \~russian Преобразует строку в \a PIVector. - //! \return A new \a PIVector containing a copy of the row elements. //! \sa PIVector::PIVector(const T*, size_t) inline PIVector toVector() const { return PIVector(p_->data(st_), sz_); } //! \~english Returns the first index of element `e` in the row, starting from `start`. //! \~russian Возвращает первый индекс элемента `e` в строке, начиная с позиции `start`. - //! \param e Element to search for. - //! \param start Starting index (negative values count from the end). Default 0. - //! \return Index if found, -1 otherwise. //! \details //! \~english See \a PIVector::indexOf() for details on negative start handling. //! \~russian Подробнее об обработке отрицательного `start` см. \a PIVector::indexOf(). @@ -307,9 +283,6 @@ public: //! \~english Returns the last index of element `e` in the row, searching backwards from `start`. //! \~russian Возвращает последний индекс элемента `e` в строке, выполняя поиск в обратном направлении от `start`. - //! \param e Element to search for. - //! \param start Starting index (negative values count from the end). Default -1 (last element). - //! \return Index if found, -1 otherwise. //! \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; @@ -321,9 +294,6 @@ public: //! \~english Returns the first index where the predicate `test` returns true, starting from `start`. //! \~russian Возвращает первый индекс, для которого предикат `test` возвращает true, начиная с `start`. - //! \param test Predicate function: `bool(const T&)`. - //! \param start Starting index (negative values count from the end). Default 0. - //! \return Index if found, -1 otherwise. //! \sa PIVector::indexWhere() inline ssize_t indexWhere(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; @@ -334,9 +304,9 @@ public: } //! \~english Returns the last index where the predicate `test` returns true, searching backwards from `start`. - //! \~russian Возвращает последний индекс, для которого предикат `test` возвращает true, выполняя поиск в обратном направлении от - //! `start`. \param test Predicate function: `bool(const T&)`. \param start Starting index (negative values count from the end). - //! Default -1. \return Index if found, -1 otherwise. \sa PIVector::lastIndexWhere() + //! \~russian Возвращает последний индекс, для которого предикат `test` возвращает true, + //! выполняя поиск в обратном направлении от `start`. + //! \sa PIVector::lastIndexWhere() inline ssize_t lastIndexWhere(std::function 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) { @@ -360,7 +330,6 @@ public: //! \~english Applies a function to each element of the row (read-only). //! \~russian Применяет функцию к каждому элементу строки (только чтение). - //! \param func Function that takes a const reference to T. //! \details //! \~english The function can't modify the elements. //! \~russian Функция не может изменять элементы. @@ -373,7 +342,6 @@ public: //! \~english Fills the row with copies of `value`. //! \~russian Заполняет строку копиями `value`. - //! \param value Value to fill with. //! \sa PIVector::fill() inline void fill(const T & value) { for (size_t i = 0; i < sz_; ++i) { @@ -383,17 +351,11 @@ public: //! \~english Checks if the row contains the element `e`. //! \~russian Проверяет, содержит ли строка элемент `e`. - //! \param e Element to check. - //! \param start Starting index (negative allowed). Default 0. - //! \return \c true if found, \c false otherwise. //! \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` в строке. - //! \param e Element to count. - //! \param start Starting index (negative allowed). Default 0. - //! \return Number of occurrences. //! \sa PIVector::entries() inline int entries(const T & e, ssize_t start = 0) const { if (start < 0) start = 0; @@ -406,9 +368,6 @@ public: //! \~english Counts elements in the row that pass the `test`. //! \~russian Подсчитывает элементы в строке, проходящие `test`. - //! \param test Predicate function. - //! \param start Starting index (negative allowed). Default 0. - //! \return Count of matching elements. //! \sa PIVector::entries(std::function) inline int entries(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; @@ -421,8 +380,6 @@ public: //! \~english Tests if any element in the row passes the `test`. //! \~russian Проверяет, проходит ли какой-либо элемент в строке `test`. - //! \param test Predicate function. - //! \return \c true if at least one element satisfies the predicate. //! \sa PIVector::any() inline bool any(std::function test) const { for (size_t i = 0; i < sz_; ++i) { @@ -433,8 +390,6 @@ public: //! \~english Tests if all elements in the row pass the `test`. //! \~russian Проверяет, проходят ли все элементы в строке `test`. - //! \param test Predicate function. - //! \return \c true if all elements satisfy the predicate. //! \sa PIVector::every() inline bool every(std::function test) const { for (size_t i = 0; i < sz_; ++i) { @@ -472,7 +427,6 @@ public: //! \~english Accesses the element at the given row index within the column. //! \~russian Доступ к элементу по заданному индексу строки в столбце. - //! \param index Row index. //! \return Reference to the element. inline T & operator[](size_t index) { return (*p_)[index * step_ + col_]; } @@ -482,8 +436,6 @@ public: //! \~english Returns a pointer to the column data starting at an optional row offset. //! \~russian Возвращает указатель на данные столбца, начиная с опционального смещения по строкам. - //! \param index Row offset (default 0). - //! \return Pointer to the element at the given row. //! \details //! \~english Note that column elements are not stored contiguously in memory, so this pointer cannot be used to iterate over the //! whole column. @@ -497,8 +449,6 @@ public: //! \~english Assigns the contents of another Col to this column. //! \~russian Присваивает этому столбцу содержимое другого столбца. - //! \param other Source column. - //! \return Reference to this column. inline Col & operator=(const Col & other) { if (p_ == other.p_ && col_ == other.col_) return *this; const size_t sz = piMin(sz_, other.sz_); @@ -509,8 +459,6 @@ public: //! \~english Assigns the contents of a \a PIVector to this column. //! \~russian Присваивает этому столбцу содержимое \a PIVector. - //! \param other Source vector. - //! \return Reference to this column. inline Col & operator=(const PIVector & other) { const size_t sz = piMin(sz_, other.size()); for (size_t i = 0; i < sz; ++i) @@ -520,7 +468,6 @@ public: //! \~english Converts the column to a \a PIVector. //! \~russian Преобразует столбец в \a PIVector. - //! \return A new \a PIVector containing a copy of the column elements. inline PIVector toVector() const { PIVector ret; ret.reserve(sz_); @@ -531,9 +478,6 @@ public: //! \~english Returns the first index of element `e` in the row, starting from `start`. //! \~russian Возвращает первый индекс элемента `e` в строке, начиная с позиции `start`. - //! \param e Element to search for. - //! \param start Starting index (negative values count from the end). Default 0. - //! \return Index if found, -1 otherwise. //! \details //! \~english See \a PIVector::indexOf() for details on negative start handling. //! \~russian Подробнее об обработке отрицательного `start` см. \a PIVector::indexOf(). @@ -548,9 +492,6 @@ public: //! \~english Returns the last index of element `e` in the row, searching backwards from `start`. //! \~russian Возвращает последний индекс элемента `e` в строке, выполняя поиск в обратном направлении от `start`. - //! \param e Element to search for. - //! \param start Starting index (negative values count from the end). Default -1 (last element). - //! \return Index if found, -1 otherwise. //! \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; @@ -562,9 +503,6 @@ public: //! \~english Returns the first index where the predicate `test` returns true, starting from `start`. //! \~russian Возвращает первый индекс, для которого предикат `test` возвращает true, начиная с `start`. - //! \param test Predicate function: `bool(const T&)`. - //! \param start Starting index (negative values count from the end). Default 0. - //! \return Index if found, -1 otherwise. //! \sa PIVector::indexWhere() inline ssize_t indexWhere(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; @@ -575,9 +513,9 @@ public: } //! \~english Returns the last index where the predicate `test` returns true, searching backwards from `start`. - //! \~russian Возвращает последний индекс, для которого предикат `test` возвращает true, выполняя поиск в обратном направлении от - //! `start`. \param test Predicate function: `bool(const T&)`. \param start Starting index (negative values count from the end). - //! Default -1. \return Index if found, -1 otherwise. \sa PIVector::lastIndexWhere() + //! \~russian Возвращает последний индекс, для которого предикат `test` возвращает true, + //! выполняя поиск в обратном направлении от `start`. + //! \sa PIVector::lastIndexWhere() inline ssize_t lastIndexWhere(std::function 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) { @@ -588,7 +526,6 @@ public: //! \~english Applies a function to each element of the column (modifiable). //! \~russian Применяет функцию к каждому элементу столбца (с возможностью изменения). - //! \param func Function that takes a reference to T. //! \details //! \~english The function can modify the elements. //! \~russian Функция может изменять элементы. @@ -601,7 +538,6 @@ public: //! \~english Applies a function to each element of the column (read-only). //! \~russian Применяет функцию к каждому элементу столбца (только чтение). - //! \param func Function that takes a const reference to T. //! \details //! \~english The function can't modify the elements. //! \~russian Функция не может изменять элементы. @@ -614,7 +550,6 @@ public: //! \~english Fills the column with copies of `value`. //! \~russian Заполняет столбец копиями `value`. - //! \param value Value to fill with. //! \sa PIVector::fill() inline void fill(const T & value) { for (size_t i = 0; i < sz_; ++i) { @@ -624,17 +559,11 @@ public: //! \~english Checks if the column contains the element `e`. //! \~russian Проверяет, содержит ли столбец элемент `e`. - //! \param e Element to check. - //! \param start Starting index (negative allowed). Default 0. - //! \return \c true if found, \c false otherwise. //! \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` в столбце. - //! \param e Element to count. - //! \param start Starting index (negative allowed). Default 0. - //! \return Number of occurrences. //! \sa PIVector::entries() inline int entries(const T & e, ssize_t start = 0) const { if (start < 0) start = 0; @@ -647,9 +576,6 @@ public: //! \~english Counts elements in the column that pass the `test`. //! \~russian Подсчитывает элементы в столбце, проходящие `test`. - //! \param test Predicate function. - //! \param start Starting index (negative allowed). Default 0. - //! \return Count of matching elements. //! \sa PIVector::entries(std::function) inline int entries(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; @@ -662,8 +588,6 @@ public: //! \~english Tests if any element in the column passes the `test`. //! \~russian Проверяет, проходит ли какой-либо элемент в столбце `test`. - //! \param test Predicate function. - //! \return \c true if at least one element satisfies the predicate. //! \sa PIVector::any() inline bool any(std::function test) const { for (size_t i = 0; i < sz_; ++i) { @@ -674,8 +598,6 @@ public: //! \~english Tests if all elements in the column pass the `test`. //! \~russian Проверяет, проходят ли все элементы в столбце `test`. - //! \param test Predicate function. - //! \return \c true if all elements satisfy the predicate. //! \sa PIVector::every() inline bool every(std::function test) const { for (size_t i = 0; i < sz_; ++i) { @@ -728,9 +650,6 @@ public: //! \~english Returns the first index of element `e` in the row, starting from `start`. //! \~russian Возвращает первый индекс элемента `e` в строке, начиная с позиции `start`. - //! \param e Element to search for. - //! \param start Starting index (negative values count from the end). Default 0. - //! \return Index if found, -1 otherwise. //! \details //! \~english See \a PIVector::indexOf() for details on negative start handling. //! \~russian Подробнее об обработке отрицательного `start` см. \a PIVector::indexOf(). @@ -745,8 +664,6 @@ public: //! \~english Returns the last index of element `e` in the row, searching backwards from `start`. //! \~russian Возвращает последний индекс элемента `e` в строке, выполняя поиск в обратном направлении от `start`. - //! \param e Element to search for. - //! \param start Starting index (negative values count from the end). Default -1 (last element). //! \return Index if found, -1 otherwise. //! \sa PIVector::lastIndexOf() inline ssize_t lastIndexOf(const T & e, ssize_t start = -1) const { @@ -759,9 +676,6 @@ public: //! \~english Returns the first index where the predicate `test` returns true, starting from `start`. //! \~russian Возвращает первый индекс, для которого предикат `test` возвращает true, начиная с `start`. - //! \param test Predicate function: `bool(const T&)`. - //! \param start Starting index (negative values count from the end). Default 0. - //! \return Index if found, -1 otherwise. //! \sa PIVector::indexWhere() inline ssize_t indexWhere(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; @@ -772,9 +686,9 @@ public: } //! \~english Returns the last index where the predicate `test` returns true, searching backwards from `start`. - //! \~russian Возвращает последний индекс, для которого предикат `test` возвращает true, выполняя поиск в обратном направлении от - //! `start`. \param test Predicate function: `bool(const T&)`. \param start Starting index (negative values count from the end). - //! Default -1. \return Index if found, -1 otherwise. \sa PIVector::lastIndexWhere() + //! \~russian Возвращает последний индекс, для которого предикат `test` возвращает true, + //! выполняя поиск в обратном направлении от `start`. + //! \sa PIVector::lastIndexWhere() inline ssize_t lastIndexWhere(std::function 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) { @@ -785,7 +699,6 @@ public: //! \~english Applies a function to each element of the row (read-only). //! \~russian Применяет функцию к каждому элементу строки (только чтение). - //! \param func Function that takes a const reference to T. //! \details //! \~english The function can't modify the elements. //! \~russian Функция не может изменять элементы. @@ -798,17 +711,11 @@ public: //! \~english Checks if the row contains the element `e`. //! \~russian Проверяет, содержит ли строка элемент `e`. - //! \param e Element to check. - //! \param start Starting index (negative allowed). Default 0. - //! \return \c true if found, \c false otherwise. //! \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` в строке. - //! \param e Element to count. - //! \param start Starting index (negative allowed). Default 0. - //! \return Number of occurrences. //! \sa PIVector::entries() inline int entries(const T & e, ssize_t start = 0) const { if (start < 0) start = 0; @@ -821,9 +728,6 @@ public: //! \~english Counts elements in the row that pass the `test`. //! \~russian Подсчитывает элементы в строке, проходящие `test`. - //! \param test Predicate function. - //! \param start Starting index (negative allowed). Default 0. - //! \return Count of matching elements. //! \sa PIVector::entries(std::function) inline int entries(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; @@ -836,8 +740,6 @@ public: //! \~english Tests if any element in the row passes the `test`. //! \~russian Проверяет, проходит ли какой-либо элемент в строке `test`. - //! \param test Predicate function. - //! \return \c true if at least one element satisfies the predicate. //! \sa PIVector::any() inline bool any(std::function test) const { for (size_t i = 0; i < sz_; ++i) { @@ -848,8 +750,6 @@ public: //! \~english Tests if all elements in the row pass the `test`. //! \~russian Проверяет, проходят ли все элементы в строке `test`. - //! \param test Predicate function. - //! \return \c true if all elements satisfy the predicate. //! \sa PIVector::every() inline bool every(std::function test) const { for (size_t i = 0; i < sz_; ++i) { @@ -910,9 +810,6 @@ public: //! \~english Returns the first index of element `e` in the row, starting from `start`. //! \~russian Возвращает первый индекс элемента `e` в строке, начиная с позиции `start`. - //! \param e Element to search for. - //! \param start Starting index (negative values count from the end). Default 0. - //! \return Index if found, -1 otherwise. //! \details //! \~english See \a PIVector::indexOf() for details on negative start handling. //! \~russian Подробнее об обработке отрицательного `start` см. \a PIVector::indexOf(). @@ -927,9 +824,6 @@ public: //! \~english Returns the last index of element `e` in the row, searching backwards from `start`. //! \~russian Возвращает последний индекс элемента `e` в строке, выполняя поиск в обратном направлении от `start`. - //! \param e Element to search for. - //! \param start Starting index (negative values count from the end). Default -1 (last element). - //! \return Index if found, -1 otherwise. //! \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; @@ -941,9 +835,6 @@ public: //! \~english Returns the first index where the predicate `test` returns true, starting from `start`. //! \~russian Возвращает первый индекс, для которого предикат `test` возвращает true, начиная с `start`. - //! \param test Predicate function: `bool(const T&)`. - //! \param start Starting index (negative values count from the end). Default 0. - //! \return Index if found, -1 otherwise. //! \sa PIVector::indexWhere() inline ssize_t indexWhere(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; @@ -954,9 +845,9 @@ public: } //! \~english Returns the last index where the predicate `test` returns true, searching backwards from `start`. - //! \~russian Возвращает последний индекс, для которого предикат `test` возвращает true, выполняя поиск в обратном направлении от - //! `start`. \param test Predicate function: `bool(const T&)`. \param start Starting index (negative values count from the end). - //! Default -1. \return Index if found, -1 otherwise. \sa PIVector::lastIndexWhere() + //! \~russian Возвращает последний индекс, для которого предикат `test` возвращает true, + //! выполняя поиск в обратном направлении от `start`. + //! \sa PIVector::lastIndexWhere() inline ssize_t lastIndexWhere(std::function 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) { @@ -967,7 +858,6 @@ public: //! \~english Applies a function to each element of the column (read-only). //! \~russian Применяет функцию к каждому элементу столбца (только чтение). - //! \param func Function that takes a const reference to T. //! \details //! \~english The function can't modify the elements. //! \~russian Функция не может изменять элементы. @@ -980,17 +870,11 @@ public: //! \~english Checks if the column contains the element `e`. //! \~russian Проверяет, содержит ли столбец элемент `e`. - //! \param e Element to check. - //! \param start Starting index (negative allowed). Default 0. - //! \return \c true if found, \c false otherwise. //! \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` в столбце. - //! \param e Element to count. - //! \param start Starting index (negative allowed). Default 0. - //! \return Number of occurrences. //! \sa PIVector::entries() inline int entries(const T & e, ssize_t start = 0) const { if (start < 0) start = 0; @@ -1003,9 +887,6 @@ public: //! \~english Counts elements in the column that pass the `test`. //! \~russian Подсчитывает элементы в столбце, проходящие `test`. - //! \param test Predicate function. - //! \param start Starting index (negative allowed). Default 0. - //! \return Count of matching elements. //! \sa PIVector::entries(std::function) inline int entries(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; @@ -1018,8 +899,6 @@ public: //! \~english Tests if any element in the column passes the `test`. //! \~russian Проверяет, проходит ли какой-либо элемент в столбце `test`. - //! \param test Predicate function. - //! \return \c true if at least one element satisfies the predicate. //! \sa PIVector::any() inline bool any(std::function test) const { for (size_t i = 0; i < sz_; ++i) { @@ -1030,8 +909,6 @@ public: //! \~english Tests if all elements in the column pass the `test`. //! \~russian Проверяет, проходят ли все элементы в столбце `test`. - //! \param test Predicate function. - //! \return \c true if all elements satisfy the predicate. //! \sa PIVector::every() inline bool every(std::function test) const { for (size_t i = 0; i < sz_; ++i) { @@ -1043,9 +920,6 @@ public: //! \~english Returns a reference to the element at the given row and column. //! \~russian Возвращает ссылку на элемент по заданной строке и столбцу. - //! \param row Row index. - //! \param col Column index. - //! \return Reference to the element. //! \details //! \~english No bounds checking is performed. //! \~russian Проверка границ не выполняется. @@ -1062,8 +936,6 @@ public: //! \~english Returns a proxy object for the row at the given index for modification. //! \~russian Возвращает прокси-объект для строки по заданному индексу для модификации. - //! \param index Row index. - //! \return Row proxy. //! \sa row(), Col inline Row operator[](size_t index) { return Row(this, index); } @@ -1073,8 +945,6 @@ public: //! \~english Returns a pointer to the underlying flat data starting at an optional offset. //! \~russian Возвращает указатель на внутренние плоские данные, начиная с опционального смещения. - //! \param index Flat index offset. - //! \return Pointer to data. //! \sa PIVector::data() inline T * data(size_t index = 0) { return mat.data(index); } @@ -1094,8 +964,6 @@ public: //! \~english Returns a proxy object for the column at the given index for modification. //! \~russian Возвращает прокси-объект для столбца по заданному индексу для модификации. - //! \param index Column index. - //! \return Column proxy. //! \sa col() const inline Col col(size_t index) { return Col(this, index); } @@ -1103,18 +971,6 @@ public: //! \~russian Возвращает прокси-объект для столбца по заданному индексу только для чтения. inline ColConst col(size_t index) const { return ColConst(this, index); } - - //! \~english Replaces a row with the contents of another Row object. - //! \~russian Заменяет строку содержимым другого объекта Row. - //! \param row Row index. - //! \param other Source row. - //! \return Reference to this 2D array. - inline PIVector2D & setRow(size_t row, const Row & other) { - const size_t sz = piMin(cols_, other.sz_); - mat._copyRaw(mat.data(cols_ * row), other.data(), sz); - return *this; - } - //! \~english Replaces a row with the contents of a read-only RowConst object. //! \~russian Заменяет строку содержимым объекта RowConst только для чтения. inline PIVector2D & setRow(size_t row, const RowConst & other) { @@ -1133,8 +989,6 @@ public: //! \~english Appends a new row to the bottom of the array from another Row object. //! \~russian Добавляет новую строку в конец массива из другого объекта Row. - //! \param other Source row. - //! \return Reference to this array. //! \details //! \~english If the array was empty, its column count is set to the size of the source row. //! Otherwise, only `min(cols(), other.size())` elements are copied; the rest of the new row is default-initialized. @@ -1163,8 +1017,8 @@ public: return *this; } - //! \~english Appends a new column to the right of the array from a \a PIVector. - //! \~russian Добавляет новую строку в конец массива из \a PIVector. + //! \~english Appends a new column to the right of the array from a \a ColConst. + //! \~russian Добавляет новую строку в конец массива из \a ColConst. inline PIVector2D & addColumn(const ColConst & other) { if (other.size() == 0) return *this; if (size() == 0) { @@ -1186,17 +1040,20 @@ public: T * dst = mat.data(r * newCols); memmove(dst, src, oldCols * sizeof(T)); if (r < other.size()) { - dst[oldCols] = other[r]; + mat._copyRaw(&(dst[oldCols]), &(other[r]), 1); } else { - dst[oldCols] = T(); + const T tmp = T(); + mat._copyRaw(&(dst[oldCols]), &tmp, 1); } } - mat[oldCols] = other[0]; + mat._copyRaw(mat.data(oldCols), &(other[0]), 1); - cols_ = newCols; + cols_ = newCols; return *this; } + //! \~english Appends a new column to the right of the array from a \a PIVector. + //! \~russian Добавляет новую строку в конец массива из \a PIVector. inline PIVector2D & addColumn(const PIVector & other) { if (other.size() == 0) return *this; if (size() == 0) { @@ -1218,23 +1075,20 @@ public: T * dst = mat.data(r * newCols); memmove(dst, src, oldCols * sizeof(T)); if (r < other.size()) { - dst[oldCols] = other[r]; + mat._copyRaw(&(dst[oldCols]), &(other[r]), 1); } else { - dst[oldCols] = T(); + const T tmp = T(); + mat._copyRaw(&(dst[oldCols]), &tmp, 1); } } - mat[oldCols] = other[0]; + mat._copyRaw(mat.data(oldCols), &(other[0]), 1); - cols_ = newCols; + cols_ = newCols; return *this; } //! \~english Resizes the 2D array to new dimensions. //! \~russian Изменяет размер двумерного массива. - //! \param rows New number of rows. - //! \param cols New number of columns. - //! \param f Value to fill newly created elements (if growing). Defaults to default-constructed T. - //! \return Reference to this array. //! \details //! \~english If the new dimensions are larger, new elements are appended and filled with copies of `f`. //! If they are smaller, the array is truncated (excess elements are destroyed). The underlying memory may be reallocated. @@ -1261,8 +1115,6 @@ public: //! \~english Equality operator. //! \~russian Оператор равенства. - //! \param t Another 2D array. - //! \return \c true if both arrays have the same dimensions and all elements are equal. //! \sa PIVector::operator== inline bool operator==(const PIVector2D & t) const { if (cols_ != t.cols_ || rows_ != t.rows_) return false; @@ -1275,7 +1127,6 @@ public: //! \~english Converts the 2D array to a vector of vectors (PIVector>). //! \~russian Преобразует двумерный массив в вектор векторов (PIVector>). - //! \return A new vector where each element is a \a PIVector representing a row. //! \details //! \~english Each row vector is a copy of the corresponding row. //! \~russian Каждый вектор-строка является копией соответствующей строки. @@ -1302,7 +1153,6 @@ public: //! \~english Swaps this 2D array with another. //! \~russian Меняет местами этот двумерный массив с другим. - //! \param other Another array. //! \details //! \~english Swaps the flat vectors and the dimension members. Very fast, no memory allocation. //! \~russian Обменивает внутренние плоские векторы и члены, хранящие размеры. Очень быстро, без выделения памяти. @@ -1336,39 +1186,25 @@ public: //! \~english Checks if the underlying flat vector contains the element `e`. //! \~russian Проверяет, содержит ли внутренний плоский вектор элемент `e`. - //! \param e Element to check. - //! \param start Starting index (negative allowed). Default 0. - //! \return \c true if found, \c false otherwise. //! \sa PIVector::contains() - inline bool contains(const T & e, ssize_t start = 0) const { return mat.contains(e, start); } - - //! \~english Checks if the underlying flat vector contains all elements of `v`. - //! \~russian Проверяет, содержит ли внутренний плоский вектор все элементы `v`. - //! \param e Element to check. - //! \param start Starting index (negative allowed). Default 0. - //! \return \c true if found, \c false otherwise. - //! \sa PIVector::contains(const PIVector&) - inline bool contains(const PIVector & v, ssize_t start = 0) const { return mat.contains(v, start); } + inline bool contains(const T & e) const { return mat.contains(e); } //! \~english Counts occurrences of `e` in the underlying flat vector. //! \~russian Подсчитывает количество вхождений `e` во внутреннем плоском векторе. //! \sa PIVector::entries() - inline int entries(const T & e, ssize_t start = 0) const { return mat.entries(e, start); } + inline int entries(const T & e) const { return mat.entries(e); } //! \~english Counts elements in the flat vector that pass the `test`. //! \~russian Подсчитывает элементы в плоском векторе, проходящие `test`. //! \sa PIVector::entries(std::function) - inline int entries(std::function test, ssize_t start = 0) const { return mat.entries(test, start); } + inline int entries(std::function test) const { return mat.entries(test); } //! \~english Returns the first index (row, col) of `e` in the 2D array. //! \~russian Возвращает первый индекс (строка, столбец) элемента `e` в двумерном массиве. - //! \param e Element to search for. - //! \param start Starting flat index (negative allowed). Default 0. - //! \return A \a PIPair where first is row, second is column. If not found, both are -1. //! \sa PIVector::indexOf() - inline PIPair indexOf(const T & e, ssize_t start = 0) const { - ssize_t flat = mat.indexOf(e, start); + inline PIPair indexOf(const T & e) const { + ssize_t flat = mat.indexOf(e); if (flat < 0 || cols_ == 0) return PIPair(-1, -1); return PIPair(flat / cols_, flat % cols_); } @@ -1413,7 +1249,6 @@ public: //! \~english Fills the entire 2D array with copies of `e`. //! \~russian Заполняет весь двумерный массив копиями `e`. - //! \return Reference to this array. //! \sa PIVector::fill() inline PIVector2D & fill(const T & e = T()) { mat.fill(e); @@ -1422,8 +1257,6 @@ public: //! \~english Fills the entire 2D array using a generator function `f` based on flat index. //! \~russian Заполняет весь двумерный массив, используя функцию-генератор `f` на основе плоского индекса. - //! \param f Function taking a size_t flat index and returning a value of type T. - //! \return Reference to this array. //! \sa PIVector::fill(std::function) inline PIVector2D & fill(std::function f) { mat.fill(f); @@ -1447,7 +1280,6 @@ public: //! \~english Returns a transposed 2D array (rows become columns and vice versa). //! \~russian Возвращает транспонированный двумерный массив (строки становятся столбцами и наоборот). - //! \return A new 2D array with dimensions (cols, rows). //! \details //! \~english The element at (r, c) in the original becomes at (c, r) in the result. //! \~russian Элемент (r, c) исходного массива становится элементом (c, r) в результате. @@ -1468,7 +1300,6 @@ public: //! \~english Reverses the order of rows in place. //! \~russian Изменяет порядок строк на обратный на месте. - //! \return Reference to this array. //! \sa reverseColumns(), PIVector::reverse() inline PIVector2D & reverseRows() { const size_t half = rows_ / 2; @@ -1484,7 +1315,6 @@ public: //! \~english Reverses the order of columns in each row in place. //! \~russian Изменяет порядок столбцов в каждой строке на обратный на месте. - //! \return Reference to this array. //! \sa reverseRows(), PIVector::reverse() inline PIVector2D & reverseColumns() { for (size_t r = 0; r < rows_; ++r) { @@ -1499,19 +1329,14 @@ public: //! \~english Returns a sub-2D array (a range of rows and columns). //! \~russian Возвращает подмассив (диапазон строк и столбцов). - //! \param rowStart Starting row index. - //! \param rowCount Number of rows to take. - //! \param colStart Starting column index. - //! \param colCount Number of columns to take. - //! \return A new 2D array containing the specified range. //! \details //! \~english If the range exceeds the array boundaries, it is clipped. If rowCount or colCount is 0, an empty array is returned. //! \~russian Если диапазон выходит за границы массива, он обрезается. Если rowCount или colCount равны 0, возвращается пустой массив. //! \sa PIVector::getRange() inline PIVector2D 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(); - size_t actualRowCount = piMin(rowCount, rows_ - rowStart); - size_t actualColCount = piMin(colCount, cols_ - colStart); + size_t actualRowCount = piMin(rowCount, rows_ - rowStart); + size_t actualColCount = piMin(colCount, cols_ - colStart); PIVector2D result(actualRowCount, actualColCount); for (size_t r = 0; r < actualRowCount; ++r) { @@ -1524,9 +1349,6 @@ public: //! \~english Applies a function to each element and returns a new 2D array of a different type. //! \~russian Применяет функцию к каждому элементу и возвращает новый двумерный массив другого типа. - //! \tparam ST Target element type. - //! \param f Mapping function: `ST(const T&)`. - //! \return A new \a PIVector2D with the same dimensions. //! \details //! \~english The original array is not modified. //! \~russian Исходный массив не изменяется. @@ -1538,9 +1360,6 @@ public: //! \~english Applies a function (with row and col indices) to each element and returns a new 2D array. //! \~russian Применяет функцию (с индексами строки и столбца) к каждому элементу и возвращает новый двумерный массив. - //! \tparam ST Target element type. - //! \param f Function: `ST(size_t row, size_t col, const T&)`. - //! \return A new \a PIVector2D. //! \sa PIVector::mapIndexed() template inline PIVector2D mapIndexed(std::function f) const { @@ -1556,8 +1375,6 @@ public: //! \~english Applies a function to each row (modifiable). //! \~russian Применяет функцию к каждой строке (с возможностью изменения). - //! \param f Function taking a \a Row. - //! \return Reference to this array. //! \sa forEachRow() const, PIVector::forEach() inline PIVector2D & forEachRow(std::function f) { for (size_t r = 0; r < rows_; ++r) @@ -1567,7 +1384,6 @@ public: //! \~english Applies a function to each row (read-only). //! \~russian Применяет функцию к каждой строке (только чтение). - //! \param f Function taking a \a RowConst. inline void forEachRow(std::function f) const { for (size_t r = 0; r < rows_; ++r) f(row(r)); @@ -1575,8 +1391,6 @@ public: //! \~english Applies a function to each column (modifiable). //! \~russian Применяет функцию к каждому столбцу (с возможностью изменения). - //! \param f Function taking a \a Col. - //! \return Reference to this array. inline PIVector2D & forEachColumn(std::function f) { for (size_t c = 0; c < cols_; ++c) f(col(c)); @@ -1593,10 +1407,6 @@ public: //! \~english Accumulates a value across all elements. //! \~russian Аккумулирует значение по всем элементам. - //! \tparam ST Accumulator type. - //! \param f Reduction function: `ST(const T&, const ST&)`. - //! \param initial Initial accumulator value. Defaults to default-constructed ST. - //! \return The accumulated result. //! \sa PIVector::reduce() template inline ST reduce(std::function f, const ST & initial = ST()) const { @@ -1605,10 +1415,6 @@ public: //! \~english Accumulates a value across all elements with indices. //! \~russian Аккумулирует значение по всем элементам с индексами. - //! \tparam ST Accumulator type. - //! \param f Function: `ST(size_t row, size_t col, const T&, const ST&)`. - //! \param initial Initial accumulator value. - //! \return The accumulated result. //! \sa PIVector::reduceIndexed() template inline ST reduceIndexed(std::function f, const ST & initial = ST()) const { @@ -1623,8 +1429,6 @@ public: //! \~english Removes a row from the 2D array. //! \~russian Удаляет строку из двумерного массива. - //! \param row Index of row to remove (must be less than rows()). - //! \return Reference to this array. //! \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. @@ -1633,8 +1437,7 @@ public: //! \sa removeColumn(), PIVector::remove() inline PIVector2D & removeRow(size_t row) { if (row >= rows_) return *this; - size_t startIdx = row * cols_; - mat.remove(startIdx, cols_); + mat.remove(row * cols_, cols_); rows_--; if (rows_ == 0) cols_ = 0; return *this; @@ -1642,8 +1445,6 @@ public: //! \~english Removes a column from the 2D array. //! \~russian Удаляет столбец из двумерного массива. - //! \param col Index of column to remove (must be less than cols()). - //! \return Reference to this array. //! \details //! \~english This operation is more expensive than removing a row because elements must be moved. //! \~russian Эта операция дороже, чем удаление строки, поскольку требуется перемещение элементов. @@ -1663,35 +1464,29 @@ public: //! \~english Removes all rows that satisfy a condition. //! \~russian Удаляет все строки, удовлетворяющие условию. - //! \param test Predicate taking a \a RowConst. - //! \return Reference to this array. //! \details //! \~english Rows are removed from the bottom to avoid index shifting issues. //! \~russian Строки удаляются снизу вверх, чтобы избежать проблем со смещением индексов. //! \sa removeColumnsWhere(), PIVector::removeWhere() inline PIVector2D & removeRowsWhere(std::function test) { - ssize_t r = rows_ - 1; - while (r >= 0) { + ssize_t r = rows_; + while (--r >= 0) { if (test(RowConst(this, r))) { removeRow(r); } - --r; } return *this; } //! \~english Removes all columns that satisfy a condition. //! \~russian Удаляет все столбцы, удовлетворяющие условию. - //! \param test Predicate taking a \a ColConst. - //! \return Reference to this array. //! \sa removeRowsWhere() inline PIVector2D & removeColumnsWhere(std::function test) { - ssize_t c = cols_ - 1; - while (c >= 0) { + ssize_t c = cols_; + while (--c >= 0) { if (test(ColConst(this, c))) { removeColumn(c); } - --c; } return *this; } @@ -1699,8 +1494,6 @@ public: //! \~english Returns a new 2D array containing only the rows that pass the test. //! \~russian Возвращает новый двумерный массив, содержащий только строки, прошедшие проверку. - //! \param test Predicate taking a \a RowConst. - //! \return Filtered array. //! \sa filterColumns(), PIVector::filter() inline PIVector2D filterRows(std::function test) const { PIVector2D result; @@ -1715,8 +1508,6 @@ public: //! \~english Returns a new 2D array containing only the columns that pass the test. //! \~russian Возвращает новый двумерный массив, содержащий только столбцы, прошедшие проверку. - //! \param test Predicate taking a \a ColConst. - //! \return Filtered array. //! \sa filterRows() inline PIVector2D filterColumns(std::function test) const { if (isEmpty()) return PIVector2D(); @@ -1735,13 +1526,6 @@ public: return result; } - //! \~english Returns a new plain array containing only the elements that pass the test. - //! \~russian Возвращает новый одноменый массив, содержащий только элементы, прошедшие проверку. - //! \param test Predicate taking a const T&. - //! \return PIVector with the filtered elements (or empty). - //! \sa PIVector::filter() - inline PIVector filterElements(std::function test) const { return mat.filter(test); } - protected: size_t rows_, cols_; PIVector mat; diff --git a/libs/main/system/pihidevice.cpp b/libs/main/system/pihidevice.cpp index e1c67818..605c3c46 100644 --- a/libs/main/system/pihidevice.cpp +++ b/libs/main/system/pihidevice.cpp @@ -342,12 +342,12 @@ PIVector PIHIDevice::allDevices(bool try_open) { PIDir hid_dir("/sys/bus/hid/devices"_a); auto hid_devs = hid_dir.entries(); - for (auto hd: hid_devs) { + for (const auto & hd: hid_devs) { // piCout << d.path; if (!isDir(hd)) continue; PIDir dir_input(hd.path + "/input"_a); auto hid_inputs = dir_input.entries(); - for (auto hd_i: hid_inputs) { + for (const auto & hd_i: hid_inputs) { if (!isDir(hd_i)) continue; // now in /sys/bus/hid/devices//input/input // piCout << hd_i.path; @@ -364,7 +364,7 @@ PIVector PIHIDevice::allDevices(bool try_open) { PIDir dir_e(hd_i.path); PIStringList devs; auto dl_e = dir_e.entries(); - for (auto d_e: dl_e) { + for (const auto & d_e: dl_e) { if (!d_e.isDir() || d_e.flags[PIFile::FileInfo::Dot] || d_e.flags[PIFile::FileInfo::DotDot]) continue; devs << d_e.name(); } @@ -392,7 +392,7 @@ PIVector PIHIDevice::allDevices(bool try_open) { if (test_f.isClosed()) continue; } - ullong ev = readFile(hd_i.path + "/capabilities/ev"_a).toULLong(16); + // ullong ev = readFile(hd_i.path + "/capabilities/ev"_a).toULLong(16); auto readAxes = [readFile, checkBit, &hd_i, &dev](const PIString & file, bool is_relative) { PIVector ret; diff --git a/tests/math/testpivector2d.cpp b/tests/math/testpivector2d.cpp index c8d3bb87..3aaf7ae4 100644 --- a/tests/math/testpivector2d.cpp +++ b/tests/math/testpivector2d.cpp @@ -466,7 +466,7 @@ TEST_F(Vector2DTest, addColumn_with_empty_source_does_nothing_on_empty) { } TEST_F(Vector2DTest, addColumn_with_empty_source_adds_default_column) { - auto oldVec = vec; + auto oldVec = vec; vec.addColumn({}); @@ -610,17 +610,15 @@ TEST_F(Vector2DTest, contains_finds_element_in_flat_vector) { TEST_F(Vector2DTest, contains_with_start_parameter_works) { int target = 10 * COLS_COUNT_INIT + 15; EXPECT_TRUE(vec.contains(target)); - EXPECT_TRUE(vec.contains(target, target)); // start exactly at target (inclusive) - EXPECT_FALSE(vec.contains(target, target + 1)); // start after target } TEST_F(Vector2DTest, contains_vector_of_elements_works) { PIVector searchFor; searchFor << 100 << 200 << 300; - EXPECT_TRUE(vec.contains(searchFor)); + EXPECT_TRUE(vec.asPlainVector().containsAll(searchFor)); searchFor << -999; - EXPECT_FALSE(vec.contains(searchFor)); + EXPECT_FALSE(vec.asPlainVector().containsAll(searchFor)); } TEST_F(Vector2DTest, entries_counts_occurrences) { -- 2.43.0 From 6041a72f30178f32699282c5dd12e40b8a636993 Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Thu, 26 Feb 2026 19:42:50 +0300 Subject: [PATCH 09/29] AGENTS.md --- AGENTS.md | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..9144501c --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,170 @@ +# AGENTS.md - Agent Guidelines for PIP + +This file provides guidance for agentic coding agents working on the PIP (Platform Independent Primitives) codebase. + +## Project Overview + +PIP is a C++ cross-platform library providing platform-independent abstractions for: +- Core/Types: Strings, variants, containers, datetime, networks +- Threading: Mutexes, semaphores, thread pools, timers +- I/O: Files, serial, CAN, GPIO, SPI, Ethernet +- Math: Vectors, matrices, FFT, quaternions +- Crypto: MD5, SHA, BLAKE2, SipHash +- Compression: zlib support +- HTTP: Client and server support +- Serialization: JSON, binary, XML + +## Build Commands + +### Basic Build +```bash +cmake -B ../build_pip +cmake --build ../build_pip +``` + +### Build with Tests +```bash +cmake -B ../build_pip -DTESTS=ON +cmake --build ../build_pip +``` + +### Run Tests +```bash +ctest --test-dir ../build_pip/tests/ # Run all tests +ctest --test-dir ../build_pip/tests/ -R # Run specific tests matching regex +ctest --test-dir ../build_pip/tests/ -V # Verbose output +``` + +To run a single test: +```bash +# Build the test executable, then run directly: +../build_pip/tests/pip__test +# Or use ctest with specific test name +ctest --test-dir ../build_pip/tests/ -R "TestName" +``` + +### Other Commands +```bash +cmake --build ../build_pip --target clean # Clean build +cmake --install ../build_pip # Install +cmake --build ../build_pip --target doc # Build documentation +``` + +### Build Options +```bash +-DTESTS=ON # Build tests +-DCOVERAGE=ON # Build with coverage +-DICU=ON # ICU support for codepage conversion +-DSTD_IOSTREAM=ON # std::iostream operators support +-DINTROSPECTION=ON # Build with introspection +-DPIP_BUILD_CRYPT=ON # Crypt module (requires libsodium) +-DPIP_BUILD_FFTW=ON # FFT support +``` + +## Code Style Guidelines + +### File Organization +- Header files: `libs/main/**/*.h` +- Source files: `libs/main/**/*.cpp` +- Private headers: `*_p.h` +- Tests: `tests//` +- Use Doxygen comments (`/*! ... */`) for documentation with `\brief`, `\param`, `\return` + +### Naming Conventions +- **Classes**: PascalCase with `PI` prefix (e.g., `PIString`, `PIByteArray`, `PIVariant`) +- **Functions**: camelCase (e.g., `toAscii()`, `isEmpty()`, `append()`) +- **Member variables**: snake_case, or just lowercase (e.g., `array_size`, `count`) +- **Constants**: PascalCase or UPPER_SNAKE_CASE +- **Enums**: PascalCase for enum names and values + +### Code Formatting +- **Indentation**: Use tabs (4 spaces equivalent) or spaces - match existing code +- **Braces**: Opening brace on same line for functions, new line for namespaces/classes +- **Includes**: System includes first, then project headers +- **Use forward declarations** where possible to reduce compile times +- **Use `nullptr`** instead of `NULL` + +### C++ Standards +- C++11 standard (enforced in CMakeLists.txt) +- Use `override` keyword for virtual function overrides +- Use `explicit` for single-argument constructors +- Use `const` member functions where applicable +- Use range-based `for` loops when possible + +### Error Handling +- Return error codes +- DO NOT USE exceptions +- Use `piCerr` and `piCout` for error messages +- Check for null pointers where appropriate + +### Module Structure + +Each module typically has: +1. Public header: `pip_.h` or `.h` +2. Private implementation: `.cpp` or `_p.cpp` +3. Use `PIP_EXPORT` macro for symbols that need to be exported from the library + +Example class structure: +```cpp +// header.h +#ifndef MODULE_CLASSNAME_H +#define MODULE_CLASSNAME_H + +#include "pip_export.h" + +class PIP_EXPORT ClassName { +public: + ClassName(); + ~ClassName(); + + void doSomething(); + bool isValid() const; + +private: + void privateMethod(); + int data; +}; + +#endif // MODULE_CLASSNAME_H + +// source.cpp +#include "header.h" +#include "piincludes_p.h" + +ClassName::ClassName() : data(0) {} +``` + +### Testing +- Use Google Test framework +- Test files go in `tests//` +- Use `TEST(TestSuite, TestName)` or `TEST_F(TestFixture, TestName)` for test cases +- Use `ASSERT_*` for fatal failures, `EXPECT_*` for non-fatal +- Test naming: `_` + +Example: +```cpp +#include "pistring.h" +#include "gtest/gtest.h" + +TEST(PIString_Tests, constructor_empty) { + PIString str; + ASSERT_TRUE(str.isEmpty()); +} +``` + +### Module Dependencies +- Main library: `libs/main/` +- Third-party: `3rd/` +- Utils: `utils/` + +### Important Macros +- `PIP_EXPORT` - Export symbol from shared library +- `PIP_NO_EXPORT` - Don't export +- `PIP_DEPRECATED` - Mark as deprecated +- Conditional compilation: `#ifdef PIP_ICU`, `#ifdef WINDOWS`, etc. + +### Key Files +- `CMakeLists.txt` - Main build configuration +- `libs/main/pip.h` - Master include +- `libs/main/piplatform.h` - Platform definitions +- `tests/CMakeLists.txt` - Test configuration -- 2.43.0 From 35772fc2d146c1832b78142f69dd2dd8483d0f3c Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Thu, 26 Feb 2026 19:43:13 +0300 Subject: [PATCH 10/29] plan for pivector2d --- plans/pivector2d.md | 70 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 plans/pivector2d.md diff --git a/plans/pivector2d.md b/plans/pivector2d.md new file mode 100644 index 00000000..b1d54ab1 --- /dev/null +++ b/plans/pivector2d.md @@ -0,0 +1,70 @@ +# План рефакторинга PIVector2D + +## Этап 1: Выполнить наследование Row от RowConst, Col от ColConst + +### 1.1 Переместить RowConst перед Row +- Найти местоположение RowConst (текущая позиция ~строка 610) +- Переместить определение RowConst перед Row (до строки ~184) + +### 1.2 Переместить ColConst перед Col +- Найти местоположение ColConst (текущая позиция ~строка 770) +- Переместить определение ColConst перед Col (до строки ~402) + +### 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: Заменить PIPair на PIVector2DIndex + +### 2.1 Создать структуру PIVector2DIndex +```cpp +struct PIVector2DIndex { + ssize_t row; + ssize_t col; +}; +``` + +### 2.2 Обновить return types +Методы для изменения: +- indexOf() -> возвращает PIVector2DIndex вместо PIPair +- lastIndexOf() +- indexWhere() +- lastIndexWhere() + +### 2.3 Обновить тесты и документацию + +--- + +## Этап 3: Дополнительные улучшения (опционально) + +- Добавить методы для работы с диапазонами +- Оптимизировать методы удаления строк/столбцов +- Добавить проверку границ в debug-режиме -- 2.43.0 From a581d9bf9dc22e99ea02f1984f7bbf64fc340050 Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Thu, 26 Feb 2026 19:49:42 +0300 Subject: [PATCH 11/29] fix build and test commands --- AGENTS.md | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 9144501c..59d1eedd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -18,36 +18,36 @@ PIP is a C++ cross-platform library providing platform-independent abstractions ### Basic Build ```bash -cmake -B ../build_pip -cmake --build ../build_pip +cmake -B build +cmake --build build ``` ### Build with Tests ```bash -cmake -B ../build_pip -DTESTS=ON -cmake --build ../build_pip +cmake -B build -DTESTS=ON +cmake --build build ``` ### Run Tests ```bash -ctest --test-dir ../build_pip/tests/ # Run all tests -ctest --test-dir ../build_pip/tests/ -R # Run specific tests matching regex -ctest --test-dir ../build_pip/tests/ -V # Verbose output +ctest --test-dir build/tests # Run all tests +ctest --test-dir build/tests -R # Run specific tests matching regex +ctest --test-dir build/tests -V # Verbose output ``` To run a single test: ```bash # Build the test executable, then run directly: -../build_pip/tests/pip__test +./build/tests/pip__test # Or use ctest with specific test name -ctest --test-dir ../build_pip/tests/ -R "TestName" +ctest --test-dir build/tests -R "TestName" ``` ### Other Commands ```bash -cmake --build ../build_pip --target clean # Clean build -cmake --install ../build_pip # Install -cmake --build ../build_pip --target doc # Build documentation +cmake --build build --target clean # Clean build +cmake --install build_pip # Install +cmake --build build --target doc # Build documentation ``` ### Build Options @@ -157,14 +157,6 @@ TEST(PIString_Tests, constructor_empty) { - Third-party: `3rd/` - Utils: `utils/` -### Important Macros -- `PIP_EXPORT` - Export symbol from shared library -- `PIP_NO_EXPORT` - Don't export -- `PIP_DEPRECATED` - Mark as deprecated -- Conditional compilation: `#ifdef PIP_ICU`, `#ifdef WINDOWS`, etc. - ### Key Files - `CMakeLists.txt` - Main build configuration -- `libs/main/pip.h` - Master include -- `libs/main/piplatform.h` - Platform definitions - `tests/CMakeLists.txt` - Test configuration -- 2.43.0 From 91b20467a7399b378f1a047db9ac1cd833aaa51a Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Thu, 26 Feb 2026 21:29:30 +0300 Subject: [PATCH 12/29] pivector2d move implement Row and Col --- AGENTS.md | 6 +- libs/main/containers/pivector2d.h | 628 +++++++++++++++--------------- 2 files changed, 323 insertions(+), 311 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 59d1eedd..8a65e260 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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 diff --git a/libs/main/containers/pivector2d.h b/libs/main/containers/pivector2d.h index f30b2bcd..72199c03 100644 --- a/libs/main/containers/pivector2d.h +++ b/libs/main/containers/pivector2d.h @@ -180,6 +180,323 @@ public: //! \sa isEmpty(), PIVector::isNotEmpty() inline bool isNotEmpty() const { return mat.isNotEmpty(); } + class RowConst; + class ColConst; + class Row; + class Col; + + + //! \class RowConst + //! \brief + //! \~english Proxy class representing a single read-only row in a \a PIVector2D. + //! \~russian Прокси-класс, представляющий одну строку в \a PIVector2D только для чтения. + //! \details + //! \~english Returned by const \a operator[] or \a row(). Provides const access to row elements. + //! \~russian Возвращается константными версиями \a operator[] или \a row(). Предоставляет константный доступ к элементам строки. + //! \sa Row, ColConst + class RowConst { + friend class PIVector2D; + + protected: + inline RowConst(const PIVector2D * p, size_t row): p_(&(p->mat)) { + st_ = p->cols_ * row; + sz_ = p->cols_; + } + const PIVector * p_; + size_t st_, sz_; + + public: + inline RowConst(const PIVector2D::Row & r): p_(r.p_) { + st_ = r.st_; + sz_ = r.sz_; + } + + //! \~english Size of the row (number of columns). + //! \~russian Размер строки (количество столбцов). + inline size_t size() const { return sz_; } + + //! \~english Const access to the element at the given column index within the row. + //! \~russian Константный доступ к элементу по заданному индексу столбца в строке. + inline const T & operator[](size_t index) const { return (*p_)[st_ + index]; } + + //! \~english Returns a const pointer to the row data starting at an optional offset. + //! \~russian Возвращает константный указатель на данные строки, начиная с опционального смещения. + inline const T * data(size_t index = 0) const { return p_->data(st_ + index); } + + //! \~english Converts the row to a \a PIVector. + //! \~russian Преобразует строку в \a PIVector. + inline PIVector toVector() const { return PIVector(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`. + //! \return Index if found, -1 otherwise. + //! \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 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 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 (read-only). + //! \~russian Применяет функцию к каждому элементу строки (только чтение). + //! \details + //! \~english The function can't modify the elements. + //! \~russian Функция не может изменять элементы. + //! \sa forEach (modifiable) + inline void forEach(std::function func) const { + for (size_t i = 0; i < sz_; ++i) { + func((*p_)[st_ + i]); + } + } + + //! \~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 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 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 test) const { + for (size_t i = 0; i < sz_; ++i) { + if (!test((*p_)[st_ + i])) return false; + } + return true; + } + }; + + + //! \class ColConst + //! \brief + //! \~english Proxy class representing a single read-only column in a \a PIVector2D. + //! \~russian Прокси-класс, представляющий один столбец в \a PIVector2D только для чтения. + //! \details + //! \~english Returned by const \a col(). Provides const access to column elements. + //! \~russian Возвращается константной версией \a col(). Предоставляет константный доступ к элементам столбца. + //! \sa Col, RowConst + class ColConst { + friend class PIVector2D; + + protected: + inline ColConst(const PIVector2D * p, size_t col): p_(&(p->mat)) { + step_ = p->cols_; + col_ = col; + sz_ = p->rows_; + } + const PIVector * p_; + size_t step_, col_, sz_; + + public: + inline ColConst(const PIVector2D::Col & c): p_(c.p_) { + step_ = c.step_; + col_ = c.col_; + sz_ = c.sz_; + } + + //! \~english Size of the column (number of rows). + //! \~russian Размер столбца (количество строк). + inline size_t size() const { return sz_; } + + //! \~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 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 Converts the column to a \a PIVector. + //! \~russian Преобразует столбец в \a PIVector. + inline PIVector toVector() const { + PIVector ret; + ret.reserve(sz_); + for (size_t i = 0; i < size(); 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 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 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 (read-only). + //! \~russian Применяет функцию к каждому элементу столбца (только чтение). + //! \details + //! \~english The function can't modify the elements. + //! \~russian Функция не может изменять элементы. + //! \sa forEach (modifiable) + inline void forEach(std::function func) const { + for (size_t i = 0; i < sz_; ++i) { + func((*p_)[i * step_ + col_]); + } + } + + //! \~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 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 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 test) const { + for (size_t i = 0; i < sz_; ++i) { + if (!test((*p_)[i * step_ + col_])) return false; + } + return true; + } + }; //! \class Row //! \brief @@ -399,6 +716,7 @@ public: } }; + //! \class Col //! \brief //! \~english Proxy class representing a single column in a \a PIVector2D for modification. @@ -607,316 +925,6 @@ public: } }; - //! \class RowConst - //! \brief - //! \~english Proxy class representing a single read-only row in a \a PIVector2D. - //! \~russian Прокси-класс, представляющий одну строку в \a PIVector2D только для чтения. - //! \details - //! \~english Returned by const \a operator[] or \a row(). Provides const access to row elements. - //! \~russian Возвращается константными версиями \a operator[] или \a row(). Предоставляет константный доступ к элементам строки. - //! \sa Row, ColConst - class RowConst { - friend class PIVector2D; - - private: - inline RowConst(const PIVector2D * p, size_t row): p_(&(p->mat)) { - st_ = p->cols_ * row; - sz_ = p->cols_; - } - const PIVector * p_; - size_t st_, sz_; - - public: - inline RowConst(const PIVector2D::Row & r): p_(r.p_) { - st_ = r.st_; - sz_ = r.sz_; - } - - //! \~english Size of the row (number of columns). - //! \~russian Размер строки (количество столбцов). - inline size_t size() const { return sz_; } - - //! \~english Const access to the element at the given column index within the row. - //! \~russian Константный доступ к элементу по заданному индексу столбца в строке. - inline const T & operator[](size_t index) const { return (*p_)[st_ + index]; } - - //! \~english Returns a const pointer to the row data starting at an optional offset. - //! \~russian Возвращает константный указатель на данные строки, начиная с опционального смещения. - inline const T * data(size_t index = 0) const { return p_->data(st_ + index); } - - //! \~english Converts the row to a \a PIVector. - //! \~russian Преобразует строку в \a PIVector. - inline PIVector toVector() const { return PIVector(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`. - //! \return Index if found, -1 otherwise. - //! \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 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 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 (read-only). - //! \~russian Применяет функцию к каждому элементу строки (только чтение). - //! \details - //! \~english The function can't modify the elements. - //! \~russian Функция не может изменять элементы. - //! \sa forEach (modifiable) - inline void forEach(std::function func) const { - for (size_t i = 0; i < sz_; ++i) { - func((*p_)[st_ + i]); - } - } - - //! \~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 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 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 test) const { - for (size_t i = 0; i < sz_; ++i) { - if (!test((*p_)[st_ + i])) return false; - } - return true; - } - }; - - //! \class ColConst - //! \brief - //! \~english Proxy class representing a single read-only column in a \a PIVector2D. - //! \~russian Прокси-класс, представляющий один столбец в \a PIVector2D только для чтения. - //! \details - //! \~english Returned by const \a col(). Provides const access to column elements. - //! \~russian Возвращается константной версией \a col(). Предоставляет константный доступ к элементам столбца. - //! \sa Col, RowConst - class ColConst { - friend class PIVector2D; - - private: - inline ColConst(const PIVector2D * p, size_t col): p_(&(p->mat)) { - step_ = p->cols_; - col_ = col; - sz_ = p->rows_; - } - const PIVector * p_; - size_t step_, col_, sz_; - - public: - inline ColConst(const PIVector2D::Col & c): p_(c.p_) { - step_ = c.step_; - col_ = c.col_; - sz_ = c.sz_; - } - - //! \~english Size of the column (number of rows). - //! \~russian Размер столбца (количество строк). - inline size_t size() const { return sz_; } - - //! \~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 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 Converts the column to a \a PIVector. - //! \~russian Преобразует столбец в \a PIVector. - inline PIVector toVector() const { - PIVector ret; - ret.reserve(sz_); - for (size_t i = 0; i < size(); 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 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 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 (read-only). - //! \~russian Применяет функцию к каждому элементу столбца (только чтение). - //! \details - //! \~english The function can't modify the elements. - //! \~russian Функция не может изменять элементы. - //! \sa forEach (modifiable) - inline void forEach(std::function func) const { - for (size_t i = 0; i < sz_; ++i) { - func((*p_)[i * step_ + col_]); - } - } - - //! \~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 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 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 test) const { - for (size_t i = 0; i < sz_; ++i) { - if (!test((*p_)[i * step_ + col_])) return false; - } - return true; - } - }; //! \~english Returns a reference to the element at the given row and column. //! \~russian Возвращает ссылку на элемент по заданной строке и столбцу. -- 2.43.0 From 071ab85359fe77f48de38ecd8040f8568a4a8aa8 Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Thu, 26 Feb 2026 21:35:14 +0300 Subject: [PATCH 13/29] fix plan --- plans/pivector2d.md | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/plans/pivector2d.md b/plans/pivector2d.md index b1d54ab1..8bbb5d20 100644 --- a/plans/pivector2d.md +++ b/plans/pivector2d.md @@ -2,15 +2,10 @@ ## Этап 1: Выполнить наследование Row от RowConst, Col от ColConst -### 1.1 Переместить RowConst перед Row -- Найти местоположение RowConst (текущая позиция ~строка 610) -- Переместить определение RowConst перед Row (до строки ~184) +### 1.1 Найти классы Col, Row, ColConst и RowConst +- они находятся в файле `libs/main/containers/pivector2d.h` -### 1.2 Переместить ColConst перед Col -- Найти местоположение ColConst (текущая позиция ~строка 770) -- Переместить определение ColConst перед Col (до строки ~402) - -### 1.3 Изменить класс Row +### 1.2 Изменить класс Row - Наследовать от RowConst: `class Row : public RowConst` - Убрать дублирующиеся методы (они унаследованы от RowConst): - size() @@ -33,12 +28,15 @@ - forEach() (неконстантный) - fill() -### 1.4 Изменить класс Col +### 1.3 Изменить класс Col - Наследовать от ColConst: `class Col : public ColConst` - Аналогично убрать дублирующиеся методы +### 1.4 Собрать проект +- собери проект, при необходимости поправь ошибки + ### 1.5 Проверить тесты -- Запустить: `./pip_math_test --gtest_filter="*Vector2D*"` +- Запустить: `./build/tests/pip_math_test --gtest_filter="*Vector2D*"` --- -- 2.43.0 From 42b2fd4dbec1a84ad83dec6e4d9c8028ca375660 Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Thu, 26 Feb 2026 22:16:28 +0300 Subject: [PATCH 14/29] update plan --- plans/pivector2d.md | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/plans/pivector2d.md b/plans/pivector2d.md index 8bbb5d20..8d869c4c 100644 --- a/plans/pivector2d.md +++ b/plans/pivector2d.md @@ -34,15 +34,21 @@ ### 1.4 Собрать проект - собери проект, при необходимости поправь ошибки +- тесты не трогай -### 1.5 Проверить тесты +## Этап 2: Проверить и поправить тесты + +### 2.1 Запустить тесты - Запустить: `./build/tests/pip_math_test --gtest_filter="*Vector2D*"` +### 2.2 Поправить код или тесты +- внести правки в pivector2d.h + --- -## Этап 2: Заменить PIPair на PIVector2DIndex +## Этап 3: Заменить PIPair на PIVector2DIndex -### 2.1 Создать структуру PIVector2DIndex +### 3.1 Создать структуру PIVector2DIndex ```cpp struct PIVector2DIndex { ssize_t row; @@ -50,19 +56,12 @@ struct PIVector2DIndex { }; ``` -### 2.2 Обновить return types +### 3.2 Обновить return types Методы для изменения: - indexOf() -> возвращает PIVector2DIndex вместо PIPair - lastIndexOf() - indexWhere() - lastIndexWhere() -### 2.3 Обновить тесты и документацию --- - -## Этап 3: Дополнительные улучшения (опционально) - -- Добавить методы для работы с диапазонами -- Оптимизировать методы удаления строк/столбцов -- Добавить проверку границ в debug-режиме -- 2.43.0 From 6557933a2ef5d89ebf0b8f72064267323b8e96a3 Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Thu, 26 Feb 2026 22:58:47 +0300 Subject: [PATCH 15/29] doxygen docs plan --- plans/doxygen_docs.md | 337 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 337 insertions(+) create mode 100644 plans/doxygen_docs.md diff --git a/plans/doxygen_docs.md b/plans/doxygen_docs.md new file mode 100644 index 00000000..771e2f43 --- /dev/null +++ b/plans/doxygen_docs.md @@ -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 +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 +inline bool operator==(const PIPair & value0, const PIPair & 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 + //! \{ + //! \file + //! \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 -- 2.43.0 From 42a1507536682986e721e2249e74a0b35f1150c9 Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Fri, 27 Feb 2026 00:07:00 +0300 Subject: [PATCH 16/29] i and ai refactor pivector2d --- AGENTS.md | 4 +- dependencies.md | 70 ++++++ libs/main/containers/pivector2d.h | 382 +++++------------------------- options.md | 59 +++++ plans/pivector2d.md | 41 +--- tests/math/testpivector2d.cpp | 24 +- 6 files changed, 202 insertions(+), 378 deletions(-) create mode 100644 dependencies.md create mode 100644 options.md diff --git a/AGENTS.md b/AGENTS.md index 8a65e260..270ffd38 100644 --- a/AGENTS.md +++ b/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 diff --git a/dependencies.md b/dependencies.md new file mode 100644 index 00000000..d0bfcadc --- /dev/null +++ b/dependencies.md @@ -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 +``` diff --git a/libs/main/containers/pivector2d.h b/libs/main/containers/pivector2d.h index 72199c03..e1006d46 100644 --- a/libs/main/containers/pivector2d.h +++ b/libs/main/containers/pivector2d.h @@ -52,6 +52,14 @@ template class PIVector2D { public: + //! \brief + //! \~english Index structure for 2D array elements (row, column). + //! \~russian Структура индекса для элементов двумерного массива (строка, столбец). + struct Index { + ssize_t row; + ssize_t col; + }; + //! \~english Constructs an empty 2D array. No memory is allocated. //! \~russian Создаёт пустой двумерный массив. Память не выделяется. //! \details @@ -198,18 +206,12 @@ public: friend class PIVector2D; protected: - inline RowConst(const PIVector2D * p, size_t row): p_(&(p->mat)) { - st_ = p->cols_ * row; - sz_ = p->cols_; - } + inline RowConst(const PIVector2D * p, size_t row): p_(&(p->mat)), st_(p->cols_ * row), sz_(p->cols_) {} const PIVector * p_; - size_t st_, sz_; + const size_t st_, sz_; public: - inline RowConst(const PIVector2D::Row & r): p_(r.p_) { - st_ = r.st_; - sz_ = r.sz_; - } + inline RowConst(const PIVector2D::Row & r): p_(r.p_), st_(r.st_), sz_(r.sz_) {} //! \~english Size of the row (number of columns). //! \~russian Размер строки (количество столбцов). @@ -351,20 +353,12 @@ public: friend class PIVector2D; protected: - inline ColConst(const PIVector2D * p, size_t col): p_(&(p->mat)) { - step_ = p->cols_; - col_ = col; - sz_ = p->rows_; - } + inline ColConst(const PIVector2D * p, size_t col): p_(&(p->mat)), step_(p->cols_), col_(col), sz_(p->rows_) {} const PIVector * p_; - size_t step_, col_, sz_; + const size_t step_, col_, sz_; public: - inline ColConst(const PIVector2D::Col & c): p_(c.p_) { - step_ = c.step_; - col_ = c.col_; - sz_ = c.sz_; - } + inline ColConst(const PIVector2D::Col & c): p_(c.p_), step_(c.step_), col_(c.col_), sz_(c.sz_) {} //! \~english Size of the column (number of rows). //! \~russian Размер столбца (количество строк). @@ -509,23 +503,17 @@ public: //! \~russian Объекты этого класса возвращаются неконстантными операторами \a operator[] или методом \a row(). //! Они предоставляют доступ к элементам конкретной строки, подобный массиву, и позволяют выполнять такие операции, как присваивание из //! другой строки или \a PIVector, поиск, заполнение и итерацию. \sa Col, RowConst - class Row { + class Row: public RowConst { friend class PIVector2D; private: - inline Row(PIVector2D * p, size_t row): p_(&(p->mat)) { - st_ = p->cols_ * row; - sz_ = p->cols_; - } + inline Row(PIVector2D * p, size_t row): RowConst(p, row), p_(&(p->mat)) {} PIVector * 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_; } + using RowConst::operator[]; + using RowConst::data; + using RowConst::size; //! \~english Accesses the element at the given column index within the row. //! \~russian Доступ к элементу по заданному индексу столбца в строке. @@ -533,12 +521,7 @@ public: //! \~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]; } + 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 Возвращает указатель на данные строки, начиная с опционального смещения. @@ -547,12 +530,7 @@ public: //! 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); } + inline T * data(size_t index = 0) { return p_->data(this->st_ + index); } //! \~english Assigns the contents of another Row to this row. //! \~russian Присваивает этой строке содержимое другой строки. @@ -561,9 +539,9 @@ public: //! \~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(sz_, other.sz_); - p_->_copyRaw(p_->data(st_), other.data(), sz); + if (p_ == other.p_ && this->st_ == other.st_) return *this; + const size_t sz = piMin(this->sz_, other.sz_); + p_->_copyRaw(p_->data(this->st_), other.data(), sz); return *this; } @@ -574,64 +552,11 @@ public: //! \~russian Копируется только минимум из размера строки и размера вектора. //! \sa PIVector::operator= inline Row & operator=(const PIVector & other) { - const size_t sz = piMin(sz_, other.size()); - p_->_copyRaw(p_->data(st_), other.data(), sz); + const size_t sz = piMin(this->sz_, other.size()); + p_->_copyRaw(p_->data(this->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 toVector() const { return PIVector(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 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 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. @@ -640,20 +565,8 @@ public: //! \~russian Функция может изменять элементы. //! \sa PIVector::forEach() inline void forEach(std::function 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 func) const { - for (size_t i = 0; i < sz_; ++i) { - func((*p_)[st_ + i]); + for (size_t i = 0; i < this->sz_; ++i) { + func((*p_)[this->st_ + i]); } } @@ -661,59 +574,10 @@ public: //! \~russian Заполняет строку копиями `value`. //! \sa PIVector::fill() inline void fill(const T & value) { - for (size_t i = 0; i < sz_; ++i) { - (*p_)[st_ + i] = value; + for (size_t i = 0; i < this->sz_; ++i) { + (*p_)[this->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 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 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 test) const { - for (size_t i = 0; i < sz_; ++i) { - if (!test((*p_)[st_ + i])) return false; - } - return true; - } }; @@ -726,31 +590,18 @@ public: //! Row. //! \~russian Объекты этого класса возвращаются неконстантным методом \a col(). Они предоставляют доступ к столбцам и операции, //! аналогичные \a Row. \sa Row, ColConst - class Col { + class Col: public ColConst { friend class PIVector2D; private: - inline Col(PIVector2D * p, size_t col): p_(&(p->mat)) { - step_ = p->cols_; - col_ = col; - sz_ = p->rows_; - } + inline Col(PIVector2D * p, size_t col): ColConst(p, col), p_(&(p->mat)) {} PIVector * 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_]; } + 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 Возвращает указатель на данные столбца, начиная с опционального смещения по строкам. @@ -759,89 +610,27 @@ public: //! 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_); } + 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_ && col_ == other.col_) return *this; - const size_t sz = piMin(sz_, other.sz_); + if (p_ == other.p_ && this->col_ == other.col_) return *this; + const size_t sz = piMin(this->sz_, other.sz_); for (size_t i = 0; i < sz; ++i) - (*p_)[i * step_ + col_] = other[i]; + (*p_)[i * this->step_ + this->col_] = other.ColConst::operator[](i); return *this; } //! \~english Assigns the contents of a \a PIVector to this column. //! \~russian Присваивает этому столбцу содержимое \a PIVector. inline Col & operator=(const PIVector & other) { - const size_t sz = piMin(sz_, other.size()); + const size_t sz = piMin(this->sz_, other.size()); for (size_t i = 0; i < sz; ++i) - (*p_)[i * step_ + col_] = other[i]; + (*p_)[i * this->step_ + this->col_] = other[i]; return *this; } - //! \~english Converts the column to a \a PIVector. - //! \~russian Преобразует столбец в \a PIVector. - inline PIVector toVector() const { - PIVector 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 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 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 @@ -849,20 +638,8 @@ public: //! \~russian Функция может изменять элементы. //! \sa PIVector::forEach() inline void forEach(std::function 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 func) const { - for (size_t i = 0; i < sz_; ++i) { - func((*p_)[i * step_ + col_]); + for (size_t i = 0; i < this->sz_; ++i) { + func((*p_)[i * this->step_ + this->col_]); } } @@ -870,59 +647,10 @@ public: //! \~russian Заполняет столбец копиями `value`. //! \sa PIVector::fill() inline void fill(const T & value) { - for (size_t i = 0; i < sz_; ++i) { - (*p_)[i * step_ + col_] = value; + for (size_t i = 0; i < this->sz_; ++i) { + (*p_)[i * this->step_ + this->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 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 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 test) const { - for (size_t i = 0; i < sz_; ++i) { - if (!test((*p_)[i * step_ + col_])) return false; - } - return true; - } }; @@ -1211,37 +939,37 @@ public: //! \~english Returns the first index (row, col) of `e` in the 2D array. //! \~russian Возвращает первый индекс (строка, столбец) элемента `e` в двумерном массиве. //! \sa PIVector::indexOf() - inline PIPair 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(-1, -1); - return PIPair(flat / cols_, flat % cols_); + if (flat < 0 || cols_ == 0) return Index{-1, -1}; + return Index{flat / cols_, flat % cols_}; } //! \~english Returns the first index (row, col) in the 2D array that passes the `test`. //! \~russian Возвращает первый индекс (строка, столбец) в двумерном массиве, проходящий `test`. //! \sa PIVector::indexWhere() - inline PIPair indexWhere(std::function test, ssize_t start = 0) const { + inline Index indexWhere(std::function test, ssize_t start = 0) const { ssize_t flat = mat.indexWhere(test, start); - if (flat < 0 || cols_ == 0) return PIPair(-1, -1); - return PIPair(flat / cols_, flat % cols_); + if (flat < 0 || cols_ == 0) return Index{-1, -1}; + return Index{flat / cols_, flat % cols_}; } //! \~english Returns the last index (row, col) of `e` in the 2D array. //! \~russian Возвращает последний индекс (строка, столбец) элемента `e` в двумерном массиве. //! \sa PIVector::lastIndexOf() - inline PIPair 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(-1, -1); - return PIPair(flat / cols_, flat % cols_); + if (flat < 0 || cols_ == 0) return Index{-1, -1}; + return Index{flat / cols_, flat % cols_}; } //! \~english Returns the last index (row, col) in the 2D array that passes the `test`. //! \~russian Возвращает последний индекс (строка, столбец) в двумерном массиве, проходящий `test`. //! \sa PIVector::lastIndexWhere() - inline PIPair lastIndexWhere(std::function test, ssize_t start = -1) const { + inline Index lastIndexWhere(std::function test, ssize_t start = -1) const { ssize_t flat = mat.lastIndexWhere(test, start); - if (flat < 0 || cols_ == 0) return PIPair(-1, -1); - return PIPair(flat / cols_, flat % cols_); + if (flat < 0 || cols_ == 0) return Index{-1, -1}; + return Index{flat / cols_, flat % cols_}; } diff --git a/options.md b/options.md new file mode 100644 index 00000000..ecc938d1 --- /dev/null +++ b/options.md @@ -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 +``` diff --git a/plans/pivector2d.md b/plans/pivector2d.md index 8d869c4c..c59c0cf5 100644 --- a/plans/pivector2d.md +++ b/plans/pivector2d.md @@ -1,48 +1,15 @@ # План рефакторинга PIVector2D -## Этап 1: Выполнить наследование Row от RowConst, Col от ColConst +## Этап 1: Сборка -### 1.1 Найти классы Col, Row, ColConst и RowConst -- они находятся в файле `libs/main/containers/pivector2d.h` - -### 1.2 Изменить класс 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.3 Изменить класс Col -- Наследовать от ColConst: `class Col : public ColConst` -- Аналогично убрать дублирующиеся методы - -### 1.4 Собрать проект +### 1.1 Собрать проект - собери проект, при необходимости поправь ошибки -- тесты не трогай ## Этап 2: Проверить и поправить тесты ### 2.1 Запустить тесты - Запустить: `./build/tests/pip_math_test --gtest_filter="*Vector2D*"` - -### 2.2 Поправить код или тесты -- внести правки в pivector2d.h +- В случае ошибок внести правки в pivector2d.h --- @@ -50,7 +17,7 @@ ### 3.1 Создать структуру PIVector2DIndex ```cpp -struct PIVector2DIndex { +struct Index { ssize_t row; ssize_t col; }; diff --git a/tests/math/testpivector2d.cpp b/tests/math/testpivector2d.cpp index 3aaf7ae4..e0f626ae 100644 --- a/tests/math/testpivector2d.cpp +++ b/tests/math/testpivector2d.cpp @@ -952,38 +952,38 @@ 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); + EXPECT_EQ(lastFlat, expectedLastFlat); } TEST_F(Vector2DTest, reduce_accumulates_correctly) { -- 2.43.0 From b01aecc2fed9ea2d16b5d5d7c9ec7fb30a1fc4a3 Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Fri, 27 Feb 2026 00:18:40 +0300 Subject: [PATCH 17/29] =?UTF-8?q?=D0=B3=D0=BE=D1=82=D0=BE=D0=B2=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/main/containers/pivector2d.h | 15 +++++++++------ plans/pivector2d.md | 22 ++++++++-------------- tests/math/testpivector2d.cpp | 22 +++++++++++----------- 3 files changed, 28 insertions(+), 31 deletions(-) diff --git a/libs/main/containers/pivector2d.h b/libs/main/containers/pivector2d.h index e1006d46..15e38c2c 100644 --- a/libs/main/containers/pivector2d.h +++ b/libs/main/containers/pivector2d.h @@ -25,7 +25,6 @@ #ifndef PIVECTOR2D_H #define PIVECTOR2D_H -#include "pipair.h" #include "pivector.h" //! \addtogroup Containers @@ -598,6 +597,10 @@ public: PIVector * 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. @@ -618,7 +621,7 @@ public: if (p_ == other.p_ && this->col_ == other.col_) return *this; const size_t sz = piMin(this->sz_, other.sz_); for (size_t i = 0; i < sz; ++i) - (*p_)[i * this->step_ + this->col_] = other.ColConst::operator[](i); + (*p_)[i * this->step_ + this->col_] = other[i]; return *this; } @@ -942,7 +945,7 @@ public: inline Index indexOf(const T & e) const { ssize_t flat = mat.indexOf(e); if (flat < 0 || cols_ == 0) return Index{-1, -1}; - return Index{flat / cols_, flat % cols_}; + return Index{flat / static_cast(cols_), flat % static_cast(cols_)}; } //! \~english Returns the first index (row, col) in the 2D array that passes the `test`. @@ -951,7 +954,7 @@ public: inline Index indexWhere(std::function test, ssize_t start = 0) const { ssize_t flat = mat.indexWhere(test, start); if (flat < 0 || cols_ == 0) return Index{-1, -1}; - return Index{flat / cols_, flat % cols_}; + return Index{flat / static_cast(cols_), flat % static_cast(cols_)}; } //! \~english Returns the last index (row, col) of `e` in the 2D array. @@ -960,7 +963,7 @@ public: inline Index lastIndexOf(const T & e, ssize_t start = -1) const { ssize_t flat = mat.lastIndexOf(e, start); if (flat < 0 || cols_ == 0) return Index{-1, -1}; - return Index{flat / cols_, flat % cols_}; + return Index{flat / static_cast(cols_), flat % static_cast(cols_)}; } //! \~english Returns the last index (row, col) in the 2D array that passes the `test`. @@ -969,7 +972,7 @@ public: inline Index lastIndexWhere(std::function test, ssize_t start = -1) const { ssize_t flat = mat.lastIndexWhere(test, start); if (flat < 0 || cols_ == 0) return Index{-1, -1}; - return Index{flat / cols_, flat % cols_}; + return Index{flat / static_cast(cols_), flat % static_cast(cols_)}; } diff --git a/plans/pivector2d.md b/plans/pivector2d.md index c59c0cf5..6e9c751a 100644 --- a/plans/pivector2d.md +++ b/plans/pivector2d.md @@ -3,32 +3,26 @@ ## Этап 1: Сборка ### 1.1 Собрать проект -- собери проект, при необходимости поправь ошибки +- [x] собери проект, при необходимости поправь ошибки ## Этап 2: Проверить и поправить тесты ### 2.1 Запустить тесты -- Запустить: `./build/tests/pip_math_test --gtest_filter="*Vector2D*"` -- В случае ошибок внести правки в pivector2d.h +- [x] Запустить: `./build/tests/pip_math_test --gtest_filter="*Vector2D*"` +- [x] В случае ошибок внести правки в pivector2d.h --- ## Этап 3: Заменить PIPair на PIVector2DIndex ### 3.1 Создать структуру PIVector2DIndex -```cpp -struct Index { - ssize_t row; - ssize_t col; -}; -``` +- [x] Создано: `struct Index { ssize_t row; ssize_t col; };` ### 3.2 Обновить return types -Методы для изменения: -- indexOf() -> возвращает PIVector2DIndex вместо PIPair -- lastIndexOf() -- indexWhere() -- lastIndexWhere() +- [x] indexOf() -> возвращает Index вместо PIPair +- [x] lastIndexOf() +- [x] indexWhere() +- [x] lastIndexWhere() --- diff --git a/tests/math/testpivector2d.cpp b/tests/math/testpivector2d.cpp index e0f626ae..c12aa631 100644 --- a/tests/math/testpivector2d.cpp +++ b/tests/math/testpivector2d.cpp @@ -952,38 +952,38 @@ 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.row, 10); - EXPECT_EQ(p.col, 15); + EXPECT_EQ(p.row, 10); + EXPECT_EQ(p.col, 15); p = vec.indexOf(-999); - EXPECT_EQ(p.row, -1); - EXPECT_EQ(p.col, -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.row, 5); - EXPECT_EQ(p.col, 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.row, 20); - EXPECT_EQ(p.col, 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.row, 0); - EXPECT_GE(p.col, 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.row * vec.cols() + p.col; size_t expectedLastFlat = vec.size() - 1; - EXPECT_EQ(lastFlat, expectedLastFlat); + EXPECT_EQ(lastFlat, expectedLastFlat); } TEST_F(Vector2DTest, reduce_accumulates_correctly) { -- 2.43.0 From 56ff28c7937fa603e83a131e8ebba086aeea1db3 Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Fri, 27 Feb 2026 00:34:56 +0300 Subject: [PATCH 18/29] add PIVector2D Index --- libs/main/containers/pivector2d.h | 31 ++++++++++++++--- tests/math/testpivector2d.cpp | 58 +++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 4 deletions(-) diff --git a/libs/main/containers/pivector2d.h b/libs/main/containers/pivector2d.h index 15e38c2c..d6b49e22 100644 --- a/libs/main/containers/pivector2d.h +++ b/libs/main/containers/pivector2d.h @@ -517,8 +517,8 @@ public: //! \~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 В релизной сборке проверка границ не выполняется; используйте с осторожностью. + //! \~english No bounds checking is performed; use with caution. + //! \~russian Проверка границ не выполняется; используйте с осторожностью. //! \sa PIVector::operator[] inline T & operator[](size_t index) { return (*p_)[this->st_ + index]; } @@ -669,10 +669,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 diff --git a/tests/math/testpivector2d.cpp b/tests/math/testpivector2d.cpp index c12aa631..d680c989 100644 --- a/tests/math/testpivector2d.cpp +++ b/tests/math/testpivector2d.cpp @@ -1431,3 +1431,61 @@ 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::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::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::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::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::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::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::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(ROWS_COUNT_INIT - 1), static_cast(COLS_COUNT_INIT - 1)}] = 200; + EXPECT_EQ(vec.element(ROWS_COUNT_INIT - 1, COLS_COUNT_INIT - 1), 200); +} -- 2.43.0 From 14e62a41bd7cbd2f0ac0ab45cf94eabe9759c5f4 Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Fri, 27 Feb 2026 00:41:51 +0300 Subject: [PATCH 19/29] Add Index access methods and validation functions to PIVector2D - Add operator[], element(), and at() overloads for Index struct - Add isValid() and isNotValid() methods to Index - Add default initialization to -1 (invalid state) - Add parameterized constructor Index(row, col) - Add tests for new functionality --- libs/main/containers/pivector2d.h | 10 ++++++++-- tests/math/testpivector2d.cpp | 33 +++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/libs/main/containers/pivector2d.h b/libs/main/containers/pivector2d.h index d6b49e22..dbc80322 100644 --- a/libs/main/containers/pivector2d.h +++ b/libs/main/containers/pivector2d.h @@ -55,8 +55,14 @@ public: //! \~english Index structure for 2D array elements (row, column). //! \~russian Структура индекса для элементов двумерного массива (строка, столбец). struct Index { - ssize_t row; - ssize_t col; + 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. diff --git a/tests/math/testpivector2d.cpp b/tests/math/testpivector2d.cpp index d680c989..0b47aac5 100644 --- a/tests/math/testpivector2d.cpp +++ b/tests/math/testpivector2d.cpp @@ -1489,3 +1489,36 @@ TEST_F(Vector2DTest, index_structure_with_brace_initialization_works) { vec[{static_cast(ROWS_COUNT_INIT - 1), static_cast(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::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::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::Index idx(0, 0); + EXPECT_TRUE(idx.isValid()); + EXPECT_FALSE(idx.isNotValid()); +} + +TEST(Vector2DIndexTest, isNotValid_returns_true_for_negative_values) { + PIVector2D::Index idx1; + EXPECT_TRUE(idx1.isNotValid()); + + PIVector2D::Index idx2(-1, 5); + EXPECT_TRUE(idx2.isNotValid()); + + PIVector2D::Index idx3(5, -1); + EXPECT_TRUE(idx3.isNotValid()); +} -- 2.43.0 From 8a26b6174db31f8f1c0e9b30c96c130a86268715 Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Fri, 27 Feb 2026 01:49:30 +0300 Subject: [PATCH 20/29] PIVector2D removeColumn memmove optimization --- libs/main/containers/pivector2d.h | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/libs/main/containers/pivector2d.h b/libs/main/containers/pivector2d.h index dbc80322..d48a8925 100644 --- a/libs/main/containers/pivector2d.h +++ b/libs/main/containers/pivector2d.h @@ -1219,14 +1219,21 @@ public: //! \sa removeRow(), PIVector::remove() inline PIVector2D & removeColumn(size_t col) { if (col >= cols_ || rows_ == 0) return *this; - PIVector2D 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); + T * dst = mat.data(r * (cols_ - 1)); + T * src = mat.data(r * cols_); + if (col > 0) { + memmove(dst, src, col * sizeof(T)); + dst += col; + src += col; + } + size_t remaining = (cols_ - 1) - col; + if (remaining > 0) { + memmove(dst, src + 1, remaining * sizeof(T)); } } - swap(result); + cols_--; + mat.resize(rows_ * cols_); return *this; } -- 2.43.0 From b86786e3431a5d40237bfb9ad2bb380efe6eb668 Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Fri, 27 Feb 2026 11:17:28 +0300 Subject: [PATCH 21/29] first try optimize resize and filter --- libs/main/containers/pivector2d.h | 59 ++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/libs/main/containers/pivector2d.h b/libs/main/containers/pivector2d.h index d48a8925..bd434075 100644 --- a/libs/main/containers/pivector2d.h +++ b/libs/main/containers/pivector2d.h @@ -869,16 +869,18 @@ public: //! \sa PIVector::resize() inline PIVector2D & resize(size_t rows, size_t cols, const T & f = T()) { if (rows == rows_ && cols == cols_) return *this; - PIVector2D 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; } - swap(tmp); - return *this; + if (rows != rows_ && cols == cols_) { + mat.resize(rows * cols_, f); + rows_ = rows; + return *this; + } + return __resize(rows, cols, f, std::is_trivially_copyable()); } //! \~english Equality operator. @@ -1103,8 +1105,8 @@ public: //! \sa PIVector::getRange() inline PIVector2D 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(); - size_t actualRowCount = piMin(rowCount, rows_ - rowStart); - size_t actualColCount = piMin(colCount, cols_ - colStart); + const size_t actualRowCount = piMin(rowCount, rows_ - rowStart); + const size_t actualColCount = piMin(colCount, cols_ - colStart); PIVector2D result(actualRowCount, actualColCount); for (size_t r = 0; r < actualRowCount; ++r) { @@ -1292,16 +1294,47 @@ public: goodCols << c; } } - PIVector2D result(rows_, goodCols.size()); + PIVector2D 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; } protected: + template::value, int>::type = 0> + inline PIVector2D & __resize(size_t rows, size_t cols, const T & f, std::true_type) { + PIVector2D tmp(rows, cols, f); + const size_t copyRows = piMin(rows_, rows); + const size_t copyCols = piMin(cols_, cols); + for (size_t r = 0; r < copyRows; ++r) { + T * dst = tmp.mat.data() + r * cols; + T * src = mat.data() + r * cols_; + memmove(dst, src, copyCols * sizeof(T)); + } + swap(tmp); + return *this; + } + + template::value, int>::type = 0> + inline PIVector2D & __resize(size_t rows, size_t cols, const T & f, std::false_type) { + PIVector2D tmp(rows, cols, f); + const size_t copyRows = piMin(rows_, rows); + const 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); + } + } + swap(tmp); + return *this; + } + size_t rows_, cols_; PIVector mat; }; -- 2.43.0 From 525dbf8e9ea9ed87ce3248184dc888883e774a3f Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Fri, 27 Feb 2026 14:40:22 +0300 Subject: [PATCH 22/29] resize not work( --- libs/main/containers/pivector2d.h | 124 ++++++++++++++++++------------ 1 file changed, 74 insertions(+), 50 deletions(-) diff --git a/libs/main/containers/pivector2d.h b/libs/main/containers/pivector2d.h index bd434075..dd21f4c5 100644 --- a/libs/main/containers/pivector2d.h +++ b/libs/main/containers/pivector2d.h @@ -785,6 +785,64 @@ public: return *this; } + // TODO: fix - memove existing elements + inline PIVector2D & addEmptyRows(size_t count, const T & f = T()) { + if (count == 0 || cols_ == 0) return *this; + mat.resize(mat.size() + count * cols_, f); + rows_ += count; + return *this; + } + + // TODO: fix - memove existing elements + inline PIVector2D & addEmptyColumns(size_t count, const T & f = T()) { + if (count == 0 || rows_ == 0) return *this; + const size_t newCols = cols_ + count; + const size_t newSize = rows_ * newCols; + mat.resize(newSize); + for (size_t r = rows_ - 1; r < rows_; --r) { + for (size_t c = newCols - 1; c >= cols_; --c) { + element(r, c) = f; + } + for (size_t c = cols_; c > 0; --c) { + element(r, c - 1 + count) = element(r, c - 1); + } + } + cols_ = newCols; + return *this; + } + + inline PIVector2D & deleteRows(size_t row, size_t count) { + if (row >= rows_) return *this; + mat.remove(row * cols_, cols_ * count); + rows_ -= count; + if (mat.isEmpty()) { + cols_ = 0; + rows_ = 0; + } + return *this; + } + + inline PIVector2D & deleteColumns(size_t col, size_t count) { + if (col >= cols_ || rows_ == 0 || count == 0) return *this; + count = piMin(count, cols_ - col); + for (size_t r = 0; r < rows_; ++r) { + T * dst = mat.data(r * (cols_ - count)); + T * src = mat.data(r * cols_); + if (col > 0) { + memmove(dst, src, col * sizeof(T)); + dst += col; + src += col; + } + size_t remaining = (cols_ - count) - col; + if (remaining > 0) { + memmove(dst, src + 1, remaining * sizeof(T)); + } + } + cols_ -= count; + mat.resize(rows_ * cols_); + return *this; + } + //! \~english Appends a new column to the right of the array from a \a ColConst. //! \~russian Добавляет новую строку в конец массива из \a ColConst. inline PIVector2D & addColumn(const ColConst & other) { @@ -880,7 +938,7 @@ public: rows_ = rows; return *this; } - return __resize(rows, cols, f, std::is_trivially_copyable()); + return __resize(rows, cols, f); } //! \~english Equality operator. @@ -1200,17 +1258,11 @@ 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 & removeRow(size_t row) { - if (row >= rows_) return *this; - mat.remove(row * cols_, cols_); - rows_--; - if (rows_ == 0) cols_ = 0; - return *this; + return deleteRows(row, 1); } //! \~english Removes a column from the 2D array. @@ -1220,23 +1272,7 @@ public: //! \~russian Эта операция дороже, чем удаление строки, поскольку требуется перемещение элементов. //! \sa removeRow(), PIVector::remove() inline PIVector2D & removeColumn(size_t col) { - if (col >= cols_ || rows_ == 0) return *this; - for (size_t r = 0; r < rows_; ++r) { - T * dst = mat.data(r * (cols_ - 1)); - T * src = mat.data(r * cols_); - if (col > 0) { - memmove(dst, src, col * sizeof(T)); - dst += col; - src += col; - } - size_t remaining = (cols_ - 1) - col; - if (remaining > 0) { - memmove(dst, src + 1, remaining * sizeof(T)); - } - } - cols_--; - mat.resize(rows_ * cols_); - return *this; + return deleteColumns(col, 1); } //! \~english Removes all rows that satisfy a condition. @@ -1307,31 +1343,19 @@ public: } protected: - template::value, int>::type = 0> - inline PIVector2D & __resize(size_t rows, size_t cols, const T & f, std::true_type) { - PIVector2D tmp(rows, cols, f); - const size_t copyRows = piMin(rows_, rows); - const size_t copyCols = piMin(cols_, cols); - for (size_t r = 0; r < copyRows; ++r) { - T * dst = tmp.mat.data() + r * cols; - T * src = mat.data() + r * cols_; - memmove(dst, src, copyCols * sizeof(T)); + inline PIVector2D & __resize(size_t rows, size_t cols, const T & f) { + if (cols > cols_) { + addEmptyColumns(cols - cols_, f); } - swap(tmp); - return *this; - } - - template::value, int>::type = 0> - inline PIVector2D & __resize(size_t rows, size_t cols, const T & f, std::false_type) { - PIVector2D tmp(rows, cols, f); - const size_t copyRows = piMin(rows_, rows); - const 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 > rows_) { + addEmptyRows(rows - rows_, f); + } + if (cols < cols_) { + deleteColumns(cols, cols_ - cols); + } + if (rows < rows_) { + deleteRows(rows, rows_ - rows); } - swap(tmp); return *this; } -- 2.43.0 From 97691e888c5e061ba2e8a428d86ae782909606ef Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Fri, 27 Feb 2026 18:39:28 +0300 Subject: [PATCH 23/29] PIVector insert with count --- libs/main/containers/pivector.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/libs/main/containers/pivector.h b/libs/main/containers/pivector.h index 96e85f9c..a6b7a766 100644 --- a/libs/main/containers/pivector.h +++ b/libs/main/containers/pivector.h @@ -1321,14 +1321,16 @@ public: //! piCout << v; // {1, 3, 7, 5} //! \endcode //! \~\sa \a append(), \a prepend(), \a remove() - inline PIVector & 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(piv_data + index + 1), reinterpret_cast(piv_data + index), os * sizeof(T)); + inline PIVector & 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(piv_data + index + count), reinterpret_cast(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; } -- 2.43.0 From 0b7d565b93ef7a524fc541c41b7eeb8920824b5f Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Fri, 27 Feb 2026 18:40:09 +0300 Subject: [PATCH 24/29] pivector2d fix add\remove rows\cols and resize --- libs/main/containers/pivector2d.h | 166 +++++++----------- tests/math/testpivector2d.cpp | 279 +++++++++++++++++++++++++++++- 2 files changed, 342 insertions(+), 103 deletions(-) diff --git a/libs/main/containers/pivector2d.h b/libs/main/containers/pivector2d.h index dd21f4c5..e8191aa4 100644 --- a/libs/main/containers/pivector2d.h +++ b/libs/main/containers/pivector2d.h @@ -777,66 +777,57 @@ public: //! \~russian Добавляет новую строку в конец массива из \a PIVector. inline PIVector2D & addRow(const PIVector & other) { if (cols_ == 0) cols_ = other.size(); - const size_t sz = piMin(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; } - // TODO: fix - memove existing elements - inline PIVector2D & addEmptyRows(size_t count, const T & f = T()) { - if (count == 0 || cols_ == 0) return *this; + inline PIVector2D & 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; } - // TODO: fix - memove existing elements - inline PIVector2D & addEmptyColumns(size_t count, const T & f = T()) { - if (count == 0 || rows_ == 0) return *this; - const size_t newCols = cols_ + count; - const size_t newSize = rows_ * newCols; - mat.resize(newSize); - for (size_t r = rows_ - 1; r < rows_; --r) { - for (size_t c = newCols - 1; c >= cols_; --c) { - element(r, c) = f; - } - for (size_t c = cols_; c > 0; --c) { - element(r, c - 1 + count) = element(r, c - 1); - } + inline PIVector2D & 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 & deleteRows(size_t row, size_t count) { - if (row >= rows_) return *this; - mat.remove(row * cols_, cols_ * count); - rows_ -= count; - if (mat.isEmpty()) { + inline PIVector2D & 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 & deleteColumns(size_t col, size_t count) { - if (col >= cols_ || rows_ == 0 || count == 0) return *this; - count = piMin(count, cols_ - col); + inline PIVector2D & 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) { - T * dst = mat.data(r * (cols_ - count)); - T * src = mat.data(r * cols_); - if (col > 0) { - memmove(dst, src, col * sizeof(T)); - dst += col; - src += col; - } - size_t remaining = (cols_ - count) - col; - if (remaining > 0) { - memmove(dst, src + 1, remaining * sizeof(T)); - } + mat.remove(r * (cols_ - count) + col_start, count); } cols_ -= count; mat.resize(rows_ * cols_); @@ -847,32 +838,25 @@ public: //! \~russian Добавляет новую строку в конец массива из \a ColConst. inline PIVector2D & 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; @@ -882,32 +866,22 @@ public: //! \~russian Добавляет новую строку в конец массива из \a PIVector. inline PIVector2D & addColumn(const PIVector & 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; @@ -938,7 +912,19 @@ public: rows_ = rows; return *this; } - return __resize(rows, cols, f); + 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); + } + return *this; } //! \~english Equality operator. @@ -1261,9 +1247,7 @@ public: //! \~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 & removeRow(size_t row) { - return deleteRows(row, 1); - } + inline PIVector2D & removeRow(size_t row) { return deleteRows(row, 1); } //! \~english Removes a column from the 2D array. //! \~russian Удаляет столбец из двумерного массива. @@ -1271,9 +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 & removeColumn(size_t col) { - return deleteColumns(col, 1); - } + inline PIVector2D & removeColumn(size_t col) { return deleteColumns(col, 1); } //! \~english Removes all rows that satisfy a condition. //! \~russian Удаляет все строки, удовлетворяющие условию. @@ -1343,22 +1325,6 @@ public: } protected: - inline PIVector2D & __resize(size_t rows, size_t cols, const T & f) { - if (cols > cols_) { - addEmptyColumns(cols - cols_, f); - } - if (rows > rows_) { - addEmptyRows(rows - rows_, f); - } - if (cols < cols_) { - deleteColumns(cols, cols_ - cols); - } - if (rows < rows_) { - deleteRows(rows, rows_ - rows); - } - return *this; - } - size_t rows_, cols_; PIVector mat; }; diff --git a/tests/math/testpivector2d.cpp b/tests/math/testpivector2d.cpp index 0b47aac5..a744becc 100644 --- a/tests/math/testpivector2d.cpp +++ b/tests/math/testpivector2d.cpp @@ -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(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 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(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 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(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((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(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(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((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(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(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(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 newCol(oldRows, 999); + PIVector 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)); } } -- 2.43.0 From 854916ad9fb8653737cbdff229dd6d6942a8e70b Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Fri, 27 Feb 2026 18:59:47 +0300 Subject: [PATCH 25/29] =?UTF-8?q?=D0=BF=D1=80=D0=B8=D0=BC=D0=B5=D1=80=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plans/doxygen_example.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 plans/doxygen_example.md diff --git a/plans/doxygen_example.md b/plans/doxygen_example.md new file mode 100644 index 00000000..52581c92 --- /dev/null +++ b/plans/doxygen_example.md @@ -0,0 +1,13 @@ +Ключевые элементы документации + +| Элемент | Описание | +|---------|----------| +| //! \~english | Описание на английском языке | +| //! \~russian | Описание на русском языке | +| //! \details | | +| //! \~english | Детальное объяснение на английском языке | +| //! \~russian | Детальное объяснение на русском языке | +| //! \note | | +| //! \~english | Важное примечание о сложности/поведении на английском языке | +| //! \~russian | Важное примечание о сложности/поведении на русском языке | +| //! \~\sa | Ссылки на связанные функции | -- 2.43.0 From 1b5a3591854395a0d3038420f0c1d2722feaeaca Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Fri, 27 Feb 2026 19:21:24 +0300 Subject: [PATCH 26/29] fix filterColumns and Doxygen comments --- libs/main/containers/pivector2d.h | 223 ++++++++++++++++++------------ plans/doxygen_example.md | 2 + 2 files changed, 137 insertions(+), 88 deletions(-) diff --git a/libs/main/containers/pivector2d.h b/libs/main/containers/pivector2d.h index e8191aa4..f1b019ea 100644 --- a/libs/main/containers/pivector2d.h +++ b/libs/main/containers/pivector2d.h @@ -55,13 +55,28 @@ public: //! \~english Index structure for 2D array elements (row, column). //! \~russian Структура индекса для элементов двумерного массива (строка, столбец). struct Index { + //! \~english Row index in the 2D array. + //! \~russian Индекс строки в двумерном массиве. ssize_t row = -1; + //! \~english Column index in the 2D array. + //! \~russian Индекс столбца в двумерном массиве. ssize_t col = -1; + //! \~english Default constructor. Initializes row and col to -1 (invalid index). + //! \~russian Конструктор по умолчанию. Инициализирует row и col значениями -1 (некорректный индекс). inline Index() = default; + //! \~english Constructs an Index with the given row and column values. + //! \~russian Создаёт Index с заданными значениями строки и столбца. inline Index(ssize_t r, ssize_t c): row(r), col(c) {} + //! \~english Checks if the index is valid (both row and column are non-negative). + //! \~russian Проверяет, является ли индекс корректным (строка и столбец неотрицательны). + //! \~\sa isNotValid() inline bool isValid() const { return row >= 0 && col >= 0; } + + //! \~english Checks if the index is invalid (either row or column is negative). + //! \~russian Проверяет, является ли индекс некорректным (строка или столбец отрицательны). + //! \~\sa isValid() inline bool isNotValid() const { return !isValid(); } }; @@ -70,7 +85,7 @@ public: //! \details //! \~english After this constructor, \a rows() and \a cols() return 0, and \a isEmpty() returns true. //! \~russian После этого конструктора \a rows() и \a cols() возвращают 0, а \a isEmpty() возвращает true. - //! \sa PIVector::PIVector() + //! \~\sa PIVector::PIVector() inline PIVector2D() { rows_ = cols_ = 0; } //! \~english Constructs a 2D array with the given dimensions, filled with copies of `f`. @@ -80,7 +95,7 @@ public: //! All elements are initialized with the value `f`. //! \~russian Внутреннее хранилище представляет собой единый непрерывный блок памяти размером `rows * cols`. //! Все элементы инициализируются значением `f`. - //! \sa PIVector::PIVector(size_t, const T&) + //! \~\sa PIVector::PIVector(size_t, const T&) inline PIVector2D(size_t rows, size_t cols, const T & f = T()) { rows_ = rows; cols_ = cols; @@ -96,7 +111,7 @@ public: //! \~russian Конструктор копирует данные из `v` во внутренний плоский вектор. //! Если `v` больше, чем `rows * cols`, лишние элементы игнорируются (вектор обрезается). //! Если `v` меньше, остальные значения будут заполнены из конструктора по умолчанию T() - //! \sa PIVector::PIVector(const PIVector&), reshape() + //! \~\sa PIVector::PIVector(const PIVector&), reshape() inline PIVector2D(size_t rows, size_t cols, const PIVector & v): rows_(rows), cols_(cols), mat(v) { mat.resize(rows * cols); } //! \~english Move constructs a 2D array from an existing 1D vector, reshaping it. @@ -106,7 +121,7 @@ public: //! After construction, `v` is left in a valid but unspecified state. //! \~russian Данные перемещаются из `v` во внутренний плоский вектор, что позволяет избежать копирования. //! После завершения конструктора `v` остаётся в корректном, но неопределённом состоянии. - //! \sa PIVector::PIVector(PIVector&&) + //! \~\sa PIVector::PIVector(PIVector&&) inline PIVector2D(size_t rows, size_t cols, PIVector && 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. @@ -136,7 +151,7 @@ public: //! \details //! \~english The result is always non-negative. If the array is empty, returns 0. //! \~russian Результат всегда неотрицательный. Если массив пуст, возвращает 0. - //! \sa cols(), size(), PIVector::size() + //! \~\sa cols(), size(), PIVector::size() inline size_t rows() const { return rows_; } //! \~english Returns the number of columns in the 2D array. @@ -145,7 +160,7 @@ public: //! \details //! \~english The result is always non-negative. If the array is empty, returns 0. //! \~russian Результат всегда неотрицательный. Если массив пуст, возвращает 0. - //! \sa rows(), size(), PIVector::size() + //! \~\sa rows(), size(), PIVector::size() inline size_t cols() const { return cols_; } //! \~english Returns the total number of elements (`rows * cols`). @@ -154,19 +169,19 @@ public: //! \details //! \~english This is equivalent to the size of the underlying flat vector. //! \~russian Это эквивалентно размеру внутреннего плоского вектора. - //! \sa rows(), cols(), PIVector::size() + //! \~\sa rows(), cols(), PIVector::size() inline size_t size() const { return mat.size(); } //! \~english Returns the total number of elements as a signed value. //! \~russian Возвращает общее количество элементов в виде знакового числа. //! \return Signed size. - //! \sa size(), PIVector::size_s() + //! \~\sa size(), PIVector::size_s() inline ssize_t size_s() const { return mat.size_s(); } //! \~english Returns the total number of elements (same as \a size()). //! \~russian Возвращает общее количество элементов (то же, что и \a size()). //! \return Total number of elements. - //! \sa size(), PIVector::length() + //! \~\sa size(), PIVector::length() inline size_t length() const { return mat.length(); } //! \~english Returns the number of elements that the underlying container has currently allocated space for. @@ -184,13 +199,13 @@ public: //! \details //! \~english An empty array has both rows and columns equal to 0. //! \~russian Пустой массив имеет и строки, и столбцы равные 0. - //! \sa isNotEmpty(), PIVector::isEmpty() + //! \~\sa isNotEmpty(), PIVector::isEmpty() inline bool isEmpty() const { return mat.isEmpty(); } //! \~english Checks if the array has at least one element. //! \~russian Проверяет, не пуст ли массив. //! \return \c true if the array is not empty, \c false otherwise. - //! \sa isEmpty(), PIVector::isNotEmpty() + //! \~\sa isEmpty(), PIVector::isNotEmpty() inline bool isNotEmpty() const { return mat.isNotEmpty(); } class RowConst; @@ -206,7 +221,7 @@ public: //! \details //! \~english Returned by const \a operator[] or \a row(). Provides const access to row elements. //! \~russian Возвращается константными версиями \a operator[] или \a row(). Предоставляет константный доступ к элементам строки. - //! \sa Row, ColConst + //! \~\sa Row, ColConst class RowConst { friend class PIVector2D; @@ -216,6 +231,9 @@ public: const size_t st_, sz_; public: + //! \~english Copy constructor from modifiable Row to read-only RowConst. + //! \~russian Конструктор копирования из модифицируемого класса Row в константный RowConst. + //! \~\sa Row inline RowConst(const PIVector2D::Row & r): p_(r.p_), st_(r.st_), sz_(r.sz_) {} //! \~english Size of the row (number of columns). @@ -239,7 +257,7 @@ public: //! \details //! \~english See \a PIVector::indexOf() for details on negative start handling. //! \~russian Подробнее об обработке отрицательного `start` см. \a PIVector::indexOf(). - //! \sa 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) { @@ -251,7 +269,7 @@ public: //! \~english Returns the last index of element `e` in the row, searching backwards from `start`. //! \~russian Возвращает последний индекс элемента `e` в строке, выполняя поиск в обратном направлении от `start`. //! \return Index if found, -1 otherwise. - //! \sa PIVector::lastIndexOf() + //! \~\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) { @@ -262,7 +280,7 @@ public: //! \~english Returns the first index where the predicate `test` returns true, starting from `start`. //! \~russian Возвращает первый индекс, для которого предикат `test` возвращает true, начиная с `start`. - //! \sa PIVector::indexWhere() + //! \~\sa PIVector::indexWhere() inline ssize_t indexWhere(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; for (size_t i = (size_t)start; i < sz_; ++i) { @@ -274,7 +292,7 @@ public: //! \~english Returns the last index where the predicate `test` returns true, searching backwards from `start`. //! \~russian Возвращает последний индекс, для которого предикат `test` возвращает true, //! выполняя поиск в обратном направлении от `start`. - //! \sa PIVector::lastIndexWhere() + //! \~\sa PIVector::lastIndexWhere() inline ssize_t lastIndexWhere(std::function 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) { @@ -288,7 +306,7 @@ public: //! \details //! \~english The function can't modify the elements. //! \~russian Функция не может изменять элементы. - //! \sa forEach (modifiable) + //! \~\sa forEach (modifiable) inline void forEach(std::function func) const { for (size_t i = 0; i < sz_; ++i) { func((*p_)[st_ + i]); @@ -297,12 +315,12 @@ public: //! \~english Checks if the row contains the element `e`. //! \~russian Проверяет, содержит ли строка элемент `e`. - //! \sa PIVector::contains() + //! \~\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() + //! \~\sa PIVector::entries() inline int entries(const T & e, ssize_t start = 0) const { if (start < 0) start = 0; int count = 0; @@ -314,7 +332,7 @@ public: //! \~english Counts elements in the row that pass the `test`. //! \~russian Подсчитывает элементы в строке, проходящие `test`. - //! \sa PIVector::entries(std::function) + //! \~\sa PIVector::entries(std::function) inline int entries(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; int count = 0; @@ -326,7 +344,7 @@ public: //! \~english Tests if any element in the row passes the `test`. //! \~russian Проверяет, проходит ли какой-либо элемент в строке `test`. - //! \sa PIVector::any() + //! \~\sa PIVector::any() inline bool any(std::function test) const { for (size_t i = 0; i < sz_; ++i) { if (test((*p_)[st_ + i])) return true; @@ -336,7 +354,7 @@ public: //! \~english Tests if all elements in the row pass the `test`. //! \~russian Проверяет, проходят ли все элементы в строке `test`. - //! \sa PIVector::every() + //! \~\sa PIVector::every() inline bool every(std::function test) const { for (size_t i = 0; i < sz_; ++i) { if (!test((*p_)[st_ + i])) return false; @@ -353,7 +371,7 @@ public: //! \details //! \~english Returned by const \a col(). Provides const access to column elements. //! \~russian Возвращается константной версией \a col(). Предоставляет константный доступ к элементам столбца. - //! \sa Col, RowConst + //! \~\sa Col, RowConst class ColConst { friend class PIVector2D; @@ -363,6 +381,9 @@ public: const size_t step_, col_, sz_; public: + //! \~english Copy constructor from modifiable Col to read-only ColConst. + //! \~russian Конструктор копирования из модифицируемого класса Col в константный ColConst. + //! \~\sa Col inline ColConst(const PIVector2D::Col & c): p_(c.p_), step_(c.step_), col_(c.col_), sz_(c.sz_) {} //! \~english Size of the column (number of rows). @@ -392,7 +413,7 @@ public: //! \details //! \~english See \a PIVector::indexOf() for details on negative start handling. //! \~russian Подробнее об обработке отрицательного `start` см. \a PIVector::indexOf(). - //! \sa 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) { @@ -403,7 +424,7 @@ public: //! \~english Returns the last index of element `e` in the row, searching backwards from `start`. //! \~russian Возвращает последний индекс элемента `e` в строке, выполняя поиск в обратном направлении от `start`. - //! \sa PIVector::lastIndexOf() + //! \~\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) { @@ -414,7 +435,7 @@ public: //! \~english Returns the first index where the predicate `test` returns true, starting from `start`. //! \~russian Возвращает первый индекс, для которого предикат `test` возвращает true, начиная с `start`. - //! \sa PIVector::indexWhere() + //! \~\sa PIVector::indexWhere() inline ssize_t indexWhere(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; for (size_t i = (size_t)start; i < sz_; ++i) { @@ -426,7 +447,7 @@ public: //! \~english Returns the last index where the predicate `test` returns true, searching backwards from `start`. //! \~russian Возвращает последний индекс, для которого предикат `test` возвращает true, //! выполняя поиск в обратном направлении от `start`. - //! \sa PIVector::lastIndexWhere() + //! \~\sa PIVector::lastIndexWhere() inline ssize_t lastIndexWhere(std::function 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) { @@ -440,7 +461,7 @@ public: //! \details //! \~english The function can't modify the elements. //! \~russian Функция не может изменять элементы. - //! \sa forEach (modifiable) + //! \~\sa forEach (modifiable) inline void forEach(std::function func) const { for (size_t i = 0; i < sz_; ++i) { func((*p_)[i * step_ + col_]); @@ -449,12 +470,12 @@ public: //! \~english Checks if the column contains the element `e`. //! \~russian Проверяет, содержит ли столбец элемент `e`. - //! \sa PIVector::contains() + //! \~\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() + //! \~\sa PIVector::entries() inline int entries(const T & e, ssize_t start = 0) const { if (start < 0) start = 0; int count = 0; @@ -466,7 +487,7 @@ public: //! \~english Counts elements in the column that pass the `test`. //! \~russian Подсчитывает элементы в столбце, проходящие `test`. - //! \sa PIVector::entries(std::function) + //! \~\sa PIVector::entries(std::function) inline int entries(std::function test, ssize_t start = 0) const { if (start < 0) start = 0; int count = 0; @@ -478,7 +499,7 @@ public: //! \~english Tests if any element in the column passes the `test`. //! \~russian Проверяет, проходит ли какой-либо элемент в столбце `test`. - //! \sa PIVector::any() + //! \~\sa PIVector::any() inline bool any(std::function test) const { for (size_t i = 0; i < sz_; ++i) { if (test((*p_)[i * step_ + col_])) return true; @@ -488,7 +509,7 @@ public: //! \~english Tests if all elements in the column pass the `test`. //! \~russian Проверяет, проходят ли все элементы в столбце `test`. - //! \sa PIVector::every() + //! \~\sa PIVector::every() inline bool every(std::function test) const { for (size_t i = 0; i < sz_; ++i) { if (!test((*p_)[i * step_ + col_])) return false; @@ -525,7 +546,7 @@ public: //! \details //! \~english No bounds checking is performed; use with caution. //! \~russian Проверка границ не выполняется; используйте с осторожностью. - //! \sa PIVector::operator[] + //! \~\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. @@ -542,7 +563,7 @@ public: //! \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= + //! \~\sa PIVector::operator= inline Row & operator=(const Row & other) { if (p_ == other.p_ && this->st_ == other.st_) return *this; const size_t sz = piMin(this->sz_, other.sz_); @@ -555,7 +576,7 @@ public: //! \details //! \~english Only the minimum of the row size and vector size is copied. //! \~russian Копируется только минимум из размера строки и размера вектора. - //! \sa PIVector::operator= + //! \~\sa PIVector::operator= inline Row & operator=(const PIVector & other) { const size_t sz = piMin(this->sz_, other.size()); p_->_copyRaw(p_->data(this->st_), other.data(), sz); @@ -568,7 +589,7 @@ public: //! \details //! \~english The function can modify the elements. //! \~russian Функция может изменять элементы. - //! \sa PIVector::forEach() + //! \~\sa PIVector::forEach() inline void forEach(std::function func) { for (size_t i = 0; i < this->sz_; ++i) { func((*p_)[this->st_ + i]); @@ -577,7 +598,7 @@ public: //! \~english Fills the row with copies of `value`. //! \~russian Заполняет строку копиями `value`. - //! \sa PIVector::fill() + //! \~\sa PIVector::fill() inline void fill(const T & value) { for (size_t i = 0; i < this->sz_; ++i) { (*p_)[this->st_ + i] = value; @@ -645,7 +666,7 @@ public: //! \details //! \~english The function can modify the elements. //! \~russian Функция может изменять элементы. - //! \sa PIVector::forEach() + //! \~\sa PIVector::forEach() inline void forEach(std::function func) { for (size_t i = 0; i < this->sz_; ++i) { func((*p_)[i * this->step_ + this->col_]); @@ -654,7 +675,7 @@ public: //! \~english Fills the column with copies of `value`. //! \~russian Заполняет столбец копиями `value`. - //! \sa PIVector::fill() + //! \~\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; @@ -668,7 +689,7 @@ public: //! \details //! \~english No bounds checking is performed. //! \~russian Проверка границ не выполняется. - //! \sa at() (const version), PIVector::operator[] + //! \~\sa at() (const version), PIVector::operator[] inline T & element(size_t row, size_t col) { return mat[row * cols_ + col]; } //! \~english Returns a const reference to the element at the given row and column. @@ -704,7 +725,7 @@ public: //! \~english Returns a proxy object for the row at the given index for modification. //! \~russian Возвращает прокси-объект для строки по заданному индексу для модификации. - //! \sa row(), Col + //! \~\sa row(), Col inline Row operator[](size_t index) { return Row(this, index); } //! \~english Returns a proxy object for the row at the given index for read-only access. @@ -713,7 +734,7 @@ public: //! \~english Returns a pointer to the underlying flat data starting at an optional offset. //! \~russian Возвращает указатель на внутренние плоские данные, начиная с опционального смещения. - //! \sa PIVector::data() + //! \~\sa PIVector::data() inline T * data(size_t index = 0) { return mat.data(index); } //! \~english Returns a const pointer to the underlying flat data starting at an optional offset. @@ -723,7 +744,7 @@ public: //! \~english Returns a proxy object for the row at the given index for modification. //! \~russian Возвращает прокси-объект для строки по заданному индексу для модификации. - //! \sa operator[] + //! \~\sa operator[] inline Row row(size_t index) { return Row(this, index); } //! \~english Returns a proxy object for the row at the given index for read-only access. @@ -732,7 +753,7 @@ public: //! \~english Returns a proxy object for the column at the given index for modification. //! \~russian Возвращает прокси-объект для столбца по заданному индексу для модификации. - //! \sa col() const + //! \~\sa col() const inline Col col(size_t index) { return Col(this, index); } //! \~english Returns a proxy object for the column at the given index for read-only access. @@ -762,14 +783,13 @@ public: //! Otherwise, only `min(cols(), other.size())` elements are copied; the rest of the new row is default-initialized. //! \~russian Если массив был пуст, количество столбцов устанавливается равным размеру исходной строки. //! В противном случае копируется только `min(cols(), other.size())` элементов; остальные элементы новой строки инициализируются по - //! умолчанию. \sa PIVector::push_back() + //! умолчанию. + //! \~\sa PIVector::push_back() inline PIVector2D & addRow(const RowConst & other) { if (cols_ == 0) cols_ = other.sz_; - const size_t sz = piMin(cols_, other.sz_); - const size_t ps = mat.size(); - mat.resize(mat.size() + cols_); - mat._copyRaw(mat.data(ps), other.data(), sz); + mat.append(other.toVector()); rows_++; + mat.resize(rows_ * cols_); return *this; } @@ -783,6 +803,14 @@ public: return *this; } + //! \~english Appends \a count new empty rows to the bottom of the array, filled with value \a f. + //! \~russian Добавляет \a count новых пустых строк в конец массива, заполненных значением \a f. + //! \details + //! \~english If the array was empty (no columns defined), the column count is set to 1. + //! The new rows are filled with the default value \a f. + //! \~russian Если массив был пуст (количество столбцов не определено), количество столбцов устанавливается равным 1. + //! Новые строки заполняются значением по умолчанию \a f. + //! \~\sa addRow(), appendColumns() inline PIVector2D & appendRows(size_t count, const T & f = T()) { if (count == 0) return *this; if (cols_ == 0) ++cols_; @@ -791,6 +819,14 @@ public: return *this; } + //! \~english Appends \a count new empty columns to the end of each row of the array. + //! \~russian Добавляет \a count новых пустых столбцов в конец каждой строки массива. + //! \details + //! \~english If the array was empty (rows not defined), the array becomes a single row with \a count columns. + //! If the array already has rows, new elements are inserted at the end of each existing row. + //! \~russian Если массив был пуст (строки не определены), массив становится одной строкой с \a count столбцов. + //! Если массив уже содержит строки, новые элементы добавляются в конец каждой существующей строки. + //! \~\sa appendRows(), addColumn() inline PIVector2D & appendColumns(size_t count, const T & f = T()) { if (count == 0) return *this; if (rows_ == 0) { @@ -810,6 +846,14 @@ public: return *this; } + //! \~english Deletes `count` rows starting from the specified row index. + //! \~russian Удаляет `count` строк, начиная с указанного индекса строки. + //! \details + //! \~english Removes the specified rows from the array and updates the row count. If all elements are deleted (array becomes empty), + //! both rows and columns are set to 0. + //! \~russian Удаляет указанные строки из массива и обновляет количество строк. Если все элементы удалены (массив становится пустым), + //! количество строк и столбцов устанавливается в 0. + //! \~\sa deleteColumns() inline PIVector2D & deleteRows(size_t row_start, size_t count) { if (row_start >= rows_ || count == 0) return *this; mat.remove(row_start * cols_, cols_ * count); @@ -822,6 +866,14 @@ public: return *this; } + //! \~english Removes the specified columns from the array and updates the column count. + //! \~russian Удаляет указанные столбцы из массива и обновляет количество столбцов. + //! \details + //! \~english Removes \a count columns starting from \a col_start. If \a col_start is out of range or \a count is 0, + //! the function does nothing. If \a count extends beyond the last column, only available columns are deleted. + //! \~russian Удаляет \a count столбцов начиная с \a col_start. Если \a col_start выходит за границы или \a count равен 0, + //! функция ничего не делает. Если \a count выходит за последний столбец, удаляются только доступные столбцы. + //! \~\sa removeColumn(), deleteRows() inline PIVector2D & deleteColumns(size_t col_start, size_t count) { if (col_start >= cols_ || rows_ == 0) return *this; count = piMin(count, cols_ - col_start); @@ -898,7 +950,7 @@ public: //! PIVector2D mat(2, 3, 0); // 2x3 matrix filled with 0 //! mat.resize(3, 4, 1); // becomes 3x4, new elements filled with 1 //! \endcode - //! \sa PIVector::resize() + //! \~\sa PIVector::resize() inline PIVector2D & resize(size_t rows, size_t cols, const T & f = T()) { if (rows == rows_ && cols == cols_) return *this; if (rows_ == 0 || cols_ == 0) { @@ -929,7 +981,7 @@ public: //! \~english Equality operator. //! \~russian Оператор равенства. - //! \sa PIVector::operator== + //! \~\sa PIVector::operator== inline bool operator==(const PIVector2D & t) const { if (cols_ != t.cols_ || rows_ != t.rows_) return false; return mat == t.mat; @@ -944,7 +996,7 @@ public: //! \details //! \~english Each row vector is a copy of the corresponding row. //! \~russian Каждый вектор-строка является копией соответствующей строки. - //! \sa fromVectors(), PIVector::PIVector(const T*, size_t) + //! \~\sa fromVectors(), PIVector::PIVector(const T*, size_t) inline PIVector> toVectors() const { PIVector> ret; ret.reserve(rows_); @@ -970,7 +1022,7 @@ public: //! \details //! \~english Swaps the flat vectors and the dimension members. Very fast, no memory allocation. //! \~russian Обменивает внутренние плоские векторы и члены, хранящие размеры. Очень быстро, без выделения памяти. - //! \sa PIVector::swap() + //! \~\sa PIVector::swap() inline void swap(PIVector2D & other) { mat.swap(other.mat); piSwap(rows_, other.rows_); @@ -991,7 +1043,7 @@ public: //! \details //! \~english The capacity of the underlying flat vector may remain unchanged. //! \~russian Ёмкость внутреннего плоского вектора может остаться неизменной. - //! \sa PIVector::clear() + //! \~\sa PIVector::clear() inline void clear() { rows_ = cols_ = 0; mat.clear(); @@ -1000,23 +1052,23 @@ public: //! \~english Checks if the underlying flat vector contains the element `e`. //! \~russian Проверяет, содержит ли внутренний плоский вектор элемент `e`. - //! \sa PIVector::contains() + //! \~\sa PIVector::contains() inline bool contains(const T & e) const { return mat.contains(e); } //! \~english Counts occurrences of `e` in the underlying flat vector. //! \~russian Подсчитывает количество вхождений `e` во внутреннем плоском векторе. - //! \sa PIVector::entries() + //! \~\sa PIVector::entries() inline int entries(const T & e) const { return mat.entries(e); } //! \~english Counts elements in the flat vector that pass the `test`. //! \~russian Подсчитывает элементы в плоском векторе, проходящие `test`. - //! \sa PIVector::entries(std::function) + //! \~\sa PIVector::entries(std::function) inline int entries(std::function test) const { return mat.entries(test); } //! \~english Returns the first index (row, col) of `e` in the 2D array. //! \~russian Возвращает первый индекс (строка, столбец) элемента `e` в двумерном массиве. - //! \sa PIVector::indexOf() + //! \~\sa PIVector::indexOf() inline Index indexOf(const T & e) const { ssize_t flat = mat.indexOf(e); if (flat < 0 || cols_ == 0) return Index{-1, -1}; @@ -1025,7 +1077,7 @@ public: //! \~english Returns the first index (row, col) in the 2D array that passes the `test`. //! \~russian Возвращает первый индекс (строка, столбец) в двумерном массиве, проходящий `test`. - //! \sa PIVector::indexWhere() + //! \~\sa PIVector::indexWhere() inline Index indexWhere(std::function test, ssize_t start = 0) const { ssize_t flat = mat.indexWhere(test, start); if (flat < 0 || cols_ == 0) return Index{-1, -1}; @@ -1034,7 +1086,7 @@ public: //! \~english Returns the last index (row, col) of `e` in the 2D array. //! \~russian Возвращает последний индекс (строка, столбец) элемента `e` в двумерном массиве. - //! \sa PIVector::lastIndexOf() + //! \~\sa PIVector::lastIndexOf() inline Index lastIndexOf(const T & e, ssize_t start = -1) const { ssize_t flat = mat.lastIndexOf(e, start); if (flat < 0 || cols_ == 0) return Index{-1, -1}; @@ -1043,7 +1095,7 @@ public: //! \~english Returns the last index (row, col) in the 2D array that passes the `test`. //! \~russian Возвращает последний индекс (строка, столбец) в двумерном массиве, проходящий `test`. - //! \sa PIVector::lastIndexWhere() + //! \~\sa PIVector::lastIndexWhere() inline Index lastIndexWhere(std::function test, ssize_t start = -1) const { ssize_t flat = mat.lastIndexWhere(test, start); if (flat < 0 || cols_ == 0) return Index{-1, -1}; @@ -1053,17 +1105,17 @@ public: //! \~english Tests if any element in the flat vector passes the `test`. //! \~russian Проверяет, проходит ли какой-либо элемент в плоском векторе `test`. - //! \sa PIVector::any() + //! \~\sa PIVector::any() inline bool any(std::function test) const { return mat.any(test); } //! \~english Tests if all elements in the flat vector pass the `test`. //! \~russian Проверяет, проходят ли все элементы в плоском векторе `test`. - //! \sa PIVector::every() + //! \~\sa PIVector::every() inline bool every(std::function test) const { return mat.every(test); } //! \~english Fills the entire 2D array with copies of `e`. //! \~russian Заполняет весь двумерный массив копиями `e`. - //! \sa PIVector::fill() + //! \~\sa PIVector::fill() inline PIVector2D & fill(const T & e = T()) { mat.fill(e); return *this; @@ -1071,7 +1123,7 @@ public: //! \~english Fills the entire 2D array using a generator function `f` based on flat index. //! \~russian Заполняет весь двумерный массив, используя функцию-генератор `f` на основе плоского индекса. - //! \sa PIVector::fill(std::function) + //! \~\sa PIVector::fill(std::function) inline PIVector2D & fill(std::function f) { mat.fill(f); return *this; @@ -1083,7 +1135,7 @@ public: //! \~english Assigns new size and fills with value. //! \~russian Задаёт новый размер и заполняет значением. - //! \sa PIVector::assign(size_t, const T&) + //! \~\sa PIVector::assign(size_t, const T&) inline PIVector2D & assign(size_t rows, size_t cols, const T & f = T()) { mat.assign(rows * cols, f); rows_ = rows; @@ -1114,7 +1166,7 @@ public: //! \~english Reverses the order of rows in place. //! \~russian Изменяет порядок строк на обратный на месте. - //! \sa reverseColumns(), PIVector::reverse() + //! \~\sa reverseColumns(), PIVector::reverse() inline PIVector2D & reverseRows() { const size_t half = rows_ / 2; for (size_t i = 0; i < half; ++i) { @@ -1129,7 +1181,7 @@ public: //! \~english Reverses the order of columns in each row in place. //! \~russian Изменяет порядок столбцов в каждой строке на обратный на месте. - //! \sa reverseRows(), PIVector::reverse() + //! \~\sa reverseRows(), PIVector::reverse() inline PIVector2D & reverseColumns() { for (size_t r = 0; r < rows_; ++r) { Row currentRow = row(r); @@ -1146,7 +1198,7 @@ public: //! \details //! \~english If the range exceeds the array boundaries, it is clipped. If rowCount or colCount is 0, an empty array is returned. //! \~russian Если диапазон выходит за границы массива, он обрезается. Если rowCount или colCount равны 0, возвращается пустой массив. - //! \sa PIVector::getRange() + //! \~\sa PIVector::getRange() inline PIVector2D 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(); const size_t actualRowCount = piMin(rowCount, rows_ - rowStart); @@ -1166,7 +1218,7 @@ public: //! \details //! \~english The original array is not modified. //! \~russian Исходный массив не изменяется. - //! \sa PIVector::map() + //! \~\sa PIVector::map() template inline PIVector2D map(std::function f) const { return PIVector2D(rows_, cols_, mat.template map(f)); @@ -1174,7 +1226,7 @@ public: //! \~english Applies a function (with row and col indices) to each element and returns a new 2D array. //! \~russian Применяет функцию (с индексами строки и столбца) к каждому элементу и возвращает новый двумерный массив. - //! \sa PIVector::mapIndexed() + //! \~\sa PIVector::mapIndexed() template inline PIVector2D mapIndexed(std::function f) const { PIVector mappedMat; @@ -1189,7 +1241,7 @@ public: //! \~english Applies a function to each row (modifiable). //! \~russian Применяет функцию к каждой строке (с возможностью изменения). - //! \sa forEachRow() const, PIVector::forEach() + //! \~\sa forEachRow() const, PIVector::forEach() inline PIVector2D & forEachRow(std::function f) { for (size_t r = 0; r < rows_; ++r) f(row(r)); @@ -1221,7 +1273,7 @@ public: //! \~english Accumulates a value across all elements. //! \~russian Аккумулирует значение по всем элементам. - //! \sa PIVector::reduce() + //! \~\sa PIVector::reduce() template inline ST reduce(std::function f, const ST & initial = ST()) const { return mat.template reduce(f, initial); @@ -1229,7 +1281,7 @@ public: //! \~english Accumulates a value across all elements with indices. //! \~russian Аккумулирует значение по всем элементам с индексами. - //! \sa PIVector::reduceIndexed() + //! \~\sa PIVector::reduceIndexed() template inline ST reduceIndexed(std::function f, const ST & initial = ST()) const { ST ret(initial); @@ -1246,7 +1298,7 @@ public: //! \details //! \~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() + //! \~\sa removeColumn(), PIVector::remove() inline PIVector2D & removeRow(size_t row) { return deleteRows(row, 1); } //! \~english Removes a column from the 2D array. @@ -1254,7 +1306,7 @@ public: //! \details //! \~english This operation is more expensive than removing a row because elements must be moved. //! \~russian Эта операция дороже, чем удаление строки, поскольку требуется перемещение элементов. - //! \sa removeRow(), PIVector::remove() + //! \~\sa removeRow(), PIVector::remove() inline PIVector2D & removeColumn(size_t col) { return deleteColumns(col, 1); } //! \~english Removes all rows that satisfy a condition. @@ -1262,7 +1314,7 @@ public: //! \details //! \~english Rows are removed from the bottom to avoid index shifting issues. //! \~russian Строки удаляются снизу вверх, чтобы избежать проблем со смещением индексов. - //! \sa removeColumnsWhere(), PIVector::removeWhere() + //! \~\sa removeColumnsWhere(), PIVector::removeWhere() inline PIVector2D & removeRowsWhere(std::function test) { ssize_t r = rows_; while (--r >= 0) { @@ -1275,7 +1327,7 @@ public: //! \~english Removes all columns that satisfy a condition. //! \~russian Удаляет все столбцы, удовлетворяющие условию. - //! \sa removeRowsWhere() + //! \~\sa removeRowsWhere() inline PIVector2D & removeColumnsWhere(std::function test) { ssize_t c = cols_; while (--c >= 0) { @@ -1289,7 +1341,7 @@ public: //! \~english Returns a new 2D array containing only the rows that pass the test. //! \~russian Возвращает новый двумерный массив, содержащий только строки, прошедшие проверку. - //! \sa filterColumns(), PIVector::filter() + //! \~\sa filterColumns(), PIVector::filter() inline PIVector2D filterRows(std::function test) const { PIVector2D result; for (size_t r = 0; r < rows_; ++r) { @@ -1303,7 +1355,7 @@ public: //! \~english Returns a new 2D array containing only the columns that pass the test. //! \~russian Возвращает новый двумерный массив, содержащий только столбцы, прошедшие проверку. - //! \sa filterRows() + //! \~\sa filterRows() inline PIVector2D filterColumns(std::function test) const { if (isEmpty()) return PIVector2D(); PIVector goodCols; @@ -1313,13 +1365,8 @@ public: } } PIVector2D 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.mat._copyRaw(result.mat.data(start_dst + gc), mat.data(start_src + goodCols[gc]), 1); - } + for (size_t gc = 0; gc < goodCols.size(); ++gc) { + result.addColumn(col(goodCols[gc])); } return result; } diff --git a/plans/doxygen_example.md b/plans/doxygen_example.md index 52581c92..4c52cdfd 100644 --- a/plans/doxygen_example.md +++ b/plans/doxygen_example.md @@ -11,3 +11,5 @@ | //! \~english | Важное примечание о сложности/поведении на английском языке | | //! \~russian | Важное примечание о сложности/поведении на русском языке | | //! \~\sa | Ссылки на связанные функции | + +NOTE: Не использовать секции \param и \return -- 2.43.0 From 9a007d7f1eada13d86a9a0047b57682a8176b57e Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Fri, 27 Feb 2026 23:43:51 +0300 Subject: [PATCH 27/29] update md --- dependencies.md | 17 +--- options.md | 6 +- plans/doxygen_docs.md | 224 ------------------------------------------ 3 files changed, 4 insertions(+), 243 deletions(-) diff --git a/dependencies.md b/dependencies.md index d0bfcadc..3dd0f8cb 100644 --- a/dependencies.md +++ b/dependencies.md @@ -22,13 +22,6 @@ | **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 | ## Опциональные (тесты/документация) @@ -37,10 +30,6 @@ | **Google Test** | Тестирование (fetched automatically) | | **Doxygen** | Генерация документации | -## Стандартные системные библиотеки - -- libm (math) -- libc (C standard) ## Схема зависимостей модулей @@ -49,10 +38,6 @@ main (core) ├── PCRE2 (встроен) ├── BLAKE2 (встроен) ├── SipHash (встроен) -├── pthread (система) -├── libdl (система) -├── librt (система) -├── libutil (система) └── ICU (опционально) console → main @@ -65,6 +50,6 @@ io_utils → [crypt, если доступен] client_server → io_utils cloud → io_utils, crypt lua → Lua (встроен), LuaBridge (встроен) -http_server → libmicrohttpd, [gnutls] +http_server → libmicrohttpd http_client → libcurl ``` diff --git a/options.md b/options.md index ecc938d1..74eac7ae 100644 --- a/options.md +++ b/options.md @@ -34,11 +34,11 @@ | Переменная | Описание | |------------|----------| | `PIP_BUILD_DEBUG` | Сборка debug версии | -| `PIP_FREERTOS` | Поддержка FreeRTOS | -| `CROSSTOOLS` | Режим кросс-компиляции | +| `PIP_FREERTOS` | Режим сборки для FreeRTOS | +| `CROSSTOOLS` | Собрать инструменты кросс-сборки под хостовую систему (pip_cmg, pip_rc, ...) | | `LOCAL` | Локальная установка (bin/lib/include) | | `PIP_CONTAINERS_MIN_ALLOC` | Переопределить минимальный размер аллокации контейнеров | -| `PIP_CONTAINERS_MAX_POT_ALLOC` | Переопределить максимальный размер (поддерживает X_KiB, X_MiB) | +| `PIP_CONTAINERS_MAX_POT_ALLOC` | Переопределить максимальный размер дополнительной аллокации (поддерживает X_KiB, X_MiB) | ### Примеры использования ```bash diff --git a/plans/doxygen_docs.md b/plans/doxygen_docs.md index 771e2f43..4954ce57 100644 --- a/plans/doxygen_docs.md +++ b/plans/doxygen_docs.md @@ -111,227 +111,3 @@ inline bool operator==(const PIPair & value0, const PIPair Date: Fri, 27 Feb 2026 23:44:01 +0300 Subject: [PATCH 28/29] version --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 88f677c5..4e4740bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,8 +5,8 @@ if (POLICY CMP0177) endif() project(PIP) set(PIP_MAJOR 5) -set(PIP_MINOR 5) -set(PIP_REVISION 5) +set(PIP_MINOR 6) +set(PIP_REVISION 0) set(PIP_SUFFIX ) set(PIP_COMPANY SHS) set(PIP_DOMAIN org.SHS) -- 2.43.0 From 7cf1a1298d1d3b56ed93ac1c6d4e18f5ed29d322 Mon Sep 17 00:00:00 2001 From: "andrey.bychkov" Date: Fri, 27 Feb 2026 23:51:53 +0300 Subject: [PATCH 29/29] remove md files --- .gitignore | 2 + AGENTS.md | 166 --------------------------------------- README.md | 115 +++++++++++++++++++++++++++ dependencies.md | 55 ------------- options.md | 59 -------------- plans/doxygen_docs.md | 113 -------------------------- plans/doxygen_example.md | 15 ---- plans/pivector2d.md | 28 ------- 8 files changed, 117 insertions(+), 436 deletions(-) delete mode 100644 AGENTS.md delete mode 100644 dependencies.md delete mode 100644 options.md delete mode 100644 plans/doxygen_docs.md delete mode 100644 plans/doxygen_example.md delete mode 100644 plans/pivector2d.md diff --git a/.gitignore b/.gitignore index 1acefdd3..1c093651 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ CMakeLists.txt.user* /include /release /build* +/AGENTS.md +/plans diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index 270ffd38..00000000 --- a/AGENTS.md +++ /dev/null @@ -1,166 +0,0 @@ -# AGENTS.md - Agent Guidelines for PIP - -This file provides guidance for agentic coding agents working on the PIP (Platform Independent Primitives) codebase. - -## Project Overview - -PIP is a C++ cross-platform library providing platform-independent abstractions for: -- Core/Types: Strings, variants, containers, datetime, networks -- Threading: Mutexes, semaphores, thread pools, timers -- I/O: Files, serial, CAN, GPIO, SPI, Ethernet -- Math: Vectors, matrices, FFT, quaternions -- Crypto: MD5, SHA, BLAKE2, SipHash -- Compression: zlib support -- HTTP: Client and server support -- Serialization: JSON, binary, XML - -## Build Commands - -### Basic Build -```bash -cmake -B build -cmake --build build -j8 -``` - -### Build with Tests -```bash -cmake -B build -DTESTS=ON -cmake --build build -j8 -``` - -### Run Tests -```bash -ctest --test-dir build/tests # Run all tests -ctest --test-dir build/tests -R # Run specific tests matching regex -ctest --test-dir build/tests -V # Verbose output -``` - -To run a single test: -```bash -# Build the test executable, then run directly: -./build/tests/pip__test -# Or use ctest with specific test name -ctest --test-dir build/tests -R "TestName" -``` - -### Other Commands -```bash -cmake --build build --target clean # Clean build -cmake --install build_pip # Install -cmake --build build --target doc # Build documentation -``` - -### Build Options -```bash --DTESTS=ON # Build tests --DCOVERAGE=ON # Build with coverage --DICU=ON # ICU support for codepage conversion --DSTD_IOSTREAM=ON # std::iostream operators support --DINTROSPECTION=ON # Build with introspection --DPIP_BUILD_CRYPT=ON # Crypt module (requires libsodium) --DPIP_BUILD_FFTW=ON # FFT support -``` - -## Code Style Guidelines - -### File Organization -- Header files: `libs/main/**/*.h` -- Source files: `libs/main/**/*.cpp` -- Private headers: `*_p.h` -- Tests: `tests//` -- Use Doxygen comments (`/*! ... */`) for documentation with `\brief`, `\param`, `\return` - -### Naming Conventions -- **Classes**: PascalCase with `PI` prefix (e.g., `PIString`, `PIByteArray`, `PIVariant`) -- **Functions**: camelCase (e.g., `toAscii()`, `isEmpty()`, `append()`) -- **Member variables**: snake_case, or just lowercase (e.g., `array_size`, `count`) -- **Constants**: PascalCase or UPPER_SNAKE_CASE -- **Enums**: PascalCase for enum names and values - -### Code Formatting -- **Indentation**: Use tabs (4 spaces equivalent) or spaces - match existing code -- **Braces**: Opening brace on same line for functions, new line for namespaces/classes -- **Includes**: System includes first, then project headers -- **Use forward declarations** where possible to reduce compile times -- **Use `nullptr`** instead of `NULL` - -### C++ Standards -- C++11 standard (enforced in CMakeLists.txt) -- Use `override` keyword for virtual function overrides -- Use `explicit` for single-argument constructors -- Use `const` member functions where applicable -- Use range-based `for` loops when possible - -### Error Handling -- Return error codes -- DO NOT USE exceptions -- Use `piCerr` and `piCout` for error messages -- Check for null pointers where appropriate - -### Module Structure - -Each module typically has: -1. Public header: `pip_.h` or `.h` -2. Private implementation: `.cpp` or `_p.cpp` -3. Use `PIP_EXPORT` macro for symbols that need to be exported from the library - -Example class structure: -```cpp -// header.h -#ifndef MODULE_CLASSNAME_H -#define MODULE_CLASSNAME_H - -#include "pip_export.h" - -class PIP_EXPORT ClassName { -public: - ClassName(); - ~ClassName(); - - void doSomething(); - bool isValid() const; - -private: - void privateMethod(); - int data; -}; - -#endif // MODULE_CLASSNAME_H - -// source.cpp -#include "header.h" -#include "piincludes_p.h" - -ClassName::ClassName() : data(0) {} -``` - -### Testing -- Use Google Test framework -- Test files go in `tests//` -- Use `TEST(TestSuite, TestName)` or `TEST_F(TestFixture, TestName)` for test cases -- Use `ASSERT_*` for fatal failures, `EXPECT_*` for non-fatal -- Test naming: `_` - -Example: -```cpp -#include "pistring.h" -#include "gtest/gtest.h" - -TEST(PIString_Tests, constructor_empty) { - PIString str; - ASSERT_TRUE(str.isEmpty()); -} -``` - -### Module Dependencies -- Main library: `libs/main/` -- Third-party: `3rd/` -- Utils: `utils/` - -### 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 diff --git a/README.md b/README.md index 11691014..236ceaf7 100644 --- a/README.md +++ b/README.md @@ -40,3 +40,118 @@ You should add ${} to your target. [🇷🇺 Онлайн документация](https://shstk.ru/pip/html/ru/index.html) [🇷🇺 Qt-help](https://shstk.ru/pip/pip_ru.qch) + +## Основные опции сборки + +### Стандартные опции (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` | Собрать инструменты кросс-сборки под хостовую систему (pip_cmg, pip_rc, ...) | +| `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 +``` + +## 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 | + +### Опциональные (тесты/документация) + +| Инструмент | Назначение | +|------------|------------| +| **Google Test** | Тестирование (fetched automatically) | +| **Doxygen** | Генерация документации | + + +### Схема зависимостей модулей + +``` +main (core) +├── PCRE2 (встроен) +├── BLAKE2 (встроен) +├── SipHash (встроен) +└── 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 +http_client → libcurl +``` + diff --git a/dependencies.md b/dependencies.md deleted file mode 100644 index 3dd0f8cb..00000000 --- a/dependencies.md +++ /dev/null @@ -1,55 +0,0 @@ -# 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 | - -## Опциональные (тесты/документация) - -| Инструмент | Назначение | -|------------|------------| -| **Google Test** | Тестирование (fetched automatically) | -| **Doxygen** | Генерация документации | - - -## Схема зависимостей модулей - -``` -main (core) -├── PCRE2 (встроен) -├── BLAKE2 (встроен) -├── SipHash (встроен) -└── 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 -http_client → libcurl -``` diff --git a/options.md b/options.md deleted file mode 100644 index 74eac7ae..00000000 --- a/options.md +++ /dev/null @@ -1,59 +0,0 @@ -# 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` | Собрать инструменты кросс-сборки под хостовую систему (pip_cmg, pip_rc, ...) | -| `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 -``` diff --git a/plans/doxygen_docs.md b/plans/doxygen_docs.md deleted file mode 100644 index 4954ce57..00000000 --- a/plans/doxygen_docs.md +++ /dev/null @@ -1,113 +0,0 @@ -# План: Добавление документации 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 -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 -inline bool operator==(const PIPair & value0, const PIPair & 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 - //! \{ - //! \file - //! \brief - //! \~english Brief description - //! \~russian Краткое описание - //! \~\} - ``` - -3. **Добавить документацию для каждого класса**: - ```cpp - //! \class ClassName - //! \brief - //! \~english Class description - //! \~russian Описание класса - ``` - -4. **Добавить документацию для методов**: - ```cpp - //! \~english Method description. - //! \~russian Описание метода. - ReturnType methodName(params); - ``` - -5. **Проверить, что файл компилируется** после изменений diff --git a/plans/doxygen_example.md b/plans/doxygen_example.md deleted file mode 100644 index 4c52cdfd..00000000 --- a/plans/doxygen_example.md +++ /dev/null @@ -1,15 +0,0 @@ -Ключевые элементы документации - -| Элемент | Описание | -|---------|----------| -| //! \~english | Описание на английском языке | -| //! \~russian | Описание на русском языке | -| //! \details | | -| //! \~english | Детальное объяснение на английском языке | -| //! \~russian | Детальное объяснение на русском языке | -| //! \note | | -| //! \~english | Важное примечание о сложности/поведении на английском языке | -| //! \~russian | Важное примечание о сложности/поведении на русском языке | -| //! \~\sa | Ссылки на связанные функции | - -NOTE: Не использовать секции \param и \return diff --git a/plans/pivector2d.md b/plans/pivector2d.md deleted file mode 100644 index 6e9c751a..00000000 --- a/plans/pivector2d.md +++ /dev/null @@ -1,28 +0,0 @@ -# План рефакторинга PIVector2D - -## Этап 1: Сборка - -### 1.1 Собрать проект -- [x] собери проект, при необходимости поправь ошибки - -## Этап 2: Проверить и поправить тесты - -### 2.1 Запустить тесты -- [x] Запустить: `./build/tests/pip_math_test --gtest_filter="*Vector2D*"` -- [x] В случае ошибок внести правки в pivector2d.h - ---- - -## Этап 3: Заменить PIPair на PIVector2DIndex - -### 3.1 Создать структуру PIVector2DIndex -- [x] Создано: `struct Index { ssize_t row; ssize_t col; };` - -### 3.2 Обновить return types -- [x] indexOf() -> возвращает Index вместо PIPair -- [x] lastIndexOf() -- [x] indexWhere() -- [x] lastIndexWhere() - - ---- -- 2.43.0