I have a class called Grid which is composed of Cells. Each cell can have its own format (the concept is similar to MS Excel).
The format in the Grid is kept in a vector std::vector<std::unique_ptr<CellFormat>> m_CellFormatTable which owns all the formatting, so whenever I need to read a Cells format, I read it from the vector and whenever there is a change, it is reported back to the vector. Sorry, I am quite new to C++11 standards so my thinking might be wrong.
Since a grid is a matrix and each cell belongs to a different part of the matrix when there is a change in a cell's format it should be reflected in the correct part of the matrix, namely positioned correctly in the vector (CellFormatTable). Therefore, at this stage I cannot use the push_back method of the vector.
The CellFormat class:
struct CellFormat
{
wxFont m_Font;
wxColor m_BackgroundColor, m_TextColor;
int m_HorizontalAlignment, m_VerticalAlignment;
CellFormat(Grid* ws) {
m_BackgroundColor = ws->GetDefaultCellBackgroundColour();
m_TextColor=ws->GetDefaultCellTextColour();
int horizontal = 0, vertical = 0;
ws->GetDefaultCellAlignment(&horizontal, &vertical);
}
CellFormat(const CellFormat& other) {
m_Font = other.m_Font;
m_BackgroundColor = other.m_BackgroundColor;
m_TextColor = other.m_TextColor;
m_HorizontalAlignment = other.m_HorizontalAlignment;
m_VerticalAlignment = other.m_VerticalAlignment;
}
CellFormat& operator=(const CellFormat& other) {
if (this == &other) return *this;
m_Font = other.m_Font;
m_BackgroundColor = other.m_BackgroundColor;
m_TextColor = other.m_TextColor;
m_HorizontalAlignment = other.m_HorizontalAlignment;
m_VerticalAlignment = other.m_VerticalAlignment;
return *this;
}
};
In the Grid.h
class Grid{
std::vector<std::unique_ptr<CellFormat>> m_CellFormatTable;
//
CellFormat* GetCellFormat(int row, int column);
void SetCellFormat(int row, int column, CellFormat format);
void ApplyCellFormat(int row, int column, const CellFormat* format);
CellFormat* CreateCellFormat(int row, int column);
//rest is omitted
}
In Grid.cpp
Grid(some arguments){
m_CellFormatTable.resize(nrows*ncols);
//rest is omitted
}
CellFormat* Grid::GetCellFormat(int row, int column)
{
int ncols= GetNumberCols();
return m_CellFormatTable[row*ncols+ column].get();
}
void Grid::SetCellFormat(int row, int column, CellFormat other)
{
CellFormat* format = GetCellFormat(row, column);
if (format == 0) format = CreateCellFormat(row, column);
*format = other;
}
void Grid::ApplyCellFormat(int row, int column, const CellFormat * format)
{
if (format == 0) {
int ncols= GetNumberCols();
//Set everything to default values
//Omitted
m_CellFormatTable[row*ncols+ column].reset();
}
else {
wxColor bgcolor = format->m_BackgroundColor;
if (bgcolor.IsOk()) SetCellBackgroundColour(row, column, bgcolor);
SetCellTextColour(row, column, format->m_TextColor);
SetCellFont(row, column, format->m_Font);
SetCellAlignment(row, column, format->m_HorizontalAlignment, format->m_VerticalAlignment);
}
}
CellFormat* Grid::CreateCellFormat(int row, int column)
{
int ncols= GetNumberCols();
CellFormat* format = new CellFormat(this);
m_CellFormatTable.emplace(m_CellFormatTable.begin() + row*ncols+ column, std::move(format));
return format;
}
Whenever I format a cell, say its background color is changed, I use the following attempt:
CellFormat* format = ws->GetCellFormat(row, col);
if (format == 0) format = ws->CreateCellFormat(row, col);
if (ChangeFillColor) {
ws->SetCellBackgroundColour(row, col, m_LastChosenFillColor);
format->m_BackgroundColor = m_LastChosenFillColor;
}
The code fails at ApplyCellFormat function at the point of format->m_BackgroundColor since the color which should have been Cell's background color is not valid. This tells me that most and highly likely CreateCellFormat does not place CellFormat in the right location. I try to use insert rather than emplace but compiler (VS 2015) complained all my attempts.
Any ideas appreciated.
You have several problems.
One is that you add a CellFormat* but your vector stores unique_ptr ;so you need std::make_uniquewith the new format.
Question: are you sure you need a vector of pointers instead of objects?
Other is that you presume the vector to have all data for all cells, being 0 if they are not set yet. That's wrong. The vector only have as many elements as you have 'pushed' or 'emplaced'.
Let's say you have 'pushed' the format for cell (0,0). Now you want to set the format for (5,2) which is (say you have 10 cols) the 52th element in the vector, but you have only one. So vector[51] is undefined (vector.at(51) will raise an error).
Add all cell formats first, with some value = 0 to tell it has not been set yet. Or re-think your strategy.
By the way, you can use wxGridCellAttr which provides what you are coding on your own.
From the fact that you use a vector of unique_ptr (rather than of objects), I deduce that not all elements of the matrix are actually occupied. In this case, it may be better to use a std::map (or std::unordered_map if the matrix is very large) of objects (not unique_ptrs).
template<typename T>
struct grid
{
using index = std::pair<unsigned, unsigned>;
// insert element if not already present
// returns if insertion occurred
template<typename...Args>
bool insert(index const&i, Args&&...args)
{
return data.emplace(std::forward<Args>(args)...).second;
}
// remove element (if it exists)
void remove(index const&i)
{
data.erase(i);
}
// get pointer to element, may be nullptr
T* get(index const&i)
{
auto it = data.find(i);
return it==data.end() ?
nullptr : std::addressof(*it);
}
private:
std::map<index,T> data;
};
The reason I see that your code is failing in this section of your code:
CellFormat* format = ws->GetCellFormat(row, col);
if (format == 0) format = ws->CreateCellFormat(row, col);
if (ChangeFillColor) {
ws->SetCellBackgroundColour(row, col, m_LastChosenFillColor);
format->m_BackgroundColor = m_LastChosenFillColor;
}
Is due to how your class is defined:
class Grid{
std::vector<std::unique_ptr<CellFormat>> m_CellFormatTable;
//
CellFormat* GetCellFormat(int row, int column);
void SetCellFormat(int row, int column, CellFormat format);
void ApplyCellFormat(int row, int column, const CellFormat* format);
CellFormat* CreateCellFormat(int row, int column);
//rest is omitted
}
By Default your class has it's members and functions set as private:
Change your class to this:
class Grid {
public:
typedef std::vector<std::unique_ptr<CellFormat>> Format;
private:
Format m_CellFormatTable;
public:
CellFormat* getCellFormat( int row, int column );
void setCellFormat( int row, int column, const CellFormat& format );
void applyCellFormat( int row, int column, const CellFormat& format );
// Add This Function If Needed
Format getCellFormatTable() const { return m_CellFormatTable; }
};
So your class's member functions are declared as public: Then outside and non-friend objects can now have access to this class's member functions and be able to return the data structure via a get method.
Thanks to all for helpful comments and posts. Finally it works as expected.
As Ripi2 suggested, CellFormat objects in the vector were not initialized, so in the constructor I initialized them. Also not presented here, I had somewhere in the code a vector of objects not initialized, so corrected that part as well.
Although looping through all the rows and columns of the grid and creating a default format is NOT the best idea, a future work for me will be Walter's suggestion, i.e. to use sets.
Grid(some arguments){
for (int i = 0; i < nrows*ncols; i++) {
m_CellFormatTable.emplace_back(new CellFormat(this));
}
//Rest is omitted
}
Also corrected below code as well:
CellFormat* Grid::CreateCellFormat(int row, int column)
{
int ncols = GetNumberCols();
CellFormat* format = new CellFormat(this);
std::unique_ptr<CellFormat> ptr(format);
m_CellFormatTable.emplace(m_CellFormatTable.begin() + row*ncols + column,std::move(ptr));
return format;
}
One way to keep track of formatting is:
CellFormat* format = ws->GetCellFormat(i, j);
if (ChangeFillColor) {
ws->SetCellBackgroundColour(i, j, m_LastChosenFillColor);
format->m_BackgroundColor = m_LastChosenFillColor;
}
Related
Suppose I have a very large array of data:
double matrix[100000][100] = {0.0};
During runtime this data is updated. Now I want to give the reference to this data to a function FUNC. However, I want to only give one column to the function FUNC, like:
FUNC(matrix["all elements"]["only column with index 5"]);
and not the entire array. Furthermore, I dont want to perform a copy operation before (because this is slow), I just want to give the pointer or reference to the specific rows/columns inside the large array data. The function should only see an array like:
void FUNC(double* array)
{
for (int i = 0; i < 100000; i++)
doSomething(array[i]);
}
How do I do give this partial data from array "matrix" to the function FUNC?
The column values of your matrix are not sequential in memory, so you can't pass a single column to FUNC() without making a copy of the data into a sequential array. However, if you are able to add the column index as an additional parameter to FUNC() then you can do something like this instead:
const int MAX_ROWS = ...;
const int MAX_COLS = ...;
using Matrix = double[MAX_ROWS][MAX_COLS];
void doSomething(double value)
{
...
}
void FUNC(const Matrix& matrix, int column)
{
for (int row = 0; row < MAX_ROWS; ++row) {
doSomething(matrix[row][column]);
}
}
Matrix matrix = {};
...
FUNC(matrix, 5);
Online Demo
I'd like to design a crossword puzzle editor in C++. It is a grid of blocks, each block containing a letter (or being black between two words), possibly a number and a thick or thin border line.
The block is therefore a container class for them. The grid is a container of blocks. But how would I structure the grid?
A raw 2d array: Block grid[row][column]?
Vector of Vectors: vector<vector<Block>>?
Two vectors, one for the rows and one for the columns: vector<Block> row; vector<Block> column?
A map, which keys are the row/column pairs and the values are the blocks: map<int[2], Block>?
By default, plain static/dynamic arrays (or their wrappers) are the most preferable: they are the most comfortable for both the programmer (random access API etc) and the processor (memory locality etc).
The easiest-to-implement Block layout in an array/a vector is [first row Blocks..., second row Blocks..., etc] - a 1D array which acts as a 2D array. It can be indexed like crossword[x + y * crossword.width()], which isn't pretty, so you might want to use a library/self-written wrapper with API like crossword(x, y) which performs that xy-to-i-index conversion under the hood.
Maybe something like this:
class Crossword {
std::vector<Block> raw;
size_t length{}; // can't name it "width" because there's a "width()" member function below
public:
Crossword() {}
Crossword(size_t x, size_t y): raw(x * y), length{x} {}
Crossword(Crossword&& other) noexcept { *this = std::move(other); }
Crossword& operator=(Crossword&& other) noexcept {
std::swap(raw, other.raw);
std::swap(length, other.length);
return *this;
}
auto size() const { return raw.size(); }
auto width() const { return length; }
auto height() const { return size() / length; }
auto& operator()(size_t x, size_t y) const { return raw[x + y * length]; }
auto& operator()(size_t x, size_t y) { return raw[x + y * length]; }
};
I can color cells by specifying a Row format or a column format but that applies the coloring/formatting to the entire row or column. I'd like to set each cell's color based on some criteria. When I include the ... coloring tags in the setCDKMatrixCell() call those characters get set to the cell text not used to format the cell.
Is there another way? Or any ideas on how to modify the drawCDKMatrixCell to do this?
void drawCDKMatrixCell() {
...
if (matrix->dominant == ROW) {
highlight = matrix->rowtitle[absolute_row][0] & A_ATTRIBUTES;
}
else if (matrix->dominant == COL) {
highlight = matrix->coltitle[col][0] & A_ATTRIBUTES;
}
/* Draw in the cell info. */
for (x = 1; x <= matrix->colwidths[col]; x++) {
chtype ch = (((x <= infolen) && !isHiddenDisplayType(disptype))
? (CharOf(MATRIX_INFO(matrix, vrow, vcol)[x - 1]) | highlight)
: matrix->filler);
(void) mvwaddch(cell, 1, x, ch | highlight);
}
...
Cells are drawn using a private function
static void drawCDKMatrixCell (CDKMATRIX *matrix,
int row,
int col,
int vrow,
int vcol,
chtype attr,
boolean Box)
which simply uses mvwaddch for each character in the cell. The information for that is set using
int setCDKMatrixCell (CDKMATRIX *matrix, int row, int col, const char *value)
and stored in the matrix as char (not chtype). If the drawCDKMatrixCell function were modified, say, to use char2Chtype to construct the data, then you could do what you're asking.
My problem is that I am starting a Thread to read data from my EyeTracker. I start it using the following functions:
BlinkMode::BlinkMode()
{
bBlink = false;
threadStopped = true;
recordeddata = nullptr;
gT = GazeTracker::getGazeTracker();
canRecord = false;
numCameras = gT->getNumCameras();
if( numCameras >0){
canRecord = true;
}
filename = "blinkmode.txt";
counter = 0;
calipointno = 0 ;
}
void BlinkMode::startRecording()
{
if (!bBlink)
{
// Turn thread loop signal on
bBlink = true;
bBlinkSuccess = false;
bExcessData = false;
blinkThread = std::thread(createBlinkThread, this);
}
}
void BlinkMode::createBlinkThread(void* instance)
{
BlinkMode* pThis = (BlinkMode*) instance;
pThis->bBlink;
if(pThis->canRecord){
pThis->threadStopped = false;
pThis->BlinkModeThread();
pThis->threadStopped = true;
}
}
void BlinkMode::BlinkModeThread ()
{
BlinkMode* pThis = (BlinkMode*) this;
pThis->bBlink;
Matrix mProvData = Matrix (DR_DATAANALYSIS, GT_EYEDATALENGTH);
Matrix aSourceMatrix = Matrix (DR_MAXRECORDEDDATA, GT_EYEDATALENGTH);
recordeddata = new float[DR_MAXRECORDEDDATA][GT_EYEDATALENGTH];
while(bBlink){
if(counter<DR_MAXRECORDEDDATA){
gT->getCurrentData(recordeddata[counter],ALLDATA);
[ETC ...]
The thing is that my boolean bBlink, which is defined as a private volatile boolean in the header file of my class:
class BlinkMode
{
private:
// Monitor thread control signal.
volatile bool bBlink;}
becomes false right after the creation of the Matrix instances, (Matrix is another class of my code). And hence, the while loop is NEVER entered. However, if I comment the Matrix lines, it works! I can even execute the new float "recordeddata", but not the Matrices.
Does that mean that I cannot call another classes while I am inside a Thread or something? Sorry I am pretty new with C++ and I am lost.
Any help please??
Thanks in advance!
The Matrix class is just to initialize Matrices in different ways and do operations with them, kind of like this:
class Matrix
{
public:
// Default constructor
Matrix();
// Default destructor
~Matrix();
// Initialise matrix of rows x cols.
Matrix(const int rows, const int cols);
// Convert a two dimensional array (rows x cols) of integers to a matrix.
Matrix(const int* const* num, const int rows, const int cols);
// Convert a two dimensional array (rows x cols) of floats to a matrix.
Matrix(const float* const* num, const int rows, const int cols);
// Copies the required row into the array.
void getRow(const int row, double[]) const;
// Copies the required row into the matrix.
void getRow(const int row, Matrix&) const;
// Sets the values of a row to the values of the array.
void setRow(const int row, const int[]);
enter code here
So I am just creating 2 objects there, and that is when the boolean automatically changes to false!!
I just created the pThis pointer you mentioned to be able to access the value of the boolean and check when it changes, but it is not relevant for the code... I can erase it and nothing changes...
What is the correct way to implement an efficient 2d vector? I need to store a set of Item objects in a 2d collection, that is fast to iterate (most important) and also fast to find elements.
I have a 2d vector of pointers declared as follows:
std::vector<std::vector<Item*>> * items;
In the constructor, I instantiate it as follows:
items = new std::vector<std::vector<Item*>>();
items->resize(10, std::vector<Item*>(10, new Item()));
I how do I (correctly) implement methods for accessing items? Eg:
items[3][4] = new Item();
AddItem(Item *& item, int x, int y)
{
items[x][y] = item;
}
My reasoning for using pointers is for better performance, so that I can pass things around by reference.
If there is a better way to go about this, please explain, however I would still be interested in how to correctly use the vector.
Edit: For clarification, this is part of a class that is for inventory management in a simple game. The set 10x10 vector represents the inventory grid which is a set size. The Item class contains the item type, a pointer to an image in the resource manager, stack size etc.
My pointer usage was in an attempt to improve performance, since this class is iterated and used to render the whole inventory every frame, using the image pointer.
It seems that you know the size of the matrix beforehand, and that this matrix is squared. Though vector<> is fine, you can also use native vectors in that case.
Item **m = new Item*[ n * n ];
If you want to access position r,c, then you only have to multiply r by n, and then add c:
pos = ( r * n ) + c;
So, if you want to access position 1, 2, and n = 5, then:
pos = ( 1 * 5 ) + 2;
Item * it = m[ pos ];
Also, instead of using plain pointers, you can use smart pointers, such as auto_ptr (obsolete) and unique_ptr, which are more or less similar: once they are destroyed, they destroy the object they are pointing to.
auto_ptr<Item> m = new auto_ptr<Item>[ n * n ];
The only drawback is that now you need to call get() in order to obtain the pointer.
pos = ( 1 * 5 ) + 2;
Item * it = m[ pos ].get();
Here you have a class that summarizes all of this:
class ItemsSquaredMatrix {
public:
ItemsSquaredMatrix(unsigned int i): size( i )
{ m = new std::auto_ptr<Item>[ size * size ]; }
~ItemsSquaredMatrix()
{ delete[] m; }
Item * get(unsigned int row, unsigned int col)
{ return m[ translate( row, col ) ].get(); }
const Item * get(unsigned int row, unsigned int col) const
{ return m[ translate( row, col ) ].get(); }
void set(unsigned int row, unsigned int col, Item * it)
{ m[ translate( row, col ) ].reset( it ); }
unsigned int translate(unsigned int row, unsigned int col) const
{ return ( ( row * size ) + col ); }
private:
unsigned int size;
std::auto_ptr<Item> * m;
};
Now you only have to create the class Item. But if you created a specific class, then you'd have to duplicate ItemsSquaredMatrix for each new piece of data. In C++ there is a specific solution for this, involving the transformation of the class above in a template (hint: vector<> is a template). Since you are a beginner, it will be simpler to have Item as an abstract class:
class Item {
public:
// more things...
virtual std::string toString() const = 0;
};
And derive all the data classes you will create from them. Remember to do a cast, though...
As you can see, there are a lot of open questions, and more questions will raise as you keep unveliling things. Enjoy!
Hope this helps.
For numerical work, you want to store your data as locally as possible in memory. For example, if you were making an n by m matrix, you might be tempted to define it as
vector<vector<double>> mat(n, vector<double>(m));
There are severe disadvantages to this approach. Firstly, it will not work with any proper matrix libraries, such as BLAS and LAPACK, which expect the data to be contiguous in memory. Secondly, even if it did, it would lead to lots of random access and pointer indirection in memory, which would kill the performance of your matrix operations. Instead, you need a contiguous block of memory n*m items in size.
vector<double> mat(n*m);
But you wouldn't really want to use a vector for this, as you would then need to translate from 1d to 2d indices manually. There are some libraries that do this for you in C++. One of them is Blitz++, but that seems to not be much developed now. Other alternatives are Armadillo and Eigen. See this previous answer for more details.
Using Eigen, for example, the matrix declaration would look like this:
MatrixXd mat(n,m);
and you would be able to access elements as mat[i][j], and multiply matrices as mat1*mat2, and so on.
The first question is why the pointers. There's almost never any reason
to have a pointer to an std::vector, and it's not that often that
you'd have a vector of pointers. You're definition should probably be:
std::vector<std::vector<Item> > items;
, or at the very least (supposing that e.g. Item is the base of a
polymorphic hierarchy):
std::vector<std::vector<Item*> > items;
As for your problem, the best solution is to wrap your data in some sort
of a Vector2D class, which contains an std::vector<Item> as member,
and does the index calculations to access the desired element:
class Vector2D
{
int my_rows;
int my_columns;
std::vector<Item> my_data;
public:
Vector2D( int rows, int columns )
: my_rows( rows )
, my_columns( columns )
{
}
Item& get( int row, int column )
{
assert( row >= 0 && row < my_rows
&& column >= 0 && column < my_columns );
return my_data[row * my_columns + column];
}
class RowProxy
{
Vector2D* my_owner;
int my_row;
public;
RowProxy(Vector2D& owner, int row)
: my_owner( &owner )
, my_row( row )
{
}
Item& operator[]( int column ) const
{
return my_owner->get( my_row, column );
}
};
RowProxy operator[]( int row )
{
return RowProxy( this, row );
}
// OR...
Item& operator()( int row, int column )
{
return get( row, column );
}
};
If you forgo bounds checking (but I wouldn't recommend it), the
RowProxy can be a simple Item*.
And of course, you should duplicate the above for const.