MT Core (C++)
Core library for replacing C++ standard in project usage
Loading...
Searching...
No Matches
csv/writer.hpp
Go to the documentation of this file.
1/*
2
3Copyright 2025 Matthew Tolman
4
5Licensed under the Apache License, Version 2.0 (the "License");
6you may not use this file except in compliance with the License.
7You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11Unless required by applicable law or agreed to in writing, software
12distributed under the License is distributed on an "AS IS" BASIS,
13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14See the License for the specific language governing permissions and
15limitations under the License.
16
17*/
18
19#ifndef MTCORE_CSV_WRITTER_HPP
20#define MTCORE_CSV_WRITTER_HPP
21
22#include "mtcore/csv/common.hpp"
23#include "mtcore/io/writer.hpp"
24
29
33namespace mtcore::csv {
38 struct RowEnd {};
43 struct ColEnd {};
44
50 using Column = std::variant<i64, u64, Slice<const char>, f64>;
58 using WriteElem = std::variant<i64, u64, Slice<const char>, f64, Slice<const Column>, RowEnd, ColEnd>;
59
60 namespace impl {
61 template<WriterImpl WI>
62 struct Writer {
63 static constexpr bool IsWriteThrough = true;
65 using ErrType = typename io::Writer<WI>::ErrType;
66 io::Writer<WI> &underlying;
67 Options opts = {};
68
70 size_t written = 0;
71 if (auto r = underlying.write(opts.quote); r.is_error()) {
72 return r.error();
73 }
74 ++written;
75 if (slices::contains(opts.quote, s)) {
76 auto splits = slices::split(opts.quote, s);
78 bool first = true;
79 while (splits.next().copy_if_present(cur)) {
80 if (!first) {
81 if (auto r = underlying.write_n_times(opts.quote, 2); r.is_error()) {
82 return r.error();
83 }
84 written += 2;
85 }
86 else {
87 first = false;
88 }
89 if (!cur.empty()) {
90 if (auto r = underlying.write_all(cur); r.is_error()) {
91 return r.error();
92 }
93 written += cur.size();
94 }
95 }
96 }
97 else if (!s.empty()) {
98 if (auto r = underlying.write_all(s); r.is_error()) {
99 return r.error();
100 }
101 written += s.size();
102 }
103
104 if (auto r = underlying.write(opts.quote); r.is_error()) {
105 return r.error();
106 }
107
108 ++written;
109 return success(written);
110 }
111 Result<size_t, ErrType> operator()(i64 i) { return print(underlying, "{}", i); }
112 Result<size_t, ErrType> operator()(u64 i) { return print(underlying, "{}", i); }
113 Result<size_t, ErrType> operator()(f64 i) { return print(underlying, "{}", i); }
114 Result<size_t, ErrType> operator()(RowEnd) {
115 if (opts.cr.has_value()) {
116 return print(underlying, "{}{}", opts.cr.value(), opts.lf);
117 }
118 return print(underlying, "{}", opts.lf);
119 }
120 Result<size_t, ErrType> operator()(ColEnd) { return print(underlying, "{}", opts.sep); }
122 auto iter = col.iter();
123 Column cur;
124 auto first = true;
125 size_t written = 0;
126 while (iter.next().copy_if_present(cur)) {
127 if (!first) {
128 if (auto r = (*this)(ColEnd{}); r.is_error()) {
129 return r.error();
130 }
131 else {
132 written += r.value();
133 }
134 }
135 else {
136 first = false;
137 }
138
139 auto pr = std::visit(*this, cur);
140 if (pr.is_error()) {
141 return pr.error();
142 }
143 written += pr.value();
144 }
145 auto leRes = (*this)(RowEnd{});
146 if (leRes.is_error()) {
147 return leRes.error();
148 }
149 written += leRes.value();
150 return success(written);
151 }
152
153 Result<size_t, ErrType> write(WriteElem e) { return std::visit(*this, e); }
154
156 auto iter = e.iter();
157 WriteElem cur;
158 size_t written = 0;
159 while (iter.next().copy_if_present(cur)) {
160 if (auto r = write(cur); r.is_error()) {
161 return r.error();
162 }
163 else {
164 written += r.value();
165 }
166 }
167 return success(written);
168 }
169 };
170 } // namespace impl
171
181 template<WriterImpl WI>
183 return io::Writer<csv::impl::Writer<WI>>{.underlying = csv::impl::Writer<WI>{underlying, opts}};
184 }
185} // namespace mtcore::csv
186
187#endif // MTCORE_CSV_WRITTER_HPP
SplitIter< T, Slice< T > > split(const Slice< T > &needle, const Slice< T > &haystack)
Splits a slice into smaller sub slices.
bool contains(const std::remove_const_t< T > &needle, const Slice< T > &haystack)
Checks whether a slice (the haystack) contains an element (the needle) Uses the equality operator of ...
io::Writer< csv::impl::Writer< WI > > writer(io::Writer< WI > &underlying, Options opts={})
Creates a CSV writer which will encode the data before writing it out.
std::variant< i64, u64, Slice< const char >, f64 > Column
Column type.
std::variant< i64, u64, Slice< const char >, f64, Slice< const Column >, RowEnd, ColEnd > WriteElem
Elements that can be written to a CSV writer.
Success< void > success()
Creates a successful void Result object.
Definition result.hpp:398
uint64_t u64
Alias for 64-bit unsigned ints.
int64_t i64
Alias for 64-bit ints.
double f64
Alias for 64-bit floats.
CSV namespace for CSV-related utilities.
Definition common.hpp:24
Generic iterator defaults built on common contracts Does not guarantee performance of iterators Actua...
Definition iter.hpp:91
bool has_value() const noexcept
Definition optional.hpp:294
T & value() noexcept
Definition optional.hpp:301
bool is_error() const noexcept
Checks if is an error Result.
Definition result.hpp:133
Represents a Result that may have an error (error code) or a success value A type of "void" means the...
Definition result.hpp:170
A Slice which is just a pointer + length Accessing elements through the array operator will do bounds...
constexpr size_t size() const noexcept
Gets the size of a Slice.
constexpr bool empty() const noexcept
Checks if a Slice is empty.
decltype(auto) iter() const noexcept
Special output-only type for indicating the end of a colum.
CSV options for defining the CSV format.
Definition common.hpp:96
Optional< char > cr
Definition common.hpp:97
Special output-only type for indicating the end of a row.
A writer that writes data to some sort of stream or buffer Note: the data elements written should be ...
Definition io/writer.hpp:51
Result< void, ErrType > write_n_times(const Slice< std::remove_const_t< WriteElem > > &s, size_t n)
Will write all the elements in a Slice N times If there is no room, will return the error OUT_OF_ROOM...
typename Impl::ErrType ErrType
Definition io/writer.hpp:53
Result< size_t, ErrType > write(const Slice< std::remove_const_t< WriteElem > > &s)
Will write as much of a Slice as possible.
Definition io/writer.hpp:62
Result< size_t, ErrType > write_all(const Slice< std::remove_const_t< WriteElem > > &s)
Will write all the elements in a Slice If there is no room, will return the error OUT_OF_ROOM Note: M...