PIVector2D - add funcs, optimize, tests, fixes, doxygen #194
@@ -705,6 +705,11 @@ public:
|
|||||||
size_t st_, sz_;
|
size_t st_, sz_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
inline RowConst(const PIVector2D<T>::Row & r): p_(r.p_) {
|
||||||
|
st_ = r.st_;
|
||||||
|
sz_ = r.sz_;
|
||||||
|
}
|
||||||
|
|
||||||
//! \~english Size of the row (number of columns).
|
//! \~english Size of the row (number of columns).
|
||||||
//! \~russian Размер строки (количество столбцов).
|
//! \~russian Размер строки (количество столбцов).
|
||||||
inline size_t size() const { return sz_; }
|
inline size_t size() const { return sz_; }
|
||||||
@@ -875,6 +880,12 @@ public:
|
|||||||
size_t step_, col_, sz_;
|
size_t step_, col_, sz_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
inline ColConst(const PIVector2D<T>::Col & c): p_(c.p_) {
|
||||||
|
step_ = c.step_;
|
||||||
|
col_ = c.col_;
|
||||||
|
sz_ = c.sz_;
|
||||||
|
}
|
||||||
|
|
||||||
//! \~english Size of the column (number of rows).
|
//! \~english Size of the column (number of rows).
|
||||||
//! \~russian Размер столбца (количество строк).
|
//! \~russian Размер столбца (количество строк).
|
||||||
inline size_t size() const { return sz_; }
|
inline size_t size() const { return sz_; }
|
||||||
@@ -1130,18 +1141,6 @@ public:
|
|||||||
//! \~russian Если массив был пуст, количество столбцов устанавливается равным размеру исходной строки.
|
//! \~russian Если массив был пуст, количество столбцов устанавливается равным размеру исходной строки.
|
||||||
//! В противном случае копируется только `min(cols(), other.size())` элементов; остальные элементы новой строки инициализируются по
|
//! В противном случае копируется только `min(cols(), other.size())` элементов; остальные элементы новой строки инициализируются по
|
||||||
//! умолчанию. \sa PIVector::push_back()
|
//! умолчанию. \sa PIVector::push_back()
|
||||||
inline PIVector2D<T> & addRow(const Row & other) {
|
|
||||||
if (cols_ == 0) cols_ = other.sz_;
|
|
||||||
const size_t sz = piMin<size_t>(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<T> & addRow(const RowConst & other) {
|
inline PIVector2D<T> & addRow(const RowConst & other) {
|
||||||
if (cols_ == 0) cols_ = other.sz_;
|
if (cols_ == 0) cols_ = other.sz_;
|
||||||
const size_t sz = piMin<size_t>(cols_, other.sz_);
|
const size_t sz = piMin<size_t>(cols_, other.sz_);
|
||||||
@@ -1164,6 +1163,72 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! \~english Appends a new column to the right of the array from a \a PIVector.
|
||||||
|
//! \~russian Добавляет новую строку в конец массива из \a PIVector.
|
||||||
|
inline PIVector2D<T> & 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<T> & addColumn(const PIVector<T> & other) {
|
||||||
|
if (other.size() == 0) return *this;
|
||||||
|
if (size() == 0) {
|
||||||
|
_resizeRaw(other.size(), 1);
|
||||||
|
for (size_t r = 0; r < other.size(); ++r) {
|
||||||
|
element(r, 0) = other[r];
|
||||||
|
}
|
||||||
|
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.
|
//! \~english Resizes the 2D array to new dimensions.
|
||||||
//! \~russian Изменяет размер двумерного массива.
|
//! \~russian Изменяет размер двумерного массива.
|
||||||
//! \param rows New number of rows.
|
//! \param rows New number of rows.
|
||||||
|
|||||||
@@ -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<int> empty;
|
||||||
|
PIVector<int> newCol(5);
|
||||||
|
for (size_t i = 0; i < 5; ++i)
|
||||||
|
newCol[i] = static_cast<int>(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<int>(100 + r));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Vector2DTest, addColumn_appends_column_to_existing) {
|
||||||
|
size_t oldRows = vec.rows();
|
||||||
|
size_t oldCols = vec.cols();
|
||||||
|
|
||||||
|
PIVector<int> 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<int>(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<int> 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<int> 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<int> empty;
|
||||||
|
PIVector<int> 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<int> 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 ====================
|
// ==================== RESIZE TESTS ====================
|
||||||
class Vector2DResizeTest: public Vector2DTest {
|
class Vector2DResizeTest: public Vector2DTest {
|
||||||
protected:
|
protected:
|
||||||
@@ -670,7 +810,8 @@ TEST(Vector2DTransposeTest, singleElement_returnsSame) {
|
|||||||
|
|
||||||
TEST(Vector2DTransposeTest, oneRow_becomesOneColumn) {
|
TEST(Vector2DTransposeTest, oneRow_becomesOneColumn) {
|
||||||
PIVector2D<int> rowVec(1, 5);
|
PIVector2D<int> rowVec(1, 5);
|
||||||
for (size_t c = 0; c < 5; ++c) rowVec.element(0, c) = static_cast<int>(c);
|
for (size_t c = 0; c < 5; ++c)
|
||||||
|
rowVec.element(0, c) = static_cast<int>(c);
|
||||||
auto transposed = rowVec.transposed();
|
auto transposed = rowVec.transposed();
|
||||||
EXPECT_EQ(transposed.rows(), 5);
|
EXPECT_EQ(transposed.rows(), 5);
|
||||||
EXPECT_EQ(transposed.cols(), 1);
|
EXPECT_EQ(transposed.cols(), 1);
|
||||||
@@ -681,7 +822,8 @@ TEST(Vector2DTransposeTest, oneRow_becomesOneColumn) {
|
|||||||
|
|
||||||
TEST(Vector2DTransposeTest, oneColumn_becomesOneRow) {
|
TEST(Vector2DTransposeTest, oneColumn_becomesOneRow) {
|
||||||
PIVector2D<int> colVec(5, 1);
|
PIVector2D<int> colVec(5, 1);
|
||||||
for (size_t r = 0; r < 5; ++r) colVec.element(r, 0) = static_cast<int>(r);
|
for (size_t r = 0; r < 5; ++r)
|
||||||
|
colVec.element(r, 0) = static_cast<int>(r);
|
||||||
auto transposed = colVec.transposed();
|
auto transposed = colVec.transposed();
|
||||||
EXPECT_EQ(transposed.rows(), 1);
|
EXPECT_EQ(transposed.rows(), 1);
|
||||||
EXPECT_EQ(transposed.cols(), 5);
|
EXPECT_EQ(transposed.cols(), 5);
|
||||||
@@ -691,7 +833,7 @@ TEST(Vector2DTransposeTest, oneColumn_becomesOneRow) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(Vector2DTest, transposed_doesNotModifyOriginal) {
|
TEST_F(Vector2DTest, transposed_doesNotModifyOriginal) {
|
||||||
auto original = vec; // копия для сравнения
|
auto original = vec; // копия для сравнения
|
||||||
auto transposed = vec.transposed();
|
auto transposed = vec.transposed();
|
||||||
// Проверяем, что исходный массив не изменился
|
// Проверяем, что исходный массив не изменился
|
||||||
EXPECT_EQ(vec, original);
|
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<int>(vec.size()); };
|
auto isLessThanMax = [&](const int & e) { return e < static_cast<int>(vec.size()); };
|
||||||
EXPECT_TRUE(col.every(isLessThanMax));
|
EXPECT_TRUE(col.every(isLessThanMax));
|
||||||
auto isNotEven = [](const int & e) { return e % 2 != 0; };
|
auto isNotEven = [](const int & e) { return e % 2 != 0; };
|
||||||
col.forEach([](const int & v) { piCout << v; });
|
|
||||||
EXPECT_FALSE(col.every(isNotEven));
|
EXPECT_FALSE(col.every(isNotEven));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user