/src/jsoncons/include/jsoncons_ext/csv/csv_reader.hpp
Line | Count | Source |
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_util.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 | | template <typename Sourceable> |
58 | | basic_csv_reader(Sourceable&& source, |
59 | | basic_json_visitor<CharT>& visitor, |
60 | | const basic_csv_decode_options<CharT>& options = basic_csv_decode_options<CharT>{}, |
61 | | const Allocator& alloc = Allocator()) |
62 | 2.61k | : source_(std::forward<Sourceable>(source)), |
63 | 2.61k | visitor_(visitor), |
64 | 2.61k | parser_(options, alloc) |
65 | | |
66 | 2.61k | { |
67 | 2.61k | } |
68 | | |
69 | | template <typename Sourceable> |
70 | | basic_csv_reader(Sourceable&& source, |
71 | | basic_json_visitor<CharT>& visitor, |
72 | | const Allocator& alloc = Allocator()) |
73 | | : basic_csv_reader(std::forward<Sourceable>(source), |
74 | | visitor, |
75 | | basic_csv_decode_options<CharT>(), |
76 | | alloc) |
77 | | { |
78 | | } |
79 | | |
80 | | #if !defined(JSONCONS_NO_DEPRECATED) |
81 | | |
82 | | template <typename Sourceable> |
83 | | basic_csv_reader(Sourceable&& source, |
84 | | basic_json_visitor<CharT>& visitor, |
85 | | const basic_csv_decode_options<CharT>& options, |
86 | | std::function<bool(csv_errc,const ser_context&)> err_handler, |
87 | | const Allocator& alloc = Allocator()) |
88 | | : source_(std::forward<Sourceable>(source)), |
89 | | visitor_(visitor), |
90 | | parser_(options, err_handler, alloc) |
91 | | |
92 | | { |
93 | | } |
94 | | |
95 | | template <typename Sourceable> |
96 | | basic_csv_reader(Sourceable&& source, |
97 | | basic_json_visitor<CharT>& visitor, |
98 | | std::function<bool(csv_errc,const ser_context&)> err_handler, |
99 | | const Allocator& alloc = Allocator()) |
100 | | : basic_csv_reader(std::forward<Sourceable>(source), |
101 | | visitor, |
102 | | basic_csv_decode_options<CharT>(), |
103 | | err_handler, |
104 | | alloc) |
105 | | { |
106 | | } |
107 | | #endif |
108 | | |
109 | 2.61k | ~basic_csv_reader() noexcept = default; |
110 | | |
111 | | void read() |
112 | 2.61k | { |
113 | 2.61k | std::error_code ec; |
114 | 2.61k | read(ec); |
115 | 2.61k | if (JSONCONS_UNLIKELY(ec)) |
116 | 93 | { |
117 | 93 | JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column())); |
118 | 93 | } |
119 | 2.61k | } |
120 | | |
121 | | void read(std::error_code& ec) |
122 | 2.61k | { |
123 | 2.61k | read_internal(ec); |
124 | 2.61k | } |
125 | | |
126 | | std::size_t line() const |
127 | | { |
128 | | return parser_.line(); |
129 | | } |
130 | | |
131 | | std::size_t column() const |
132 | | { |
133 | | return parser_.column(); |
134 | | } |
135 | | |
136 | | bool eof() const |
137 | | { |
138 | | return parser_.source_exhausted() && source_.eof(); |
139 | | } |
140 | | |
141 | | private: |
142 | | |
143 | | void read_internal(std::error_code& ec) |
144 | 2.61k | { |
145 | 2.61k | if (source_.is_error()) |
146 | 0 | { |
147 | 0 | ec = csv_errc::source_error; |
148 | 0 | return; |
149 | 0 | } |
150 | 19.5k | while (!parser_.stopped()) |
151 | 17.0k | { |
152 | 17.0k | if (parser_.source_exhausted()) |
153 | 17.0k | { |
154 | 17.0k | auto s = source_.read_buffer(ec); |
155 | 17.0k | if (JSONCONS_UNLIKELY(ec)) return; |
156 | 17.0k | if (s.size() > 0) |
157 | 2.60k | { |
158 | 2.60k | parser_.update(s.data(),s.size()); |
159 | 2.60k | } |
160 | 17.0k | } |
161 | 17.0k | parser_.parse_some(visitor_, ec); |
162 | 17.0k | if (JSONCONS_UNLIKELY(ec)) return; |
163 | 17.0k | } |
164 | 2.61k | } |
165 | | }; |
166 | | |
167 | | using csv_string_reader = basic_csv_reader<char,string_source<char>>; |
168 | | using wcsv_string_reader = basic_csv_reader<wchar_t,string_source<wchar_t>>; |
169 | | using csv_stream_reader = basic_csv_reader<char,stream_source<char>>; |
170 | | using wcsv_stream_reader = basic_csv_reader<wchar_t,stream_source<wchar_t>>; |
171 | | |
172 | | }} |
173 | | |
174 | | #endif |