C++ rapidcsv
1.unittest.h
#pragma once
#ifndef _MSC_VER
#include <unistd.h>
#else
#include <io.h>
#endif
#include <fstream>
#include <string>
#include <sstream>
#define ExpectEqual(t, a, b) ExpectEqualFun<t>(a, b, #a, #b, __FILE__, __LINE__)
#define ExpectTrue(a) ExpectTrueFun(a, #a, __FILE__, __LINE__)
#define ExpectException(expr, excp) \
do \
{ \
bool success = false; \
try \
{ \
expr; \
} \
catch (const excp&) \
{ \
success = true; \
} \
catch(const std::exception& ex) \
{ \
std::stringstream ss; \
ss << unittest::detail::FileName(__FILE__) << ":" << std::to_string(__LINE__); \
ss << " ExpectException failed: unexpected exception '" << typeid(ex).name(); \
ss << "' thrown." << std::endl; \
throw std::runtime_error(ss.str()); \
} \
\
if (!success) \
{ \
std::stringstream ss; \
ss << unittest::detail::FileName(__FILE__) << ":" << std::to_string(__LINE__); \
ss << " ExpectException failed: expected exception '" << #excp << "' not thrown."; \
ss << std::endl; \
throw std::runtime_error(ss.str()); \
} \
} \
while (0)
namespace unittest
{
namespace detail
{
inline std::string FileName(const std::string& pPath)
{
const std::size_t slash = pPath.rfind("/");
std::string name = (slash != std::string::npos) ? pPath.substr(slash + 1) : pPath;
return name;
}
}
inline std::string TempPath()
{
char name[] = "rapidcsvtest.XXXXXX";
#ifndef _MSC_VER
int fd = mkstemp(name);
close(fd);
#else
_mktemp_s(name, strlen(name) + 1);
#endif
return std::string(name);
}
inline void WriteFile(const std::string& pPath, const std::string& pData)
{
std::ofstream outfile;
outfile.open(pPath, std::ifstream::out | std::ifstream::binary);
outfile << pData;
outfile.close();
}
inline std::string ReadFile(const std::string& pPath)
{
std::ifstream infile;
infile.open(pPath, std::ifstream::in | std::ifstream::binary);
std::string data((std::istreambuf_iterator<char>(infile)), std::istreambuf_iterator<char>());
infile.close();
return data;
}
inline void DeleteFile(const std::string& pPath)
{
std::remove(pPath.c_str());
}
template<typename T>
inline void ExpectEqualFun(T pTest, T pRef, const std::string& testName,
const std::string& refName, const std::string& filePath, int lineNo)
{
if (pTest != pRef)
{
std::stringstream ss;
ss << detail::FileName(filePath) << ":" << std::to_string(lineNo);
ss << " ExpectEqual failed: " << testName << " != " << refName << std::endl;
ss << testName << " = '" << pTest << "'" << std::endl;
ss << refName << " = '" << pRef << "'" << std::endl;
throw std::runtime_error(ss.str());
}
}
inline void ExpectTrueFun(bool pTest, const std::string& testName, const std::string& filePath,
int lineNo)
{
if (!pTest)
{
std::stringstream ss;
ss << detail::FileName(filePath) << ":" << std::to_string((long long)lineNo);
ss << " ExpectTrue failed: " << testName << " == false" << std::endl;
throw std::runtime_error(ss.str());
}
}
}
2.rapidcsv.h
#pragma once
#include <algorithm>
#include <cassert>
#include <cmath>
#ifdef HAS_CODECVT
#include <codecvt>
#endif
#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <typeinfo>
#include <vector>
using namespace std;
#if defined(_MSC_VER)
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif
namespace rapidcsv
{
#if defined(_MSC_VER)
static const bool sPlatformHasCR = true;
#else
static const bool sPlatformHasCR = false;
#endif
/**
* @brief Datastructure holding parameters controlling how invalid numbers (including
* empty strings) should be handled.
*/
struct ConverterParams
{
/**
* @brief Constructor
* @param pHasDefaultConverter specifies if conversion of non-numerical strings shall be
* converted to a default numerical value, instead of causing
* an exception to be thrown (default).
* @param pDefaultFloat floating-point default value to represent invalid numbers.
* @param pDefaultInteger integer default value to represent invalid numbers.
*/
explicit ConverterParams(const bool pHasDefaultConverter = false,
const long double pDefaultFloat = std::numeric_limits<long double>::signaling_NaN(),
const long long pDefaultInteger = 0)
: mHasDefaultConverter(pHasDefaultConverter)
, mDefaultFloat(pDefaultFloat)
, mDefaultInteger(pDefaultInteger)
{
}
/**
* @brief specifies if conversion of non-numerical strings shall be converted to a default
* numerical value, instead of causing an exception to be thrown (default).
*/
bool mHasDefaultConverter;
/**
* @brief floating-point default value to represent invalid numbers.
*/
long double mDefaultFloat;
/**
* @brief integer default value to represent invalid numbers.
*/
long long mDefaultInteger;
};
/**
* @brief Exception thrown when attempting to access Document data in a datatype which
* is not supported by the Converter class.
*/
class no_converter : public std::exception
{
/**
* @brief Provides details about the exception
* @returns an explanatory string
*/
virtual const char* what() const throw()
{
return "unsupported conversion datatype";
}
};
/**
* @brief Class providing conversion to/from numerical datatypes and strings. Only
* intended for rapidcsv internal usage, but exposed externally to allow
* specialization for custom datatype conversions.
*/
template<typename T>
class Converter
{
public:
/**
* @brief Constructor
* @param pConverterParams specifies how conversion of non-numerical values to
* numerical datatype shall be handled.
*/
Converter(const ConverterParams& pConverterParams)
: mConverterParams(pConverterParams)
{
}
/**
* @brief Converts numerical value to string representation.
* @param pVal numerical value
* @param pStr output string
*/
void ToStr(const T& pVal, std::string& pStr) const
{
if (typeid(T) == typeid(int) ||
typeid(T) == typeid(long) ||
typeid(T) == typeid(long long) ||
typeid(T) == typeid(unsigned) ||
typeid(T) == typeid(unsigned long) ||
typeid(T) == typeid(unsigned long long) ||
typeid(T) == typeid(float) ||
typeid(T) == typeid(double) ||
typeid(T) == typeid(long double) ||
typeid(T) == typeid(char))
{
std::ostringstream out;
out << pVal;
pStr = out.str();
}
else
{
throw no_converter();
}
}
/**
* @brief Converts string holding a numerical value to numerical datatype representation.
* @param pVal numerical value
* @param pStr output string
*/
void ToVal(const std::string& pStr, T& pVal) const
{
try
{
if (typeid(T) == typeid(int))
{
pVal = static_cast<T>(std::stoi(pStr));
return;
}
else if (typeid(T) == typeid(long))
{
pVal = static_cast<T>(std::stol(pStr));
return;
}
else if (typeid(T) == typeid(long long))
{
pVal = static_cast<T>(std::stoll(pStr));
return;
}
else if (typeid(T) == typeid(unsigned))
{
pVal = static_cast<T>(std::stoul(pStr));
return;
}
else if (typeid(T) == typeid(unsigned long))
{
pVal = static_cast<T>(std::stoul(pStr));
return;
}
else if (typeid(T) == typeid(unsigned long long))
{
pVal = static_cast<T>(std::stoull(pStr)