// 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_SOURCE_HPP #define JSONCONS_SOURCE_HPP #include #include #include #include #include // std::addressof #include // std::memcpy #include #include #include // std::enable_if #include #include // jsoncons::byte_traits #include namespace jsoncons { template class basic_null_istream : public std::basic_istream { class null_buffer : public std::basic_streambuf { null_buffer(const null_buffer&) = delete; null_buffer& operator=(const null_buffer&) = delete; public: using typename std::basic_streambuf::int_type; using typename std::basic_streambuf::traits_type; null_buffer() = default; null_buffer(null_buffer&&) = default; null_buffer& operator=(null_buffer&&) = default; int_type overflow( int_type ch = typename std::basic_streambuf::traits_type::eof() ) override { return ch; } } nb_; public: basic_null_istream() : std::basic_istream(&nb_) { } basic_null_istream(const null_buffer&) = delete; basic_null_istream& operator=(const null_buffer&) = delete; basic_null_istream(basic_null_istream&&) noexcept : std::basic_istream(&nb_) { } basic_null_istream& operator=(basic_null_istream&&) noexcept { return *this; } }; template struct char_result { CharT value; bool eof; }; // text sources template class stream_source { static constexpr std::size_t default_max_buffer_size = 16384; public: using value_type = CharT; private: using char_type = typename std::conditional::type; basic_null_istream null_is_; std::basic_istream* stream_ptr_; std::basic_streambuf* sbuf_; std::size_t position_; std::vector buffer_; const value_type* buffer_data_; std::size_t buffer_length_; // Noncopyable stream_source(const stream_source&) = delete; stream_source& operator=(const stream_source&) = delete; public: stream_source() : stream_ptr_(&null_is_), sbuf_(null_is_.rdbuf()), position_(0), buffer_(1), buffer_data_(buffer_.data()), buffer_length_(0) { } stream_source(std::basic_istream& is, std::size_t buf_size = default_max_buffer_size) : stream_ptr_(std::addressof(is)), sbuf_(is.rdbuf()), position_(0), buffer_(buf_size), buffer_data_(buffer_.data()), buffer_length_(0) { } stream_source(stream_source&& other) noexcept : stream_ptr_(&null_is_), sbuf_(null_is_.rdbuf()), position_(0), buffer_(), buffer_data_(buffer_.data()), buffer_length_(0) { if (other.stream_ptr_ != &other.null_is_) { stream_ptr_ = other.stream_ptr_; sbuf_ = other.sbuf_; position_ = other.position_; buffer_ = std::move(other.buffer_); buffer_data_ = buffer_.data() + (other.buffer_data_ - other.buffer_.data()); buffer_length_ = other.buffer_length_; other = stream_source(); } } ~stream_source() { } stream_source& operator=(stream_source&& other) noexcept { if (other.stream_ptr_ != &other.null_is_) { stream_ptr_ = other.stream_ptr_; sbuf_ = other.sbuf_; position_ = other.position_; buffer_ = std::move(other.buffer_); buffer_data_ = buffer_.data() + (other.buffer_data_ - other.buffer_.data()); buffer_length_ = other.buffer_length_; other = stream_source(); } else { stream_ptr_ = &null_is_; sbuf_ = null_is_.rdbuf(); position_ = 0; buffer_data_ = buffer_.data(); buffer_length_ = 0; } return *this; } bool eof() const { return buffer_length_ == 0 && stream_ptr_->eof(); } bool is_error() const { return stream_ptr_->bad(); } std::size_t position() const { return position_; } void ignore(std::size_t length) { std::size_t len = 0; if (buffer_length_ > 0) { len = (std::min)(buffer_length_, length); position_ += len; buffer_data_ += len; buffer_length_ -= len; } while (length - len > 0) { fill_buffer(); if (buffer_length_ == 0) { break; } std::size_t len2 = (std::min)(buffer_length_, length-len); position_ += len2; buffer_data_ += len2; buffer_length_ -= len2; len += len2; } } char_result peek() { if (buffer_length_ == 0) { fill_buffer(); } if (buffer_length_ > 0) { value_type c = *buffer_data_; return char_result{c, false}; } else { return char_result{0, true}; } } span read_buffer() { if (buffer_length_ == 0) { fill_buffer(); } const value_type* data = buffer_data_; std::size_t length = buffer_length_; buffer_data_ += buffer_length_; position_ += buffer_length_; buffer_length_ = 0; return span(data, length); } std::size_t read(value_type* p, std::size_t length) { std::size_t len = 0; if (buffer_length_ > 0) { len = (std::min)(buffer_length_, length); std::memcpy(p, buffer_data_, len*sizeof(value_type)); buffer_data_ += len; buffer_length_ -= len; position_ += len; } if (length - len == 0) { return len; } else if (length - len < buffer_.size()) { fill_buffer(); if (buffer_length_ > 0) { std::size_t len2 = (std::min)(buffer_length_, length-len); std::memcpy(p+len, buffer_data_, len2*sizeof(value_type)); buffer_data_ += len2; buffer_length_ -= len2; position_ += len2; len += len2; } return len; } else { if (stream_ptr_->eof()) { buffer_length_ = 0; return 0; } JSONCONS_TRY { std::streamsize count = sbuf_->sgetn(reinterpret_cast(p+len), length-len); std::size_t len2 = static_cast(count); if (len2 < length-len) { stream_ptr_->clear(stream_ptr_->rdstate() | std::ios::eofbit); } len += len2; position_ += len2; return len; } JSONCONS_CATCH(const std::exception&) { stream_ptr_->clear(stream_ptr_->rdstate() | std::ios::badbit | std::ios::eofbit); return 0; } } } private: void fill_buffer() { if (stream_ptr_->eof()) { buffer_length_ = 0; return; } buffer_data_ = buffer_.data(); JSONCONS_TRY { std::streamsize count = sbuf_->sgetn(reinterpret_cast(buffer_.data()), buffer_.size()); buffer_length_ = static_cast(count); if (buffer_length_ < buffer_.size()) { stream_ptr_->clear(stream_ptr_->rdstate() | std::ios::eofbit); } } JSONCONS_CATCH(const std::exception&) { stream_ptr_->clear(stream_ptr_->rdstate() | std::ios::badbit | std::ios::eofbit); buffer_length_ = 0; } } }; // string_source template class string_source { public: using value_type = CharT; using string_view_type = jsoncons::basic_string_view; private: const value_type* data_; const value_type* current_; const value_type* end_; // Noncopyable string_source(const string_source&) = delete; string_source& operator=(const string_source&) = delete; public: string_source() : data_(nullptr), current_(nullptr), end_(nullptr) { } template string_source(const Sourceable& s, typename std::enable_if::value>::type* = 0) : data_(s.data()), current_(s.data()), end_(s.data()+s.size()) { } string_source(const value_type* data) : data_(data), current_(data), end_(data+std::char_traits::length(data)) { } string_source(string_source&& val) = default; string_source& operator=(string_source&& val) = default; bool eof() const { return current_ == end_; } bool is_error() const { return false; } std::size_t position() const { return (current_ - data_)/sizeof(value_type); } void ignore(std::size_t count) { std::size_t len; if ((std::size_t)(end_ - current_) < count) { len = end_ - current_; } else { len = count; } current_ += len; } char_result peek() { return current_ < end_ ? char_result{*current_, false} : char_result{0, true}; } span read_buffer() { const value_type* data = current_; std::size_t length = end_ - current_; current_ = end_; return span(data, length); } std::size_t read(value_type* p, std::size_t length) { std::size_t len; if ((std::size_t)(end_ - current_) < length) { len = end_ - current_; } else { len = length; } std::memcpy(p, current_, len*sizeof(value_type)); current_ += len; return len; } }; // iterator source template class iterator_source { public: using value_type = typename std::iterator_traits::value_type; private: static constexpr std::size_t default_max_buffer_size = 16384; IteratorT current_; IteratorT end_; std::size_t position_; std::vector buffer_; std::size_t buffer_length_; using difference_type = typename std::iterator_traits::difference_type; using iterator_category = typename std::iterator_traits::iterator_category; // Noncopyable iterator_source(const iterator_source&) = delete; iterator_source& operator=(const iterator_source&) = delete; public: iterator_source(const IteratorT& first, const IteratorT& last, std::size_t buf_size = default_max_buffer_size) : current_(first), end_(last), position_(0), buffer_(buf_size), buffer_length_(0) { } iterator_source(iterator_source&& other) = default; iterator_source& operator=(iterator_source&& other) = default; bool eof() const { return !(current_ != end_); } bool is_error() const { return false; } std::size_t position() const { return position_; } void ignore(std::size_t count) { while (count-- > 0 && current_ != end_) { ++position_; ++current_; } } char_result peek() { return current_ != end_ ? char_result{*current_, false} : char_result{0, true}; } span read_buffer() { if (buffer_length_ == 0) { buffer_length_ = read(buffer_.data(), buffer_.size()); } std::size_t length = buffer_length_; buffer_length_ = 0; return span(buffer_.data(), length); } template typename std::enable_if::value, std::size_t>::type read(value_type* data, std::size_t length) { std::size_t count = (std::min)(length, static_cast(std::distance(current_, end_))); JSONCONS_COPY(current_, current_ + count, data); current_ += count; position_ += count; return count; } template typename std::enable_if::value, std::size_t>::type read(value_type* data, std::size_t length) { value_type* p = data; value_type* pend = data + length; while (p < pend && current_ != end_) { *p = static_cast(*current_); ++p; ++current_; } position_ += (p - data); return p - data; } }; // binary sources using binary_stream_source = stream_source; class bytes_source { public: typedef uint8_t value_type; private: const value_type* data_; const value_type* current_; const value_type* end_; // Noncopyable bytes_source(const bytes_source&) = delete; bytes_source& operator=(const bytes_source&) = delete; public: bytes_source() : data_(nullptr), current_(nullptr), end_(nullptr) { } template bytes_source(const Sourceable& source, typename std::enable_if::value,int>::type = 0) : data_(reinterpret_cast(source.data())), current_(data_), end_(data_+source.size()) { } bytes_source(bytes_source&&) = default; bytes_source& operator=(bytes_source&&) = default; bool eof() const { return current_ == end_; } bool is_error() const { return false; } std::size_t position() const { return current_ - data_; } void ignore(std::size_t count) { std::size_t len; if ((std::size_t)(end_ - current_) < count) { len = end_ - current_; } else { len = count; } current_ += len; } char_result peek() { return current_ < end_ ? char_result{*current_, false} : char_result{0, true}; } span read_buffer() { const value_type* data = current_; std::size_t length = end_ - current_; current_ = end_; return span(data, length); } std::size_t read(value_type* p, std::size_t length) { std::size_t len; if ((std::size_t)(end_ - current_) < length) { len = end_ - current_; } else { len = length; } std::memcpy(p, current_, len*sizeof(value_type)); current_ += len; return len; } }; // binary_iterator source template class binary_iterator_source { public: using value_type = uint8_t; private: static constexpr std::size_t default_max_buffer_size = 16384; IteratorT current_; IteratorT end_; std::size_t position_; std::vector buffer_; std::size_t buffer_length_; using difference_type = typename std::iterator_traits::difference_type; using iterator_category = typename std::iterator_traits::iterator_category; // Noncopyable binary_iterator_source(const binary_iterator_source&) = delete; binary_iterator_source& operator=(const binary_iterator_source&) = delete; public: binary_iterator_source(const IteratorT& first, const IteratorT& last, std::size_t buf_size = default_max_buffer_size) : current_(first), end_(last), position_(0), buffer_(buf_size), buffer_length_(0) { } binary_iterator_source(binary_iterator_source&& other) = default; binary_iterator_source& operator=(binary_iterator_source&& other) = default; bool eof() const { return !(current_ != end_); } bool is_error() const { return false; } std::size_t position() const { return position_; } void ignore(std::size_t count) { while (count-- > 0 && current_ != end_) { ++position_; ++current_; } } char_result peek() { return current_ != end_ ? char_result{static_cast(*current_), false} : char_result{0, true}; } span read_buffer() { if (buffer_length_ == 0) { buffer_length_ = read(buffer_.data(), buffer_.size()); } std::size_t length = buffer_length_; buffer_length_ = 0; return span(buffer_.data(), length); } template typename std::enable_if::value, std::size_t>::type read(value_type* data, std::size_t length) { std::size_t count = (std::min)(length, static_cast(std::distance(current_, end_))); JSONCONS_COPY(current_, current_ + count, data); current_ += count; position_ += count; return count; } template typename std::enable_if::value, std::size_t>::type read(value_type* data, std::size_t length) { value_type* p = data; value_type* pend = data + length; while (p < pend && current_ != end_) { *p = static_cast(*current_); ++p; ++current_; } position_ += (p - data); return p - data; } }; template struct source_reader { using value_type = typename Source::value_type; static constexpr std::size_t max_buffer_length = 16384; template static typename std::enable_if::value && type_traits::has_reserve::value && type_traits::has_data_exact::value , std::size_t>::type read(Source& source, Container& v, std::size_t length) { std::size_t unread = length; std::size_t n = (std::min)(max_buffer_length, unread); while (n > 0 && !source.eof()) { std::size_t offset = v.size(); v.resize(v.size()+n); std::size_t actual = source.read(v.data()+offset, n); unread -= actual; n = (std::min)(max_buffer_length, unread); } return length - unread; } template static typename std::enable_if::value && type_traits::has_reserve::value && !type_traits::has_data_exact::value , std::size_t>::type read(Source& source, Container& v, std::size_t length) { std::size_t unread = length; std::size_t n = (std::min)(max_buffer_length, unread); while (n > 0 && !source.eof()) { v.reserve(v.size()+n); std::size_t actual = 0; while (actual < n) { typename Source::value_type c; if (source.read(&c,1) != 1) { break; } v.push_back(c); ++actual; } unread -= actual; n = (std::min)(max_buffer_length, unread); } return length - unread; } }; template constexpr std::size_t source_reader::max_buffer_length; #if !defined(JSONCONS_NO_DEPRECATED) using bin_stream_source = binary_stream_source; #endif } // namespace jsoncons #endif