31static const bool sPlatformHasCR =
true;
33static const bool sPlatformHasCR =
false;
52 std::numeric_limits<long double>::signaling_NaN(),
86 virtual const char *what()
const throw()
override {
return "unsupported conversion datatype"; }
115 if (
typeid(T) ==
typeid(
int) ||
typeid(T) ==
typeid(
long) ||
116 typeid(T) ==
typeid(
long long) ||
typeid(T) ==
typeid(
unsigned) ||
117 typeid(T) ==
typeid(
unsigned long) ||
118 typeid(T) ==
typeid(
unsigned long long) ||
typeid(T) ==
typeid(
float) ||
119 typeid(T) ==
typeid(
double) ||
typeid(T) ==
typeid(
long double) ||
120 typeid(T) ==
typeid(
char))
122 std::ostringstream
out;
141 if (
typeid(T) ==
typeid(
int))
143 pVal =
static_cast<T
>(std::stoi(
pStr));
146 else if (
typeid(T) ==
typeid(long))
148 pVal =
static_cast<T
>(std::stol(
pStr));
151 else if (
typeid(T) ==
typeid(
long long))
153 pVal =
static_cast<T
>(std::stoll(
pStr));
156 else if (
typeid(T) ==
typeid(unsigned))
158 pVal =
static_cast<T
>(std::stoul(
pStr));
161 else if (
typeid(T) ==
typeid(
unsigned long))
163 pVal =
static_cast<T
>(std::stoul(
pStr));
166 else if (
typeid(T) ==
typeid(
unsigned long long))
168 pVal =
static_cast<T
>(std::stoull(
pStr));
174 if (!mConverterParams.mHasDefaultConverter)
180 pVal =
static_cast<T
>(mConverterParams.mDefaultInteger);
187 if (
typeid(T) ==
typeid(float))
189 pVal =
static_cast<T
>(std::stof(
pStr));
192 else if (
typeid(T) ==
typeid(double))
194 pVal =
static_cast<T
>(std::stod(
pStr));
197 else if (
typeid(T) ==
typeid(
long double))
199 pVal =
static_cast<T
>(std::stold(
pStr));
205 if (!mConverterParams.mHasDefaultConverter)
211 pVal =
static_cast<T
>(mConverterParams.mDefaultFloat);
216 if (
typeid(T) ==
typeid(char))
238 std::string &
pStr)
const
250 std::string &
pVal)
const
256using ConvFunc = std::function<void(
const std::string &
pStr, T &
pVal)>;
307 const bool pHasCR = sPlatformHasCR,
502 mColumnNames.clear();
519 if (mColumnNames.find(
pColumnName) != mColumnNames.end())
532 template <
typename T>
536 std::vector<T> column;
544 column.push_back(val);
556 template <
typename T>
560 std::vector<T> column;
567 column.push_back(val);
578 template <
typename T>
584 throw std::out_of_range(
"column not found: " +
pColumnName);
595 template <
typename T>
601 throw std::out_of_range(
"column not found: " +
pColumnName);
611 template <
typename T>
618 std::vector<std::string> row;
619 row.resize(GetDataColumnCount());
620 mData.push_back(row);
623 if ((
columnIdx + 1) > GetDataColumnCount())
635 converter.ToStr(*
itRow, str);
648 template <
typename T>
654 throw std::out_of_range(
"column not found: " +
pColumnName);
681 throw std::out_of_range(
"column not found: " +
pColumnName);
693 template <
typename T>
695 const std::vector<T> &
pColumn = std::vector<T>(),
700 std::vector<std::string> column;
703 column.resize(GetDataRowCount());
712 converter.ToStr(*
itRow, str);
719 while (column.size() > GetDataRowCount())
721 std::vector<std::string> row;
722 const size_t columnCount =
724 GetDataColumnCount());
725 row.resize(columnCount);
726 mData.push_back(row);
731 const size_t rowIdx = std::distance(mData.begin(),
itRow);
748 static_cast<ssize_t>((mData.size() > 0) ? mData.at(0).size() : 0) -
750 return (count >= 0) ? count : 0;
762 if (mRowNames.find(
pRowName) != mRowNames.end())
775 template <
typename T>
787 converter.ToVal(*
itCol, val);
800 template <
typename T>
824 template <
typename T>
830 throw std::out_of_range(
"row not found: " +
pRowName);
841 template <
typename T>
847 throw std::out_of_range(
"row not found: " +
pRowName);
857 template <
typename T>
862 while ((
rowIdx + 1) > GetDataRowCount())
864 std::vector<std::string> row;
865 row.resize(GetDataColumnCount());
866 mData.push_back(row);
869 if (
pRow.size() > GetDataColumnCount())
881 converter.ToStr(*
itCol, str);
892 template <
typename T>
898 throw std::out_of_range(
"row not found: " +
pRowName);
910 mData.erase(mData.begin() +
rowIdx);
922 throw std::out_of_range(
"row not found: " +
pRowName);
934 template <
typename T>
936 const std::string &
pRowName = std::string())
940 std::vector<std::string> row;
943 row.resize(GetDataColumnCount());
952 converter.ToStr(*
itCol, str);
953 row.at(std::distance(
pRow.begin(),
itCol) +
958 while (
rowIdx > GetDataRowCount())
960 std::vector<std::string>
tempRow;
961 tempRow.resize(GetDataColumnCount());
965 mData.insert(mData.begin() +
rowIdx, row);
981 return (count >= 0) ? count : 0;
990 template <
typename T>
1009 template <
typename T>
1026 template <
typename T>
1032 throw std::out_of_range(
"column not found: " +
pColumnName);
1038 throw std::out_of_range(
"row not found: " +
pRowName);
1051 template <
typename T>
1058 throw std::out_of_range(
"column not found: " +
pColumnName);
1064 throw std::out_of_range(
"row not found: " +
pRowName);
1076 template <
typename T>
1082 throw std::out_of_range(
"column not found: " +
pColumnName);
1095 template <
typename T>
1102 throw std::out_of_range(
"column not found: " +
pColumnName);
1114 template <
typename T>
1120 throw std::out_of_range(
"row not found: " +
pRowName);
1133 template <
typename T>
1140 throw std::out_of_range(
"row not found: " +
pRowName);
1152 template <
typename T>
1158 while ((
rowIdx + 1) > GetDataRowCount())
1160 std::vector<std::string> row;
1161 row.resize(GetDataColumnCount());
1162 mData.push_back(row);
1165 if ((
columnIdx + 1) > GetDataColumnCount())
1175 converter.ToStr(
pCell, str);
1185 template <
typename T>
1192 throw std::out_of_range(
"column not found: " +
pColumnName);
1198 throw std::out_of_range(
"row not found: " +
pRowName);
1214 throw std::out_of_range(
"column name row index < 0: " +
1232 throw std::out_of_range(
"column name row index < 0: " +
1238 if (
rowIdx >=
static_cast<int>(mData.size()))
1240 mData.resize(
rowIdx + 1);
1242 auto &row = mData[
rowIdx];
1243 if (
columnIdx >=
static_cast<int>(row.size()))
1259 return std::vector<std::string>(
1265 return std::vector<std::string>();
1278 throw std::out_of_range(
"row name column index < 0: " +
1296 throw std::out_of_range(
"row name column index < 0: " +
1301 if (
rowIdx >=
static_cast<int>(mData.size()))
1303 mData.resize(
rowIdx + 1);
1305 auto &row = mData[
rowIdx];
1306 if (mLabelParams.
mRowNameIdx >=
static_cast<int>(row.size()))
1337 std::ifstream stream;
1338 stream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
1339 stream.open(mPath, std::ios::binary);
1343 void ReadCsv(std::istream &
pStream)
1346 pStream.seekg(0, std::ios::end);
1347 std::streamsize length =
pStream.tellg();
1348 pStream.seekg(0, std::ios::beg);
1351 std::vector<char>
bom2b(2,
'\0');
1355 pStream.seekg(0, std::ios::beg);
1358 static const std::vector<char>
bomU16le = {
'\xff',
'\xfe' };
1359 static const std::vector<char>
bomU16be = {
'\xfe',
'\xff' };
1366 wstream.exceptions(std::wifstream::failbit | std::wifstream::badbit);
1367 wstream.open(mPath, std::ios::binary);
1372 new std::codecvt_utf16<
wchar_t, 0x10ffff,
1373 static_cast<std::codecvt_mode
>(
1374 std::consume_header |
1375 std::little_endian)>));
1381 new std::codecvt_utf16<wchar_t, 0x10ffff, std::consume_header>));
1383 std::wstringstream
wss;
1386 std::stringstream
ss(utf8);
1387 ParseCsv(
ss, utf8.size());
1395 std::vector<char>
bom3b(3,
'\0');
1397 static const std::vector<char>
bomU8 = {
'\xef',
'\xbb',
'\xbf' };
1401 pStream.seekg(0, std::ios::beg);
1416 const std::streamsize
bufLength = 64 * 1024;
1418 std::vector<std::string> row;
1431 if (buffer[i] ==
'"')
1433 if (cell.empty() || cell[0] ==
'"')
1439 else if (buffer[i] == mSeparatorParams.
mSeparator)
1443 row.push_back(Unquote(Trim(cell)));
1451 else if (buffer[i] ==
'\r')
1462 else if (buffer[i] ==
'\n')
1478 row.push_back(Unquote(Trim(cell)));
1481 !row.at(0).empty() &&
1488 mData.push_back(row);
1506 if (!cell.empty() || !row.empty())
1508 row.push_back(Unquote(Trim(cell)));
1510 mData.push_back(row);
1522 for (
auto &
columnName : mData[mLabelParams.mColumnNameIdx])
1543 void WriteCsv()
const
1548 std::stringstream
ss;
1550 std::string utf8 =
ss.str();
1554 wstream.exceptions(std::wofstream::failbit | std::wofstream::badbit);
1555 wstream.open(mPath, std::ios::binary | std::ios::trunc);
1561 new std::codecvt_utf16<
wchar_t, 0x10ffff,
1562 static_cast<std::codecvt_mode
>(
1563 std::little_endian)>));
1568 new std::codecvt_utf16<wchar_t, 0x10ffff>));
1577 std::ofstream stream;
1578 stream.exceptions(std::ofstream::failbit | std::ofstream::badbit);
1579 stream.open(mPath, std::ios::binary | std::ios::trunc);
1584 void WriteCsv(std::ostream &
pStream)
const
1586 for (
auto itr = mData.begin();
itr != mData.end(); ++
itr)
1591 ((
itc->find(mSeparatorParams.
mSeparator) != std::string::npos) ||
1592 (
itc->find(
' ') != std::string::npos)))
1595 std::string str = *
itc;
1596 ReplaceString(str,
"\"",
"\"\"");
1598 pStream <<
"\"" << str <<
"\"";
1605 if (std::distance(
itc,
itr->end()) > 1)
1614 size_t GetDataRowCount()
const {
return mData.size(); }
1616 size_t GetDataColumnCount()
const
1618 return (mData.size() > 0) ? mData.at(0).size() : 0;
1621 std::string Trim(
const std::string &
pStr)
1623 if (mSeparatorParams.
mTrim)
1625 std::string str =
pStr;
1628 str.erase(str.begin(), std::find_if(str.begin(), str.end(),
1629 [](
int ch) { return !isspace(ch); }));
1632 str.erase(std::find_if(str.rbegin(), str.rend(),
1633 [](
int ch) { return !isspace(ch); })
1645 std::string Unquote(
const std::string &
pStr)
1648 (
pStr.back() ==
'"'))
1651 std::string str =
pStr.substr(1,
pStr.size() - 2);
1654 ReplaceString(str,
"\"\"",
"\"");
1665#if defined(_MSC_VER)
1666#pragma warning(disable : 4996)
1670 size_t len = std::wcstombs(
nullptr,
pWStr.c_str(), 0) + 1;
1673 std::string str(
cstr);
1687#if defined(_MSC_VER)
1688#pragma warning(default : 4996)
1692 static void ReplaceString(std::string &
pStr,
const std::string &
pSearch,
1697 while ((pos =
pStr.find(
pSearch, pos)) != std::string::npos)
1706 LabelParams mLabelParams;
1707 SeparatorParams mSeparatorParams;
1708 ConverterParams mConverterParams;
1709 LineReaderParams mLineReaderParams;
1710 std::vector<std::vector<std::string>> mData;
1711 std::map<std::string, size_t> mColumnNames;
1712 std::map<std::string, size_t> mRowNames;
Class providing conversion to/from numerical datatypes and strings.
void ToStr(const T &pVal, std::string &pStr) const
Converts numerical value to string representation.
void ToVal(const std::string &pStr, T &pVal) const
Converts string holding a numerical value to numerical datatype representation.
Converter(const ConverterParams &pConverterParams)
Constructor.
Class representing a CSV document.
std::vector< T > GetRow(const std::string &pRowName, ConvFunc< T > pToVal) const
Get row by name.
std::string GetRowName(const ssize_t pRowIdx)
Get row name.
ssize_t GetColumnIdx(const std::string &pColumnName) const
Get column index by name.
void SetRow(const std::string &pRowName, const std::vector< T > &pRow)
Set row by name.
std::vector< T > GetRow(const size_t pRowIdx, ConvFunc< T > pToVal) const
Get row by index.
T GetCell(const std::string &pColumnName, const std::string &pRowName) const
Get cell by name.
std::vector< T > GetColumn(const size_t pColumnIdx, ConvFunc< T > pToVal) const
Get column by index.
void RemoveColumn(const size_t pColumnIdx)
Remove column by index.
T GetCell(const size_t pColumnIdx, const std::string &pRowName) const
Get cell by column index and row name.
void Clear()
Clears loaded Document data.
std::vector< std::string > GetColumnNames()
Get column names.
Document(const std::string &pPath=std::string(), const LabelParams &pLabelParams=LabelParams(), const SeparatorParams &pSeparatorParams=SeparatorParams(), const ConverterParams &pConverterParams=ConverterParams(), const LineReaderParams &pLineReaderParams=LineReaderParams())
Constructor.
std::vector< T > GetColumn(const std::string &pColumnName) const
Get column by name.
void RemoveRow(const std::string &pRowName)
Remove row by name.
T GetCell(const size_t pColumnIdx, const size_t pRowIdx, ConvFunc< T > pToVal) const
Get cell by index.
void SetColumnName(size_t pColumnIdx, const std::string &pColumnName)
Set column name.
void SetRowName(size_t pRowIdx, const std::string &pRowName)
Set row name.
T GetCell(const size_t pColumnIdx, const size_t pRowIdx) const
Get cell by index.
std::vector< T > GetRow(const std::string &pRowName) const
Get row by name.
void SetRow(const size_t pRowIdx, const std::vector< T > &pRow)
Set row by index.
std::vector< T > GetColumn(const std::string &pColumnName, ConvFunc< T > pToVal) const
Get column by name.
std::vector< T > GetColumn(const size_t pColumnIdx) const
Get column by index.
std::vector< std::string > GetRowNames()
Get row names.
void Load(const std::string &pPath, const LabelParams &pLabelParams=LabelParams(), const SeparatorParams &pSeparatorParams=SeparatorParams(), const ConverterParams &pConverterParams=ConverterParams(), const LineReaderParams &pLineReaderParams=LineReaderParams())
Read Document data from file.
void InsertColumn(const size_t pColumnIdx, const std::vector< T > &pColumn=std::vector< T >(), const std::string &pColumnName=std::string())
Insert column at specified index.
void InsertRow(const size_t pRowIdx, const std::vector< T > &pRow=std::vector< T >(), const std::string &pRowName=std::string())
Insert row at specified index.
void SetCell(const size_t pColumnIdx, const size_t pRowIdx, const T &pCell)
Set cell by index.
T GetCell(const std::string &pColumnName, const size_t pRowIdx) const
Get cell by column name and row index.
void Save(const std::string &pPath=std::string())
Write Document data to file.
ssize_t GetRowIdx(const std::string &pRowName) const
Get row index by name.
T GetCell(const std::string &pColumnName, const std::string &pRowName, ConvFunc< T > pToVal) const
Get cell by name.
T GetCell(const size_t pColumnIdx, const std::string &pRowName, ConvFunc< T > pToVal) const
Get cell by column index and row name.
void Save(std::ostream &pStream)
Write Document data to stream.
void SetColumn(const std::string &pColumnName, const std::vector< T > &pColumn)
Set column by name.
void SetCell(const std::string &pColumnName, const std::string &pRowName, const T &pCell)
Set cell by name.
std::string GetColumnName(const ssize_t pColumnIdx)
Get column name.
void Load(std::istream &pStream, const LabelParams &pLabelParams=LabelParams(), const SeparatorParams &pSeparatorParams=SeparatorParams(), const ConverterParams &pConverterParams=ConverterParams(), const LineReaderParams &pLineReaderParams=LineReaderParams())
Read Document data from stream.
void RemoveColumn(const std::string &pColumnName)
Remove column by name.
void RemoveRow(const size_t pRowIdx)
Remove row by index.
Document(std::istream &pStream, const LabelParams &pLabelParams=LabelParams(), const SeparatorParams &pSeparatorParams=SeparatorParams(), const ConverterParams &pConverterParams=ConverterParams(), const LineReaderParams &pLineReaderParams=LineReaderParams())
Constructor.
void SetColumn(const size_t pColumnIdx, const std::vector< T > &pColumn)
Set column by index.
size_t GetColumnCount() const
Get number of data columns (excluding label columns).
T GetCell(const std::string &pColumnName, const size_t pRowIdx, ConvFunc< T > pToVal) const
Get cell by column name and row index.
size_t GetRowCount() const
Get number of data rows (excluding label rows).
std::vector< T > GetRow(const size_t pRowIdx) const
Get row by index.
Exception thrown when attempting to access Document data in a datatype which is not supported by the ...
Datastructure holding parameters controlling how invalid numbers (including empty strings) should be ...
long double mDefaultFloat
floating-point default value to represent invalid numbers.
long long mDefaultInteger
integer default value to represent invalid numbers.
bool mHasDefaultConverter
specifies if conversion of non-numerical strings shall be converted to a default numerical value,...
ConverterParams(const bool pHasDefaultConverter=false, const long double pDefaultFloat=std::numeric_limits< long double >::signaling_NaN(), const long long pDefaultInteger=0)
Constructor.
Datastructure holding parameters controlling which row and column should be treated as labels.
int mRowNameIdx
specifies the zero-based column index of the row labels.
LabelParams(const int pColumnNameIdx=0, const int pRowNameIdx=-1)
Constructor.
int mColumnNameIdx
specifies the zero-based row index of the column labels.
Datastructure holding parameters controlling how special line formats should be treated.
bool mSkipCommentLines
specifies whether to skip lines prefixed with mCommentPrefix.
char mCommentPrefix
specifies which prefix character to indicate a comment line.
bool mSkipEmptyLines
specifies whether to skip empty lines.
LineReaderParams(const bool pSkipCommentLines=false, const char pCommentPrefix='#', const bool pSkipEmptyLines=false)
Constructor.
Datastructure holding parameters controlling how the CSV data fields are separated.
bool mQuotedLinebreaks
specifies whether to allow line breaks in quoted text.
bool mTrim
specifies whether to trim leading and trailing spaces from cells read.
SeparatorParams(const char pSeparator=',', const bool pTrim=false, const bool pHasCR=sPlatformHasCR, const bool pQuotedLinebreaks=false, const bool pAutoQuote=true)
Constructor.
bool mHasCR
specifies whether new documents should use CR/LF instead of LF.
char mSeparator
specifies the column separator.
bool mAutoQuote
specifies whether to automatically dequote cell data.