iphreeqc/CSelectedOutput.cpp
2024-12-02 15:28:05 +13:00

402 lines
8.5 KiB
C++

// SelectedOutput.cpp: implementation of the CSelectedOutput class.
//
//////////////////////////////////////////////////////////////////////
#if defined(WIN32)
#include <windows.h> // OutputDebugString
#endif
#if defined(_DEBUG)
#include <sstream> // std::ostringstream
#endif
#include <stdarg.h>
#include <stdio.h>
#include <string.h> // 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<int> &types, // each column for each row types, including headings
std::vector<long> &longs, // in order by occurrence
std::vector<double> &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<int> &types, // each column for each row types, including headings
std::vector<long> &longs, // in order by occurrence
std::vector<double> &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<std::string> 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;
}
}
}
}