// SelectedOutput.cpp: implementation of the CSelectedOutput class. // ////////////////////////////////////////////////////////////////////// #if defined(WIN32) #include // OutputDebugString #endif #if defined(_DEBUG) #include // std::ostringstream #endif #include #include #include // strlen #include "Debug.h" // ASSERT #if defined(R_SO) #include "CSelectedOutputhxx.h" // CSelectedOutput #else #include "CSelectedOutput.hxx" // CSelectedOutput #endif const float INACTIVE_CELL_VALUE = 1.0e30f; const size_t RESERVE_ROWS = 80; const size_t RESERVE_COLS = 80; CSelectedOutput::CSelectedOutput() : m_nRowCount(0) { this->m_arrayVar.reserve(RESERVE_COLS); } CSelectedOutput::~CSelectedOutput() { } void CSelectedOutput::Clear(void) { this->m_nRowCount = 0; this->m_vecVarHeadings.clear(); this->m_arrayVar.clear(); this->m_mapHeadingToCol.clear(); } size_t CSelectedOutput::GetRowCount(void)const { if (this->GetColCount()) { return this->m_nRowCount + 1; // rows + heading } else { return 0; } } size_t CSelectedOutput::GetColCount(void)const { return this->m_vecVarHeadings.size(); } CVar CSelectedOutput::Get(int nRow, int nCol)const { CVar v; this->Get(nRow, nCol, &v); return v; } VRESULT CSelectedOutput::Get(int nRow, int nCol, VAR* pVAR)const { if (::VarClear(pVAR) == VR_BADVARTYPE) { return VR_BADVARTYPE; } if ((size_t)nRow >= this->GetRowCount() || nRow < 0) { pVAR->type = TT_ERROR; pVAR->vresult = VR_INVALIDROW; return pVAR->vresult; } if ((size_t)nCol >= this->GetColCount() || nCol < 0) { pVAR->type = TT_ERROR; pVAR->vresult = VR_INVALIDCOL; return pVAR->vresult; } if (nRow) { ASSERT((size_t)nRow <= this->m_arrayVar[nCol].size()); return ::VarCopy(pVAR, &(this->m_arrayVar[nCol])[nRow - 1]); } else { return ::VarCopy(pVAR, &(this->m_vecVarHeadings[nCol])); } } int CSelectedOutput::EndRow(void) { if (size_t ncols = this->GetColCount()) { ++this->m_nRowCount; // make sure array is full for (size_t col = 0; col < ncols; ++col) { size_t nrows = this->m_arrayVar[col].size(); if (nrows < this->m_nRowCount) { // fill w/ empty this->m_arrayVar[col].resize(this->m_nRowCount); } #if defined(_DEBUG) else if (nrows > this->m_nRowCount) { ASSERT(false); } #endif } } return 0; } int CSelectedOutput::PushBack(const char* key, const CVar& var) { try { // check if key is new std::map< std::string, size_t >::iterator find; find = this->m_mapHeadingToCol.find(std::string(key)); if (find == this->m_mapHeadingToCol.end()) { // new key(column) // this->m_mapHeadingToCol.insert(std::map< std::string, size_t >::value_type(std::string(key), this->m_mapHeadingToCol.size()) ); // add heading // this->m_vecVarHeadings.push_back(CVar(key)); // add new vector(col) // this->m_arrayVar.resize(this->m_arrayVar.size() + 1); this->m_arrayVar.back().reserve(RESERVE_ROWS); // add empty rows if nec if (this->m_nRowCount) this->m_arrayVar.back().resize(this->m_nRowCount); this->m_arrayVar.back().push_back(var); } else { if (this->m_arrayVar[find->second].size() == this->m_nRowCount) { this->m_arrayVar[find->second].push_back(var); } else { ASSERT(this->m_arrayVar[find->second].size() == this->m_nRowCount + 1); this->m_arrayVar[find->second].at(this->m_nRowCount) = var; } } return 0; } catch(...) { ASSERT(false); throw; } return 1; // error } int CSelectedOutput::PushBackDouble(const char* key, double value) { CVar v(value); return this->PushBack(key, v); } int CSelectedOutput::PushBackLong(const char* key, long value) { CVar v(value); return this->PushBack(key, v); } int CSelectedOutput::PushBackString(const char* key, const char* value) { CVar v(value); return this->PushBack(key, v); } int CSelectedOutput::PushBackEmpty(const char* key) { CVar v; return this->PushBack(key, v); } #if defined(_DEBUG) void CSelectedOutput::Dump(const char* heading) { ::OutputDebugStringA(heading); std::ostringstream oss; oss << *this; std::istringstream iss(oss.str()); std::string line; while (std::getline(iss, line)) { ::OutputDebugStringA(line.c_str()); ::OutputDebugStringA("\n"); } } void CSelectedOutput::AssertValid(void)const { if (size_t cols = this->GetColCount()) { size_t rows = this->m_arrayVar[0].size(); for (size_t col = 0; col < cols; ++col) { ASSERT(rows == this->m_arrayVar[col].size()); } } } #endif std::ostream& operator<< (std::ostream &os, const CSelectedOutput &a) { os << "CSelectedOutput(rows=" << a.GetRowCount() << ", cols=" << a.GetColCount() << ")\n"; CVar v; for (size_t r = 0; r < a.GetRowCount(); ++r) { for (size_t c = 0; c < a.GetColCount(); ++c) { a.Get((int)r, (int)c, &v); os << v << ", "; ::VarClear(&v); } os << "\n"; } os << "\n"; return os; } void CSelectedOutput::Serialize( int row_number, std::vector &types, // each column for each row types, including headings std::vector &longs, // in order by occurrence std::vector &doubles, // in order by occurrence std::string &strings) { types.clear(); longs.clear(); doubles.clear(); strings.clear(); // size_t nrows = this->m_nRowCount; size_t ncols = this->m_vecVarHeadings.size(); longs.push_back((long) 1); longs.push_back((long) ncols); // put headings for (size_t i = 0; i < ncols; i++) { ASSERT(this->m_vecVarHeadings[i].type == TT_STRING); longs.push_back((long) strlen(this->m_vecVarHeadings[i].sVal)); strings.append(this->m_vecVarHeadings[i].sVal); } // go through rows by column for (size_t j = 0; j < ncols; j++) { for (size_t i = row_number; i < (size_t)(row_number + 1); i++) { types.push_back(m_arrayVar[j][i].type); switch(m_arrayVar[j][i].type) { case TT_EMPTY: break; case TT_ERROR: longs.push_back(m_arrayVar[j][i].vresult); break; case TT_LONG: longs.push_back(m_arrayVar[j][i].lVal); break; case TT_DOUBLE: doubles.push_back(m_arrayVar[j][i].dVal); break; case TT_STRING: longs.push_back((long) strlen(m_arrayVar[j][i].sVal)); strings.append(m_arrayVar[j][i].sVal); break; } } } } void CSelectedOutput::DeSerialize( std::vector &types, // each column for each row types, including headings std::vector &longs, // in order by occurrence std::vector &doubles, // in order by occurrence std::string &strings) { size_t i_types = 0, i_longs = 0, i_doubles = 0; size_t strings_start = 0; size_t nrows = longs[i_longs++]; size_t ncols = longs[i_longs++]; // put headings std::vector headings; for (size_t i = 0; i < ncols; i++) { size_t l = (size_t) longs[i_longs++]; headings.push_back(strings.substr(strings_start, l)); strings_start += l; } // go through rows by column for (size_t j = 0; j < ncols; j++) { for (size_t i = 0; i < nrows; i++) { switch((VAR_TYPE) types[i_types++]) { case TT_EMPTY: { CVar v; v.Clear(); this->PushBack(headings[j].c_str(), v); } break; case TT_ERROR: { CVar v; v.Clear(); v.type = TT_ERROR; v.vresult = (VRESULT) longs[i_longs++]; this->PushBack(headings[j].c_str(), v); } break; case TT_LONG: PushBackLong(headings[j].c_str(), longs[i_longs++]); break; case TT_DOUBLE: PushBackDouble(headings[j].c_str(), doubles[i_doubles++]); break; case TT_STRING: { size_t l = (size_t) longs[i_longs++]; PushBackString(headings[j].c_str(), strings.substr(strings_start, l).c_str()); strings_start += l; } break; } } } this->EndRow(); } void CSelectedOutput::Doublize( int &nrow, int &ncol, std::vector < double > &doubles) { nrow = (int) this->m_nRowCount; ncol = (int) this->m_vecVarHeadings.size(); doubles.clear(); // go through column dominant order (Fortran) for (size_t j = 0; j < (size_t)ncol; j++) { for (size_t i = 0; i < (size_t)nrow; i++) { switch(m_arrayVar[j][i].type) { case TT_EMPTY: doubles.push_back((double) INACTIVE_CELL_VALUE); break; case TT_ERROR: doubles.push_back((double) INACTIVE_CELL_VALUE); break; case TT_LONG: doubles.push_back((double) m_arrayVar[j][i].lVal); break; case TT_DOUBLE: doubles.push_back(m_arrayVar[j][i].dVal); break; case TT_STRING: doubles.push_back((double) INACTIVE_CELL_VALUE); break; default: doubles.push_back((double) INACTIVE_CELL_VALUE); break; } } } }