// Copyright 2018 Daniel Parker // Distributed under the Boost license, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // See https://github.com/danielaparker/jsoncons for latest version #ifndef JSONCONS_CSV_CSV_CURSOR_HPP #define JSONCONS_CSV_CSV_CURSOR_HPP #include // std::allocator #include #include #include #include #include #include // std::basic_istream #include #include #include #include #include #include #include #include namespace jsoncons { namespace csv { template,class Allocator=std::allocator> class basic_csv_cursor : public basic_staj_cursor, private virtual ser_context { public: using source_type = Source; using char_type = CharT; using allocator_type = Allocator; private: static constexpr size_t default_max_buffer_size = 16384; typedef typename std::allocator_traits:: template rebind_alloc char_allocator_type; text_source_adaptor source_; basic_csv_parser parser_; basic_staj_visitor cursor_visitor_; // Noncopyable and nonmoveable basic_csv_cursor(const basic_csv_cursor&) = delete; basic_csv_cursor& operator=(const basic_csv_cursor&) = delete; public: using string_view_type = jsoncons::basic_string_view; // Constructors that throw parse exceptions template basic_csv_cursor(Sourceable&& source, const basic_csv_decode_options& options = basic_csv_decode_options(), std::function err_handler = default_csv_parsing(), const Allocator& alloc = Allocator(), typename std::enable_if,Sourceable>::value>::type* = 0) : source_(std::forward(source)), parser_(options,err_handler,alloc), cursor_visitor_(accept_all) { if (!done()) { next(); } } template basic_csv_cursor(Sourceable&& source, const basic_csv_decode_options& options = basic_csv_decode_options(), std::function err_handler = default_csv_parsing(), const Allocator& alloc = Allocator(), typename std::enable_if,Sourceable>::value>::type* = 0) : source_(), parser_(options,err_handler,alloc), cursor_visitor_(accept_all) { jsoncons::basic_string_view sv(std::forward(source)); initialize_with_string_view(sv); } // Constructors that set parse error codes template basic_csv_cursor(Sourceable&& source, std::error_code& ec) : basic_csv_cursor(std::allocator_arg, Allocator(), std::forward(source), basic_csv_decode_options(), default_csv_parsing(), ec) { } template basic_csv_cursor(Sourceable&& source, const basic_csv_decode_options& options, std::error_code& ec) : basic_csv_cursor(std::allocator_arg, Allocator(), std::forward(source), options, default_csv_parsing(), ec) { } template basic_csv_cursor(Sourceable&& source, const basic_csv_decode_options& options, std::function err_handler, std::error_code& ec) : basic_csv_cursor(std::allocator_arg, Allocator(), std::forward(source), options, err_handler, ec) { } template basic_csv_cursor(std::allocator_arg_t, const Allocator& alloc, Sourceable&& source, const basic_csv_decode_options& options, std::function err_handler, std::error_code& ec, typename std::enable_if,Sourceable>::value>::type* = 0) : source_(std::forward(source)), parser_(options,err_handler,alloc), cursor_visitor_(accept_all) { if (!done()) { next(ec); } } template basic_csv_cursor(std::allocator_arg_t, const Allocator& alloc, Sourceable&& source, const basic_csv_decode_options& options, std::function err_handler, std::error_code& ec, typename std::enable_if,Sourceable>::value>::type* = 0) : source_(), parser_(options,err_handler,alloc), cursor_visitor_(accept_all) { jsoncons::basic_string_view sv(std::forward(source)); initialize_with_string_view(sv, ec); } template typename std::enable_if,Sourceable>::value>::type reset(Sourceable&& source) { source_ = std::forward(source); parser_.reinitialize(); cursor_visitor_.reset(); if (!done()) { next(); } } template typename std::enable_if,Sourceable>::value>::type reset(Sourceable&& source) { source_ = {}; parser_.reinitialize(); cursor_visitor_.reset(); initialize_with_string_view(std::forward(source)); } template typename std::enable_if,Sourceable>::value>::type reset(Sourceable&& source, std::error_code& ec) { source_ = std::forward(source); parser_.reinitialize(); cursor_visitor_.reset(); if (!done()) { next(ec); } } template typename std::enable_if,Sourceable>::value>::type reset(Sourceable&& source, std::error_code& ec) { source_ = {}; parser_.reinitialize(); initialize_with_string_view(std::forward(source), ec); } bool done() const override { return parser_.done(); } const basic_staj_event& current() const override { return cursor_visitor_.event(); } void read_to(basic_json_visitor& visitor) override { std::error_code ec; read_to(visitor, ec); if (ec) { JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column())); } } void read_to(basic_json_visitor& visitor, std::error_code& ec) override { if (staj_to_saj_event(cursor_visitor_.event(), visitor, *this, ec)) { read_next(visitor, ec); } } void next() override { std::error_code ec; next(ec); if (ec) { JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column())); } } void next(std::error_code& ec) override { read_next(ec); } static bool accept_all(const basic_staj_event&, const ser_context&) { return true; } const ser_context& context() const override { return *this; } bool eof() const { return parser_.source_exhausted() && source_.eof(); } std::size_t line() const override { return parser_.line(); } std::size_t column() const override { return parser_.column(); } friend basic_staj_filter_view operator|(basic_csv_cursor& cursor, std::function&, const ser_context&)> pred) { return basic_staj_filter_view(cursor, pred); } #if !defined(JSONCONS_NO_DEPRECATED) JSONCONS_DEPRECATED_MSG("Instead, use read_to(basic_json_visitor&)") void read(basic_json_visitor& visitor) { read_to(visitor); } JSONCONS_DEPRECATED_MSG("Instead, use read_to(basic_json_visitor&, std::error_code&)") void read(basic_json_visitor& visitor, std::error_code& ec) { read_to(visitor, ec); } #endif private: void initialize_with_string_view(string_view_type sv) { auto r = unicode_traits::detect_json_encoding(sv.data(), sv.size()); if (!(r.encoding == unicode_traits::encoding_kind::utf8 || r.encoding == unicode_traits::encoding_kind::undetected)) { JSONCONS_THROW(ser_error(json_errc::illegal_unicode_character,parser_.line(),parser_.column())); } std::size_t offset = (r.ptr - sv.data()); parser_.update(sv.data()+offset,sv.size()-offset); if (!done()) { next(); } } void initialize_with_string_view(string_view_type sv, std::error_code& ec) { auto r = unicode_traits::detect_encoding_from_bom(sv.data(), sv.size()); if (!(r.encoding == unicode_traits::encoding_kind::utf8 || r.encoding == unicode_traits::encoding_kind::undetected)) { ec = json_errc::illegal_unicode_character; return; } std::size_t offset = (r.ptr - sv.data()); parser_.update(sv.data()+offset,sv.size()-offset); if (!done()) { next(ec); } } void read_next(std::error_code& ec) { read_next(cursor_visitor_, ec); } void read_next(basic_json_visitor& visitor, std::error_code& ec) { parser_.restart(); while (!parser_.stopped()) { if (parser_.source_exhausted()) { auto s = source_.read_buffer(ec); if (ec) return; if (s.size() > 0) { parser_.update(s.data(),s.size()); } } parser_.parse_some(visitor, ec); if (ec) return; } } }; using csv_stream_cursor = basic_csv_cursor>; using csv_string_cursor = basic_csv_cursor>; using wcsv_stream_cursor = basic_csv_cursor>; using wcsv_string_cursor = basic_csv_cursor>; using csv_cursor = basic_csv_cursor; using wcsv_cursor = basic_csv_cursor; }} #endif