56 #include <initializer_list> 62 #include "gridlocation.h" 63 #include "privatestrlib.h" 83 template <
typename ValueType>
105 Grid(
int _rowCount,
int _columnCount);
106 Grid(
int _rowCount,
int _columnCount,
const ValueType& value);
112 Grid(std::initializer_list<std::initializer_list<ValueType>> list);
119 virtual ~Grid() =
default;
137 bool equals(
const Grid<ValueType>& grid2)
const;
145 void fill(
const ValueType& value);
156 ValueType
get(
int row,
int col);
157 const ValueType&
get(
int row,
int col)
const;
158 ValueType
get(
const GridLocation& loc);
159 const ValueType&
get(
const GridLocation& loc)
const;
168 bool inBounds(
int row,
int col)
const;
169 bool inBounds(
const GridLocation& loc)
const;
177 bool isEmpty()
const;
190 GridLocationRange locations(
bool rowMajor =
true)
const;
201 void mapAll(std::function<
void (
const ValueType &)>)
const;
212 void mapAllColumnMajor(std::function<
void (
const ValueType &)>)
const;
240 void resize(
int _rowCount,
int _columnCount,
bool retain =
false);
251 void set(
int row,
int col,
const ValueType& value);
252 void set(
const GridLocation& loc,
const ValueType& value);
271 string toString()
const;
284 string rowStart =
"{",
286 string colSeparator =
", ",
287 string rowSeparator =
",\n ")
const;
300 GridRow operator [](
int row);
301 const GridRowConst operator [](
int row)
const;
302 ValueType& operator [](
const GridLocation& loc);
303 const ValueType& operator [](
const GridLocation& loc)
const;
324 bool operator ==(
const Grid& grid2)
const;
332 bool operator !=(
const Grid& grid2)
const;
342 bool operator <(
const Grid& grid2)
const;
343 bool operator <=(
const Grid& grid2)
const;
344 bool operator >(
const Grid& grid2)
const;
345 bool operator >=(
const Grid& grid2)
const;
367 std::vector<ValueType> _elements;
369 int _columnCount = 0;
381 void checkIndexes(
int row,
int col,
382 int rowMax,
int colMax,
383 string prefix)
const;
384 int gridCompare(
const Grid& grid2)
const;
396 using iterator =
typename std::vector<ValueType>::iterator;
397 using const_iterator =
typename std::vector<ValueType>::const_iterator;
400 return _elements.begin();
403 return _elements.end();
406 const_iterator begin()
const {
407 return _elements.begin();
409 const_iterator end()
const {
410 return _elements.end();
421 GridRow() : _gp(nullptr), _row(0) {
425 ValueType& operator [](
int col) {
426 _gp->checkIndexes(_row, col, _gp->_rowCount-1, _gp->_columnCount-1,
"operator [][]");
427 return _gp->_elements[(_row * _gp->_columnCount) + col];
430 ValueType operator [](
int col)
const {
431 _gp->checkIndexes(_row, col, _gp->_rowCount-1, _gp->_columnCount-1,
"operator [][]");
432 return _gp->_elements[(_row * _gp->_columnCount) + col];
436 return _gp->numCols();
440 GridRow(Grid* gridRef,
int index) {
449 friend class GridRow;
453 GridRowConst() : _gp(nullptr), _row(0) {
457 const ValueType operator [](
int col)
const {
458 _gp->checkIndexes(_row, col, _gp->_rowCount-1, _gp->_columnCount-1,
"operator [][]");
459 return _gp->_elements[(_row * _gp->_columnCount) + col];
463 return _gp->numCols();
467 GridRowConst(Grid*
const gridRef,
int index) : _gp(gridRef), _row(index) {}
469 const Grid*
const _gp;
473 friend class GridRowConst;
476 template <
typename ValueType>
477 Grid<ValueType>::Grid(
int numRows,
int numCols) {
478 resize(numRows, numCols);
481 template <
typename ValueType>
482 Grid<ValueType>::Grid(
int numRows,
int numCols,
const ValueType& value) {
483 resize(numRows, numCols);
487 template <
typename ValueType>
488 Grid<ValueType>::Grid(std::initializer_list<std::initializer_list<ValueType>> list) {
490 _rowCount = list.size();
491 if (list.begin() != list.end()) {
492 _columnCount = list.begin()->size();
494 resize(_rowCount, _columnCount);
497 auto rowItr = list.begin();
498 for (
int row = 0; row < _rowCount; row++) {
499 if (static_cast<int>(rowItr->size()) != _columnCount) {
500 throw std::runtime_error(
"Grid::constructor: initializer list is not rectangular (must have same # cols in each row)");
502 auto colItr = rowItr->begin();
503 for (
int col = 0; col < _columnCount; col++) {
504 set(row, col, *colItr);
511 template <
typename ValueType>
512 void Grid<ValueType>::clear() {
513 ValueType defaultValue = ValueType();
514 for (
int r = 0; r < _rowCount; r++) {
515 for (
int c = 0; c < _columnCount; c++) {
516 set(r, c, defaultValue);
521 template <
typename ValueType>
522 bool Grid<ValueType>::equals(
const Grid<ValueType>& grid2)
const {
524 if (
this == &grid2) {
528 if (_rowCount != grid2._rowCount || _columnCount != grid2._columnCount) {
531 for (
int row = 0; row < _rowCount; row++) {
532 for (
int col = 0; col < _columnCount; col++) {
533 if (
get(row, col) != grid2.get(row, col)) {
541 template <
typename ValueType>
542 void Grid<ValueType>::fill(
const ValueType& value) {
543 for (
int row = 0; row < _rowCount; row++) {
544 for (
int col = 0; col < _columnCount; col++) {
545 set(row, col, value);
553 template <
typename ValueType>
554 ValueType Grid<ValueType>::get(
int row,
int col) {
555 checkIndexes(row, col, _rowCount-1, _columnCount-1,
"get");
556 return _elements[(row * _columnCount) + col];
559 template <
typename ValueType>
560 const ValueType& Grid<ValueType>::get(
int row,
int col)
const {
561 checkIndexes(row, col, _rowCount-1, _columnCount-1,
"get");
562 return _elements[(row * _columnCount) + col];
565 template <
typename ValueType>
566 ValueType Grid<ValueType>::get(
const GridLocation& loc) {
567 return get(loc.row, loc.col);
570 template <
typename ValueType>
571 const ValueType& Grid<ValueType>::get(
const GridLocation& loc)
const {
572 return get(loc.row, loc.col);
575 template <
typename ValueType>
576 bool Grid<ValueType>::inBounds(
int row,
int col)
const {
577 return row >= 0 && col >= 0 && row < _rowCount && col < _columnCount;
580 template <
typename ValueType>
581 bool Grid<ValueType>::inBounds(
const GridLocation& loc)
const {
582 return inBounds(loc.row, loc.col);
585 template <
typename ValueType>
586 bool Grid<ValueType>::isEmpty()
const {
587 return _rowCount == 0 || _columnCount == 0;
590 template <
typename ValueType>
591 GridLocationRange Grid<ValueType>::locations(
bool rowMajor)
const {
592 return GridLocationRange(0, 0, numRows() - 1, numCols() - 1, rowMajor);
595 template <
typename ValueType>
596 void Grid<ValueType>::mapAll(std::function<
void (
const ValueType &)> fn)
const {
597 for (
int i = 0; i < _rowCount; i++) {
598 for (
int j = 0; j < _columnCount; j++) {
604 template <
typename ValueType>
605 void Grid<ValueType>::mapAllColumnMajor(std::function<
void (
const ValueType &)> fn)
const {
606 for (
int j = 0; j < _columnCount; j++) {
607 for (
int i = 0; i < _rowCount; i++) {
613 template <
typename ValueType>
614 int Grid<ValueType>::numCols()
const {
618 template <
typename ValueType>
619 int Grid<ValueType>::numRows()
const {
623 template <
typename ValueType>
624 void Grid<ValueType>::resize(
int numRows,
int numCols,
bool retain) {
625 if (numRows < 0 || numCols < 0) {
626 std::ostringstream out;
627 out <<
"Grid::resize: Attempt to resize grid to invalid size (" 628 << numRows <<
", " << numCols <<
")";
629 throw std::runtime_error(out.str());
633 if (numRows == this->_rowCount && numCols == this->_columnCount && retain) {
642 std::vector<ValueType> oldElements = std::move(_elements);
643 int oldnRows = this->_rowCount;
644 int oldnCols = this->_columnCount;
647 this->_rowCount = numRows;
648 this->_columnCount = numCols;
649 this->_elements = std::vector<ValueType>(numRows * numCols, ValueType());
653 int minRows = oldnRows < numRows ? oldnRows : numRows;
654 int minCols = oldnCols < numCols ? oldnCols : numCols;
655 for (
int row = 0; row < minRows; row++) {
656 for (
int col = 0; col < minCols; col++) {
657 this->_elements[(row * numCols) + col] = oldElements[(row * oldnCols) + col];
663 template <
typename ValueType>
664 void Grid<ValueType>::set(
int row,
int col,
const ValueType& value) {
665 checkIndexes(row, col, _rowCount - 1, _columnCount - 1,
"set");
666 _elements[(row * _columnCount) + col] = value;
669 template <
typename ValueType>
670 void Grid<ValueType>::set(
const GridLocation& loc,
const ValueType& value) {
671 set(loc.row, loc.col, value);
674 template <
typename ValueType>
675 int Grid<ValueType>::size()
const {
676 return _rowCount * _columnCount;
679 template <
typename ValueType>
680 string Grid<ValueType>::toString()
const {
681 std::ostringstream os;
686 template <
typename ValueType>
687 string Grid<ValueType>::toString2D(
688 string rowStart, string rowEnd,
689 string colSeparator, string rowSeparator)
const {
690 std::ostringstream os;
694 for (
int i = 0; i < nr ; i++) {
699 for (
int j = 0; j < nc; j++) {
703 writeGenericValue(os,
get(i, j),
true);
711 template <
typename ValueType>
712 typename Grid<ValueType>::GridRow Grid<ValueType>::operator [](
int row) {
713 return GridRow(
this, row);
716 template <
typename ValueType>
717 ValueType& Grid<ValueType>::operator [](
const GridLocation& loc) {
718 checkIndexes(loc.row, loc.col, _rowCount-1, _columnCount-1,
"operator []");
719 return _elements[(loc.row * _columnCount) + loc.col];
722 template <
typename ValueType>
723 const typename Grid<ValueType>::GridRowConst
724 Grid<ValueType>::operator [](
int row)
const {
725 return GridRowConst(const_cast<Grid*>(
this), row);
728 template <
typename ValueType>
729 const ValueType& Grid<ValueType>::operator [](
const GridLocation& loc)
const {
730 checkIndexes(loc.row, loc.col, _rowCount-1, _columnCount-1,
"operator []");
731 return _elements[(loc.row * _columnCount) + loc.col];
734 template <
typename ValueType>
735 bool Grid<ValueType>::operator ==(
const Grid& grid2)
const {
736 return equals(grid2);
739 template <
typename ValueType>
740 bool Grid<ValueType>::operator !=(
const Grid& grid2)
const {
741 return !equals(grid2);
744 template <
typename ValueType>
745 bool Grid<ValueType>::operator <(
const Grid& grid2)
const {
746 return gridCompare(grid2) < 0;
749 template <
typename ValueType>
750 bool Grid<ValueType>::operator <=(
const Grid& grid2)
const {
751 return gridCompare(grid2) <= 0;
754 template <
typename ValueType>
755 bool Grid<ValueType>::operator >(
const Grid& grid2)
const {
756 return gridCompare(grid2) > 0;
759 template <
typename ValueType>
760 bool Grid<ValueType>::operator >=(
const Grid& grid2)
const {
761 return gridCompare(grid2) >= 0;
764 template <
typename ValueType>
765 void Grid<ValueType>::checkIndexes(
int row,
int col,
766 int rowMax,
int colMax,
767 string prefix)
const {
768 const int rowMin = 0;
769 const int colMin = 0;
770 if (row < rowMin || row > rowMax || col < colMin || col > colMax) {
771 std::ostringstream out;
772 out <<
"Grid::" << prefix <<
": (" << row <<
", " << col <<
")" 773 <<
" is outside of valid range [";
774 if (rowMin < rowMax && colMin < colMax) {
775 out <<
"(" << rowMin <<
", " << colMin <<
")..(" 776 << rowMax <<
", " << colMax <<
")";
777 }
else if (rowMin == rowMax && colMin == colMax) {
778 out <<
"(" << rowMin <<
", " << colMin <<
")";
781 throw std::runtime_error(out.str());
785 template <
typename ValueType>
786 int Grid<ValueType>::gridCompare(
const Grid& grid2)
const {
787 if (_rowCount != grid2._rowCount)
return _rowCount - grid2._rowCount;
788 if (_columnCount != grid2._columnCount)
return _columnCount - grid2._columnCount;
791 itr2 = grid2.begin(),
795 itr1 != end1 && itr2 != end2;
810 }
else if (*itr2 < *itr1) {
817 if (itr1 == end1 && itr2 == end2) {
819 }
else if (itr1 == end1) {
833 template <
typename ValueType>
834 std::ostream& operator <<(std::ostream& os, const Grid<ValueType>& grid) {
836 int nRows = grid.numRows();
837 int nCols = grid.numCols();
838 for (
int i = 0; i < nRows; i++) {
843 for (
int j = 0; j < nCols; j++) {
847 writeGenericValue(os, grid.get(i, j),
true);
854 template <
typename ValueType>
855 std::istream& operator >>(std::istream& is, Grid<ValueType>& grid) {
856 std::vector<std::vector<ValueType>> vec2d;
857 if (!(is >> vec2d)) {
858 is.setstate(std::ios_base::failbit);
862 int nRows = vec2d.size();
863 int nCols = (nRows == 0) ? 0 : vec2d[0].size();
864 grid.resize(nRows, nCols);
865 for (
int i = 0; i < nRows; i++) {
866 for (
int j = 0; j < nCols; j++) {
867 grid[i][j] = vec2d[i][j];
881 template <
typename T>
882 const T& randomElement(
const Grid<T>& grid) {
883 if (grid.isEmpty()) {
884 throw std::runtime_error(
"randomElement: empty grid was passed");
887 int randomIndex = rand() % grid.size();
888 int row = randomIndex / grid.numCols();
889 int col = randomIndex % grid.numCols();
890 return grid.get(row, col);
896 template <
typename T>
897 void shuffle(Grid<T>& grid) {
898 int rows = grid.numRows();
899 int cols = grid.numCols();
900 int length = rows * cols;
901 for (
int i = 0; i < length; i++) {
902 int j = (rand() % (length - i)) + i;
908 T temp = grid[r1][c1];
909 grid[r1][c1] = grid[r2][c2];