10 #include <type_traits>
18 static int DECIMAL_PLACES = 5;
23 template<
typename T =
int>
34 inline long int csv_abs(
long int x) {
39 inline long long int csv_abs(
long long int x) {
49 inline double csv_abs(
double x) {
54 inline long double csv_abs(
long double x) {
63 csv::enable_if_t<std::is_arithmetic<T>::value,
int> = 0
81 csv::enable_if_t<std::is_unsigned<T>::value,
int> = 0>
83 std::string digits_reverse =
"";
85 if (value == 0)
return "0";
88 digits_reverse += (char)(
'0' + (value % 10));
92 return std::string(digits_reverse.rbegin(), digits_reverse.rend());
98 csv::enable_if_t<std::is_integral<T>::value && std::is_signed<T>::value,
int> = 0
104 return "-" +
to_string((
size_t)(value * -1));
110 csv::enable_if_t<std::is_floating_point<T>::value,
int> = 0
117 std::string result =
"";
120 T fractional_part = std::abs(std::modf(value, &integral_part));
121 integral_part = std::abs(integral_part);
124 if (value < 0) result =
"-";
126 if (integral_part == 0) {
130 for (
int n_digits =
num_digits(integral_part); n_digits > 0; n_digits --) {
131 int digit = (int)(std::fmod(integral_part,
pow10(n_digits)) /
pow10(n_digits - 1));
132 result += (char)(
'0' + digit);
139 if (fractional_part > 0) {
140 fractional_part *= (T)(
pow10(DECIMAL_PLACES));
141 for (
int n_digits = DECIMAL_PLACES; n_digits > 0; n_digits--) {
142 int digit = (int)(std::fmod(fractional_part,
pow10(n_digits)) /
pow10(n_digits - 1));
143 result += (char)(
'0' + digit);
160 inline static void set_decimal_places(
int precision) {
161 internals::DECIMAL_PLACES = precision;
192 template<
class OutputStream,
char Delim,
char Quote,
bool Flush>
202 : out(_out), quote_minimal(_quote_minimal) {};
225 template<
typename T,
size_t Size>
227 for (
size_t i = 0; i < Size; i++) {
228 out << csv_escape(record[i]);
229 if (i + 1 != Size) out << Delim;
237 template<
typename... T>
239 this->write_tuple<0, T...>(record);
249 typename T,
typename Alloc,
template <
typename,
typename>
class Container,
252 csv::enable_if_t<std::is_class<Alloc>::value,
int> = 0
255 const size_t ilen = record.size();
257 for (
const auto& field : record) {
258 out << csv_escape(field);
259 if (i + 1 != ilen) out << Delim;
278 !std::is_convertible<T, std::string>::value
279 && !std::is_convertible<T, csv::string_view>::value
282 std::string csv_escape(T in) {
289 std::is_convertible<T, std::string>::value
290 || std::is_convertible<T, csv::string_view>::value
293 std::string csv_escape(T in) {
294 IF_CONSTEXPR(std::is_convertible<T, csv::string_view>::value) {
295 return _csv_escape(in);
298 return _csv_escape(std::string(in));
309 bool quote_escape =
false;
312 if (ch == Quote || ch == Delim || ch ==
'\r' || ch ==
'\n') {
319 if (quote_minimal)
return std::string(in);
321 std::string ret(1, Quote);
329 std::string ret(1, Quote);
331 if (ch == Quote) ret += std::string(2, Quote);
341 template<
size_t Index = 0,
typename... T>
342 typename std::enable_if<Index <
sizeof...(T),
void>::type write_tuple(
const std::tuple<T...>& record) {
343 out << csv_escape(std::get<Index>(record));
347 this->write_tuple<Index + 1>(record);
351 template<
size_t Index = 0,
typename... T>
352 typename std::enable_if<Index ==
sizeof...(T),
void>::type write_tuple(
const std::tuple<T...>& record) {
374 template<
class OutputStream,
bool Flush = true>
385 template<
class OutputStream,
bool Flush = true>
389 template<
class OutputStream>
395 template<
class OutputStream>
401 template<
class OutputStream>
407 template<
class OutputStream>
Class for writing delimiter separated values files.
DelimWriter & operator<<(const std::tuple< T... > &record)
Format a sequence of strings and write to CSV according to RFC 4180.
void flush()
Flushes the written data.
DelimWriter(OutputStream &_out, bool _quote_minimal=true)
Construct a DelimWriter over the specified output stream.
DelimWriter(const std::string &filename)
Construct a DelimWriter over the file.
~DelimWriter()
Destructor will flush remaining data.
DelimWriter & operator<<(const Container< T, Alloc > &record)
Format a sequence of strings and write to CSV according to RFC 4180.
DelimWriter & operator<<(const std::array< T, Size > &record)
Format a sequence of strings and write to CSV according to RFC 4180.
A standalone header file containing shared code.
#define IF_CONSTEXPR
Expands to if constexpr in C++17 and if otherwise.
Implements data type parsing functionality.
T csv_abs(T x)
Calculate the absolute value of a number.
int num_digits(T x)
Calculate the number of digits in a number.
HEDLEY_CONST CONSTEXPR_14 long double pow10(const T &n) noexcept
Compute 10 to the power of n.
std::string to_string(T value)
to_string() for unsigned integers
The all encompassing namespace.
TSVWriter< OutputStream, false > make_tsv_writer_buffered(OutputStream &out, bool quote_minimal=true)
Return a buffered csv::TSVWriter over the output stream (does not auto flush)
CSVWriter< OutputStream > make_csv_writer(OutputStream &out, bool quote_minimal=true)
Return a csv::CSVWriter over the output stream.
CSVWriter< OutputStream, false > make_csv_writer_buffered(OutputStream &out, bool quote_minimal=true)
Return a buffered csv::CSVWriter over the output stream (does not auto flush)
TSVWriter< OutputStream > make_tsv_writer(OutputStream &out, bool quote_minimal=true)
Return a csv::TSVWriter over the output stream.
nonstd::string_view string_view
The string_view class used by this library.