/src/jsoncons/include/jsoncons_ext/csv/csv_reader.hpp
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2013-2025 Daniel Parker |
2 | | // Distributed under the Boost license, Version 1.0. |
3 | | // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
4 | | |
5 | | // See https://github.com/danielaparker/jsoncons for latest version |
6 | | |
7 | | #ifndef JSONCONS_CSV_CSV_READER_HPP |
8 | | #define JSONCONS_CSV_CSV_READER_HPP |
9 | | |
10 | | #include <cstddef> |
11 | | #include <functional> |
12 | | #include <memory> // std::allocator |
13 | | #include <system_error> |
14 | | #include <utility> // std::move |
15 | | |
16 | | #include <jsoncons/config/compiler_support.hpp> |
17 | | #include <jsoncons/json_decoder.hpp> |
18 | | #include <jsoncons/json_exception.hpp> |
19 | | #include <jsoncons/json_reader.hpp> |
20 | | #include <jsoncons/json_visitor.hpp> |
21 | | #include <jsoncons/ser_context.hpp> |
22 | | #include <jsoncons/source.hpp> |
23 | | #include <jsoncons/source_adaptor.hpp> |
24 | | |
25 | | #include <jsoncons_ext/csv/csv_error.hpp> |
26 | | #include <jsoncons_ext/csv/csv_options.hpp> |
27 | | #include <jsoncons_ext/csv/csv_parser.hpp> |
28 | | |
29 | | namespace jsoncons { |
30 | | namespace csv { |
31 | | |
32 | | template <typename CharT,typename Source=jsoncons::stream_source<CharT>,typename Allocator=std::allocator<char>> |
33 | | class basic_csv_reader |
34 | | { |
35 | | struct stack_item |
36 | | { |
37 | | stack_item() noexcept |
38 | | : array_begun_(false) |
39 | | { |
40 | | } |
41 | | |
42 | | bool array_begun_; |
43 | | }; |
44 | | using char_type = CharT; |
45 | | using temp_allocator_type = Allocator; |
46 | | using char_allocator_type = typename std::allocator_traits<temp_allocator_type>:: template rebind_alloc<CharT>; |
47 | | |
48 | | basic_csv_reader(const basic_csv_reader&) = delete; |
49 | | basic_csv_reader& operator = (const basic_csv_reader&) = delete; |
50 | | |
51 | | basic_default_json_visitor<CharT> default_visitor_; |
52 | | text_source_adaptor<Source> source_; |
53 | | basic_json_visitor<CharT>& visitor_; |
54 | | basic_csv_parser<CharT,Allocator> parser_; |
55 | | |
56 | | public: |
57 | | // Structural characters |
58 | | static constexpr size_t default_max_buffer_size = 16384; |
59 | | //! Parse an input stream of CSV text into a json object |
60 | | /*! |
61 | | \param is The input stream to read from |
62 | | */ |
63 | | |
64 | | template <typename Sourceable> |
65 | | basic_csv_reader(Sourceable&& source, |
66 | | basic_json_visitor<CharT>& visitor, |
67 | | const Allocator& alloc = Allocator()) |
68 | | |
69 | 3.44k | : basic_csv_reader(std::forward<Sourceable>(source), |
70 | 3.44k | visitor, |
71 | 3.44k | basic_csv_decode_options<CharT>(), |
72 | 3.44k | default_csv_parsing(), |
73 | 3.44k | alloc) |
74 | 3.44k | { |
75 | 3.44k | } |
76 | | |
77 | | template <typename Sourceable> |
78 | | basic_csv_reader(Sourceable&& source, |
79 | | basic_json_visitor<CharT>& visitor, |
80 | | const basic_csv_decode_options<CharT>& options, |
81 | | const Allocator& alloc = Allocator()) |
82 | | |
83 | 2.36k | : basic_csv_reader(std::forward<Sourceable>(source), |
84 | 2.36k | visitor, |
85 | 2.36k | options, |
86 | 2.36k | default_csv_parsing(), |
87 | 2.36k | alloc) |
88 | 2.36k | { |
89 | 2.36k | } |
90 | | |
91 | | template <typename Sourceable> |
92 | | basic_csv_reader(Sourceable&& source, |
93 | | basic_json_visitor<CharT>& visitor, |
94 | | std::function<bool(csv_errc,const ser_context&)> err_handler, |
95 | | const Allocator& alloc = Allocator()) |
96 | | : basic_csv_reader(std::forward<Sourceable>(source), |
97 | | visitor, |
98 | | basic_csv_decode_options<CharT>(), |
99 | | err_handler, |
100 | | alloc) |
101 | | { |
102 | | } |
103 | | |
104 | | template <typename Sourceable> |
105 | | basic_csv_reader(Sourceable&& source, |
106 | | basic_json_visitor<CharT>& visitor, |
107 | | const basic_csv_decode_options<CharT>& options, |
108 | | std::function<bool(csv_errc,const ser_context&)> err_handler, |
109 | | const Allocator& alloc = Allocator()) |
110 | 5.81k | : source_(std::forward<Sourceable>(source)), |
111 | 5.81k | visitor_(visitor), |
112 | 5.81k | parser_(options, err_handler, alloc) |
113 | | |
114 | 5.81k | { |
115 | 5.81k | } jsoncons::csv::basic_csv_reader<char, jsoncons::stream_source<char>, std::__1::allocator<char> >::basic_csv_reader<std::__1::basic_istringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >&>(std::__1::basic_istringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, jsoncons::basic_json_visitor<char>&, jsoncons::csv::basic_csv_decode_options<char> const&, std::__1::function<bool (jsoncons::csv::csv_errc, jsoncons::ser_context const&)>, std::__1::allocator<char> const&) Line | Count | Source | 110 | 3.44k | : source_(std::forward<Sourceable>(source)), | 111 | 3.44k | visitor_(visitor), | 112 | 3.44k | parser_(options, err_handler, alloc) | 113 | | | 114 | 3.44k | { | 115 | 3.44k | } |
jsoncons::csv::basic_csv_reader<char, jsoncons::string_source<char>, std::__1::allocator<char> >::basic_csv_reader<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, jsoncons::basic_json_visitor<char>&, jsoncons::csv::basic_csv_decode_options<char> const&, std::__1::function<bool (jsoncons::csv::csv_errc, jsoncons::ser_context const&)>, std::__1::allocator<char> const&) Line | Count | Source | 110 | 2.36k | : source_(std::forward<Sourceable>(source)), | 111 | 2.36k | visitor_(visitor), | 112 | 2.36k | parser_(options, err_handler, alloc) | 113 | | | 114 | 2.36k | { | 115 | 2.36k | } |
|
116 | | |
117 | 5.81k | ~basic_csv_reader() noexcept = default; jsoncons::csv::basic_csv_reader<char, jsoncons::stream_source<char>, std::__1::allocator<char> >::~basic_csv_reader() Line | Count | Source | 117 | 3.44k | ~basic_csv_reader() noexcept = default; |
jsoncons::csv::basic_csv_reader<char, jsoncons::string_source<char>, std::__1::allocator<char> >::~basic_csv_reader() Line | Count | Source | 117 | 2.36k | ~basic_csv_reader() noexcept = default; |
|
118 | | |
119 | | void read() |
120 | 2.36k | { |
121 | 2.36k | std::error_code ec; |
122 | 2.36k | read(ec); |
123 | 2.36k | if (JSONCONS_UNLIKELY(ec)) |
124 | 85 | { |
125 | 85 | JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column())); |
126 | 85 | } |
127 | 2.36k | } |
128 | | |
129 | | void read(std::error_code& ec) |
130 | 5.81k | { |
131 | 5.81k | read_internal(ec); |
132 | 5.81k | } jsoncons::csv::basic_csv_reader<char, jsoncons::stream_source<char>, std::__1::allocator<char> >::read(std::__1::error_code&) Line | Count | Source | 130 | 3.44k | { | 131 | 3.44k | read_internal(ec); | 132 | 3.44k | } |
jsoncons::csv::basic_csv_reader<char, jsoncons::string_source<char>, std::__1::allocator<char> >::read(std::__1::error_code&) Line | Count | Source | 130 | 2.36k | { | 131 | 2.36k | read_internal(ec); | 132 | 2.36k | } |
|
133 | | |
134 | | std::size_t line() const |
135 | | { |
136 | | return parser_.line(); |
137 | | } |
138 | | |
139 | | std::size_t column() const |
140 | | { |
141 | | return parser_.column(); |
142 | | } |
143 | | |
144 | | bool eof() const |
145 | | { |
146 | | return parser_.source_exhausted() && source_.eof(); |
147 | | } |
148 | | |
149 | | private: |
150 | | |
151 | | void read_internal(std::error_code& ec) |
152 | 5.81k | { |
153 | 5.81k | if (source_.is_error()) |
154 | 0 | { |
155 | 0 | ec = csv_errc::source_error; |
156 | 0 | return; |
157 | 0 | } |
158 | 47.2k | while (!parser_.stopped()) |
159 | 41.5k | { |
160 | 41.5k | if (parser_.source_exhausted()) |
161 | 41.5k | { |
162 | 41.5k | auto s = source_.read_buffer(ec); |
163 | 41.5k | if (JSONCONS_UNLIKELY(ec)) return; |
164 | 41.5k | if (s.size() > 0) |
165 | 8.60k | { |
166 | 8.60k | parser_.update(s.data(),s.size()); |
167 | 8.60k | } |
168 | 41.5k | } |
169 | 41.5k | parser_.parse_some(visitor_, ec); |
170 | 41.5k | if (JSONCONS_UNLIKELY(ec)) return; |
171 | 41.5k | } |
172 | 5.81k | } jsoncons::csv::basic_csv_reader<char, jsoncons::stream_source<char>, std::__1::allocator<char> >::read_internal(std::__1::error_code&) Line | Count | Source | 152 | 3.44k | { | 153 | 3.44k | if (source_.is_error()) | 154 | 0 | { | 155 | 0 | ec = csv_errc::source_error; | 156 | 0 | return; | 157 | 0 | } | 158 | 29.5k | while (!parser_.stopped()) | 159 | 26.1k | { | 160 | 26.1k | if (parser_.source_exhausted()) | 161 | 26.1k | { | 162 | 26.1k | auto s = source_.read_buffer(ec); | 163 | 26.1k | if (JSONCONS_UNLIKELY(ec)) return; | 164 | 26.1k | if (s.size() > 0) | 165 | 6.24k | { | 166 | 6.24k | parser_.update(s.data(),s.size()); | 167 | 6.24k | } | 168 | 26.1k | } | 169 | 26.1k | parser_.parse_some(visitor_, ec); | 170 | 26.1k | if (JSONCONS_UNLIKELY(ec)) return; | 171 | 26.1k | } | 172 | 3.44k | } |
jsoncons::csv::basic_csv_reader<char, jsoncons::string_source<char>, std::__1::allocator<char> >::read_internal(std::__1::error_code&) Line | Count | Source | 152 | 2.36k | { | 153 | 2.36k | if (source_.is_error()) | 154 | 0 | { | 155 | 0 | ec = csv_errc::source_error; | 156 | 0 | return; | 157 | 0 | } | 158 | 17.6k | while (!parser_.stopped()) | 159 | 15.3k | { | 160 | 15.3k | if (parser_.source_exhausted()) | 161 | 15.3k | { | 162 | 15.3k | auto s = source_.read_buffer(ec); | 163 | 15.3k | if (JSONCONS_UNLIKELY(ec)) return; | 164 | 15.3k | if (s.size() > 0) | 165 | 2.35k | { | 166 | 2.35k | parser_.update(s.data(),s.size()); | 167 | 2.35k | } | 168 | 15.3k | } | 169 | 15.3k | parser_.parse_some(visitor_, ec); | 170 | 15.3k | if (JSONCONS_UNLIKELY(ec)) return; | 171 | 15.3k | } | 172 | 2.36k | } |
|
173 | | }; |
174 | | |
175 | | using csv_string_reader = basic_csv_reader<char,string_source<char>>; |
176 | | using wcsv_string_reader = basic_csv_reader<wchar_t,string_source<wchar_t>>; |
177 | | using csv_stream_reader = basic_csv_reader<char,stream_source<char>>; |
178 | | using wcsv_stream_reader = basic_csv_reader<wchar_t,stream_source<wchar_t>>; |
179 | | |
180 | | }} |
181 | | |
182 | | #endif |