#include <map>
#include <string>
#include <vector>
using namespace std;
template <class Tk>
class head
{
private:
map<Tk, unsigned int> m_head;
public:
//optionally use another map to define the column indeces
head(map<Tk, unsigned int>& column_defs)
: m_head(column_defs){ }
//define the columns based on the data in this vector
head(const vector<Tk>* pvct_columns = NULL)
{
if (pvct_columns != NULL){
for (unsigned int i = 0; i < pvct_columns->size(); ++i)
{
m_head[ (*pvct_columns)[i] ] = i;
}
}
}
bool exists(const Tk& col){
return m_head.find(col) != m_head.end();
}
/**
* Get the value if it exists,
* Useful if we do not know the column headers associated with this
* associative array
*
* @param i the index
* @return pointer to the Tk column it found, NULL if does not exist
*/
const Tk* value_to_key(unsigned int i)
{
bool found = false;
map<Tk, unsigned int>::iterator it = m_head.begin(); // internalMap is std::map
while(it != m_head.end())
{
found = (it->second == i);
if(found)
return &it->first;
++it;
}
return NULL;
}
void undefine(const Tk& col){
m_head.erase(m_head.find(col));
}
unsigned int count(){ return m_head.size(); }
inline unsigned int size(){ return m_head.size(); }
//return the column index
unsigned int& column(const Tk& col){ return m_head[col]; }
unsigned int& operator[](const Tk& col){ return m_head[col]; }
const Tk& operator[](unsigned int i)
{
const Tk* pstr = value_to_key(i);
if (pstr == NULL){ throw 1; }
return (*pstr);
}
};
template <class Tk, class Tv>
class row
{
head<Tk>* m_phead;
vector< vector<Tv> >* m_pvdata; ///pointer to the full data array
public:
unsigned int m_row;
public:
explicit row(head<Tk>* phead, vector< vector<Tv> >* pvdata, unsigned int row_index = 0)
: m_phead(phead), m_pvdata(pvdata), m_row(row_index)
{ }
//this is the second bracket[row][key]
Tv& operator[](const Tk& key) const
{
return (*this)[ m_phead->column(key) ];
}
//this is the second bracket[row][index]
Tv& operator[](unsigned int index) const
{
return (*m_pvdata)[m_row][index];
}
vector <Tv>& operator=(std::vector<Tv>& rhs)
{
if (rhs.size() > m_phead->size())
{
throw Tk( "vector has more entries than columns" );
}
else
{
(*m_pvdata)[m_row] = rhs;
}
return (*m_pvdata)[m_row];
}
vector <Tv>& operator=(const std::vector<Tv>& rhs) const
{
if (rhs.size() > m_phead->size())
{
throw Tk( "vector has more entries than columns" );
}
else
{
(*m_pvdata)[m_row] = rhs;
}
return (*m_pvdata)[m_row];
}
};
/**
* This contains the core data, the vector of all the rows,
* and the column header information
*/
template <class Tk, class Tv>
class assoc_array
{
private:
vector< vector<Tv> > m_data;
head<Tk> m_head;
row<Tk,Tv> m_temp_row;
public:
assoc_array(unsigned int num_rows = 0, const vector<Tk>& vct_columns = vector<Tk>(1), int fill_value = 0)
: m_data(num_rows, vector<Tv>(vct_columns.size(), fill_value)), m_head(&vct_columns), m_temp_row(&m_head, &m_data)
{
}
const Tk& get_column(unsigned int i){ return m_head[i]; }
const int numCols(){ return m_head.size(); }
void define_column(const Tk& col, unsigned int index){
m_head[col] = index;
}
void undefine_column(const Tk& col){
m_head.undefine(col);
}
//access either using a column name or column index -- optimized (not 2 different entries like PHP)
Tv& data(unsigned int row, unsigned int col){ return m_data[row][col]; }
Tv& data(unsigned int row, const Tk& scol){
Tv col = m_head.column(scol);
return m_data[row][col];
}
const int numRows(){ return m_data.size(); }
inline const int count(){ return numRows(); }
const row<Tk, Tv>& operator[](unsigned int row)
{
//set the temporary row index so the next time
m_temp_row.m_row = row;
return m_temp_row;
}
};
#include <iostream>
char* rword (char *word)
{
int len = rand () % 6 + 1;
word [len] = 0;
while (len) word [--len] = 'a' + rand () % 26;
return word;
}
template<class Tk, class Tv>
void print(assoc_array<Tk, Tv>& ary)
{
for (int j = 0; j < ary.numCols(); j++)
{
cout << ary.get_column(j) << "\t";
}
cout << endl;
for (int j = 0; j < 40; ++j){ cout << "-"; }
cout << endl;
for (int i = 0; i < ary.numRows(); ++i)
{
for (int j = 0; j < ary.numCols(); j++)
{
cout << ary[i][j] << "\t";
}
cout << endl;
}
}
int main()
{
assoc_array<string, int> ary;
vector<string> cols(5);
cols[0] = "text";
cols[1] = "book";
cols[2] = "chapter";
cols[3] = "verse";
cols[4] = "rowid";
assoc_array<string, int> big_ary(5, cols, 8888);
//set some data
big_ary.data(2, "rowid") = 2;
big_ary.data(2, "chapter") = 15;
for (int i = 0; i < big_ary.numRows(); ++i)
{
std::vector<int> vct(big_ary.numCols(), i);
big_ary[i] = vct;
}
print(big_ary);
system("PAUSE");
}
/** output **
text book chapter verse rowid
----------------------------------------
0 0 0 0 0
1 1 1 1 1
2 2 2 2 2
3 3 3 3 3
4 4 4 4 4
**/
Refactorings
No refactoring yet !
raul
March 12, 2010, March 12, 2010 13:27, permalink
Use std::map for this:
#include <map>
#include <string>
#include <iostream>
void foo()
{
std::map<string,int> myArray;
myArray["slot_0"] = 1;
myArray["slot_1"] = 2;
myArray["slot_2"] = 3;
cout << myArray["slot_0"] << " " << myArray["slot_1"] << " " << myArray["slot_2"];
}
looking for stability and speed, is this the right route to take?
the idea is to be able to do myary[row]["column-heading"] = 77;