xtensor
Loading...
Searching...
No Matches
xcsv.hpp
1/***************************************************************************
2 * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht *
3 * Copyright (c) QuantStack *
4 * *
5 * Distributed under the terms of the BSD 3-Clause License. *
6 * *
7 * The full license is in the file LICENSE, distributed with this software. *
8 ****************************************************************************/
9
10#ifndef XTENSOR_CSV_HPP
11#define XTENSOR_CSV_HPP
12
13#include <exception>
14#include <istream>
15#include <iterator>
16#include <sstream>
17#include <string>
18#include <utility>
19
20#include "xtensor.hpp"
21#include "xtensor_config.hpp"
22
23namespace xt
24{
25
26 /**************************************
27 * load_csv and dump_csv declarations *
28 **************************************/
29
30 template <class T, class A = std::allocator<T>>
31 using xcsv_tensor = xtensor_container<std::vector<T, A>, 2, layout_type::row_major>;
32
33 template <class T, class A = std::allocator<T>>
34 xcsv_tensor<T, A> load_csv(
35 std::istream& stream,
36 const char delimiter = ',',
37 const std::size_t skip_rows = 0,
38 const std::ptrdiff_t max_rows = -1,
39 const std::string comments = "#"
40 );
41
42 template <class E>
43 void dump_csv(std::ostream& stream, const xexpression<E>& e);
44
45 /*****************************************
46 * load_csv and dump_csv implementations *
47 *****************************************/
48
49 namespace detail
50 {
51 template <class T>
52 inline T lexical_cast(const std::string& cell)
53 {
54 T res;
55 std::istringstream iss(cell);
56 iss >> res;
57 return res;
58 }
59
60 template <>
61 inline std::string lexical_cast(const std::string& cell)
62 {
63 size_t first = cell.find_first_not_of(' ');
64 if (first == std::string::npos)
65 {
66 return cell;
67 }
68
69 size_t last = cell.find_last_not_of(' ');
70 return cell.substr(first, last == std::string::npos ? cell.size() : last + 1);
71 }
72
73 template <>
74 inline float lexical_cast<float>(const std::string& cell)
75 {
76 return std::stof(cell);
77 }
78
79 template <>
80 inline double lexical_cast<double>(const std::string& cell)
81 {
82 return std::stod(cell);
83 }
84
85 template <>
86 inline long double lexical_cast<long double>(const std::string& cell)
87 {
88 return std::stold(cell);
89 }
90
91 template <>
92 inline int lexical_cast<int>(const std::string& cell)
93 {
94 return std::stoi(cell);
95 }
96
97 template <>
98 inline long lexical_cast<long>(const std::string& cell)
99 {
100 return std::stol(cell);
101 }
102
103 template <>
104 inline long long lexical_cast<long long>(const std::string& cell)
105 {
106 return std::stoll(cell);
107 }
108
109 template <>
110 inline unsigned int lexical_cast<unsigned int>(const std::string& cell)
111 {
112 return static_cast<unsigned int>(std::stoul(cell));
113 }
114
115 template <>
116 inline unsigned long lexical_cast<unsigned long>(const std::string& cell)
117 {
118 return std::stoul(cell);
119 }
120
121 template <>
122 inline unsigned long long lexical_cast<unsigned long long>(const std::string& cell)
123 {
124 return std::stoull(cell);
125 }
126
127 template <class ST, class T, class OI>
128 ST load_csv_row(std::istream& row_stream, OI output, std::string cell, const char delimiter = ',')
129 {
130 ST length = 0;
131 while (std::getline(row_stream, cell, delimiter))
132 {
133 *output++ = lexical_cast<T>(cell);
134 ++length;
135 }
136 return length;
137 }
138 }
139
151 template <class T, class A>
153 std::istream& stream,
154 const char delimiter,
155 const std::size_t skip_rows,
156 const std::ptrdiff_t max_rows,
157 const std::string comments
158 )
159 {
161 using storage_type = typename tensor_type::storage_type;
162 using size_type = typename tensor_type::size_type;
163 using inner_shape_type = typename tensor_type::inner_shape_type;
164 using inner_strides_type = typename tensor_type::inner_strides_type;
165 using output_iterator = std::back_insert_iterator<storage_type>;
166
167 storage_type data;
168 size_type nbrow = 0, nbcol = 0, nhead = 0;
169 {
171 std::string row, cell;
172 while (std::getline(stream, row))
173 {
174 if (nhead < skip_rows)
175 {
176 ++nhead;
177 continue;
178 }
179 if (std::equal(comments.begin(), comments.end(), row.begin()))
180 {
181 continue;
182 }
183 if (0 < max_rows && max_rows <= static_cast<const long long>(nbrow))
184 {
185 break;
186 }
187 std::stringstream row_stream(row);
188 nbcol = detail::load_csv_row<size_type, T, output_iterator>(row_stream, output, cell, delimiter);
189 ++nbrow;
190 }
191 }
192 inner_shape_type shape = {nbrow, nbcol};
193 inner_strides_type strides; // no need for initializer list for stack-allocated strides_type
195 // Sanity check for data size.
196 if (data.size() != data_size)
197 {
198 XTENSOR_THROW(std::runtime_error, "Inconsistent row lengths in CSV");
199 }
200 return tensor_type(std::move(data), std::move(shape), std::move(strides));
201 }
202
209 template <class E>
210 void dump_csv(std::ostream& stream, const xexpression<E>& e)
211 {
212 using size_type = typename E::size_type;
213 const E& ex = e.derived_cast();
214 if (ex.dimension() != 2)
215 {
216 XTENSOR_THROW(std::runtime_error, "Only 2-D expressions can be serialized to CSV");
217 }
218 size_type nbrows = ex.shape()[0], nbcols = ex.shape()[1];
219 auto st = ex.stepper_begin(ex.shape());
220 for (size_type r = 0; r != nbrows; ++r)
221 {
222 for (size_type c = 0; c != nbcols; ++c)
223 {
224 stream << *st;
225 if (c != nbcols - 1)
226 {
227 st.step(1);
228 stream << ',';
229 }
230 else
231 {
232 st.reset(1);
233 st.step(0);
234 stream << std::endl;
235 }
236 }
237 }
238 }
239
241 {
242 char delimiter;
243 std::size_t skip_rows;
244 std::ptrdiff_t max_rows;
245 std::string comments;
246
248 : delimiter(',')
249 , skip_rows(0)
250 , max_rows(-1)
251 , comments("#")
252 {
253 }
254 };
255
256 template <class E>
257 void load_file(std::istream& stream, xexpression<E>& e, const xcsv_config& config)
258 {
259 e.derived_cast() = load_csv<typename E::value_type>(
260 stream,
261 config.delimiter,
262 config.skip_rows,
263 config.max_rows,
264 config.comments
265 );
266 }
267
268 template <class E>
269 void dump_file(std::ostream& stream, const xexpression<E>& e, const xcsv_config&)
270 {
271 dump_csv(stream, e);
272 }
273}
274
275#endif
std::size_t compute_strides(const shape_type &shape, layout_type l, strides_type &strides)
Compute the strides given the shape and the layout of an array.
Definition xstrides.hpp:566
auto strides(const E &e, stride_type type=stride_type::normal) noexcept
Get strides of an object.
Definition xstrides.hpp:248
standard mathematical functions for xexpressions
xcsv_tensor< T, A > load_csv(std::istream &stream, const char delimiter=',', const std::size_t skip_rows=0, const std::ptrdiff_t max_rows=-1, const std::string comments="#")
Load tensor from CSV.
Definition xcsv.hpp:152
auto row(E &&e, std::ptrdiff_t index)
Constructs and returns a row (sliced view) on the specified expression.
Definition xview.hpp:1922
void dump_csv(std::ostream &stream, const xexpression< E > &e)
Dump tensor to CSV.
Definition xcsv.hpp:210