aboutsummaryrefslogtreecommitdiff
path: root/include/jsoncons/source.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'include/jsoncons/source.hpp')
-rw-r--r--include/jsoncons/source.hpp777
1 files changed, 777 insertions, 0 deletions
diff --git a/include/jsoncons/source.hpp b/include/jsoncons/source.hpp
new file mode 100644
index 0000000..e9c0735
--- /dev/null
+++ b/include/jsoncons/source.hpp
@@ -0,0 +1,777 @@
+// 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 <stdexcept>
+#include <string>
+#include <vector>
+#include <istream>
+#include <memory> // std::addressof
+#include <cstring> // std::memcpy
+#include <exception>
+#include <iterator>
+#include <type_traits> // std::enable_if
+#include <jsoncons/config/jsoncons_config.hpp>
+#include <jsoncons/byte_string.hpp> // jsoncons::byte_traits
+#include <jsoncons/more_type_traits.hpp>
+
+namespace jsoncons {
+
+ template <class CharT>
+ class basic_null_istream : public std::basic_istream<CharT>
+ {
+ class null_buffer : public std::basic_streambuf<CharT>
+ {
+ null_buffer(const null_buffer&) = delete;
+ null_buffer& operator=(const null_buffer&) = delete;
+ public:
+ using typename std::basic_streambuf<CharT>::int_type;
+ using typename std::basic_streambuf<CharT>::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<CharT>::traits_type::eof() ) override
+ {
+ return ch;
+ }
+ } nb_;
+ public:
+ basic_null_istream()
+ : std::basic_istream<CharT>(&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<CharT>(&nb_)
+ {
+ }
+ basic_null_istream& operator=(basic_null_istream&&) noexcept
+ {
+ return *this;
+ }
+ };
+
+ template <class CharT>
+ struct char_result
+ {
+ CharT value;
+ bool eof;
+ };
+
+ // text sources
+
+ template <class CharT>
+ 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<sizeof(CharT) == sizeof(char),char,CharT>::type;
+ basic_null_istream<char_type> null_is_;
+ std::basic_istream<char_type>* stream_ptr_;
+ std::basic_streambuf<char_type>* sbuf_;
+ std::size_t position_;
+ std::vector<value_type> 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<char_type>& 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<value_type> peek()
+ {
+ if (buffer_length_ == 0)
+ {
+ fill_buffer();
+ }
+ if (buffer_length_ > 0)
+ {
+ value_type c = *buffer_data_;
+ return char_result<value_type>{c, false};
+ }
+ else
+ {
+ return char_result<value_type>{0, true};
+ }
+ }
+
+ span<const value_type> 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<const value_type>(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<char_type*>(p+len), length-len);
+ std::size_t len2 = static_cast<std::size_t>(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<char_type*>(buffer_.data()), buffer_.size());
+ buffer_length_ = static_cast<std::size_t>(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 CharT>
+ class string_source
+ {
+ public:
+ using value_type = CharT;
+ using string_view_type = jsoncons::basic_string_view<value_type>;
+ 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 <class Sourceable>
+ string_source(const Sourceable& s,
+ typename std::enable_if<type_traits::is_sequence_of<Sourceable,value_type>::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<value_type>::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<value_type> peek()
+ {
+ return current_ < end_ ? char_result<value_type>{*current_, false} : char_result<value_type>{0, true};
+ }
+
+ span<const value_type> read_buffer()
+ {
+ const value_type* data = current_;
+ std::size_t length = end_ - current_;
+ current_ = end_;
+
+ return span<const value_type>(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 IteratorT>
+ class iterator_source
+ {
+ public:
+ using value_type = typename std::iterator_traits<IteratorT>::value_type;
+ private:
+ static constexpr std::size_t default_max_buffer_size = 16384;
+
+ IteratorT current_;
+ IteratorT end_;
+ std::size_t position_;
+ std::vector<value_type> buffer_;
+ std::size_t buffer_length_;
+
+ using difference_type = typename std::iterator_traits<IteratorT>::difference_type;
+ using iterator_category = typename std::iterator_traits<IteratorT>::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<value_type> peek()
+ {
+ return current_ != end_ ? char_result<value_type>{*current_, false} : char_result<value_type>{0, true};
+ }
+
+ span<const value_type> read_buffer()
+ {
+ if (buffer_length_ == 0)
+ {
+ buffer_length_ = read(buffer_.data(), buffer_.size());
+ }
+ std::size_t length = buffer_length_;
+ buffer_length_ = 0;
+
+ return span<const value_type>(buffer_.data(), length);
+ }
+
+ template <class Category = iterator_category>
+ typename std::enable_if<std::is_same<Category,std::random_access_iterator_tag>::value, std::size_t>::type
+ read(value_type* data, std::size_t length)
+ {
+ std::size_t count = (std::min)(length, static_cast<std::size_t>(std::distance(current_, end_)));
+
+ JSONCONS_COPY(current_, current_ + count, data);
+ current_ += count;
+ position_ += count;
+
+ return count;
+ }
+
+ template <class Category = iterator_category>
+ typename std::enable_if<!std::is_same<Category,std::random_access_iterator_tag>::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<value_type>(*current_);
+ ++p;
+ ++current_;
+ }
+
+ position_ += (p - data);
+
+ return p - data;
+ }
+ };
+
+ // binary sources
+
+ using binary_stream_source = stream_source<uint8_t>;
+
+ 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 <class Sourceable>
+ bytes_source(const Sourceable& source,
+ typename std::enable_if<type_traits::is_byte_sequence<Sourceable>::value,int>::type = 0)
+ : data_(reinterpret_cast<const value_type*>(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<value_type> peek()
+ {
+ return current_ < end_ ? char_result<value_type>{*current_, false} : char_result<value_type>{0, true};
+ }
+
+ span<const value_type> read_buffer()
+ {
+ const value_type* data = current_;
+ std::size_t length = end_ - current_;
+ current_ = end_;
+
+ return span<const value_type>(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 IteratorT>
+ 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<value_type> buffer_;
+ std::size_t buffer_length_;
+
+ using difference_type = typename std::iterator_traits<IteratorT>::difference_type;
+ using iterator_category = typename std::iterator_traits<IteratorT>::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<value_type> peek()
+ {
+ return current_ != end_ ? char_result<value_type>{static_cast<value_type>(*current_), false} : char_result<value_type>{0, true};
+ }
+
+ span<const value_type> read_buffer()
+ {
+ if (buffer_length_ == 0)
+ {
+ buffer_length_ = read(buffer_.data(), buffer_.size());
+ }
+ std::size_t length = buffer_length_;
+ buffer_length_ = 0;
+
+ return span<const value_type>(buffer_.data(), length);
+ }
+
+ template <class Category = iterator_category>
+ typename std::enable_if<std::is_same<Category,std::random_access_iterator_tag>::value, std::size_t>::type
+ read(value_type* data, std::size_t length)
+ {
+ std::size_t count = (std::min)(length, static_cast<std::size_t>(std::distance(current_, end_)));
+ JSONCONS_COPY(current_, current_ + count, data);
+ current_ += count;
+ position_ += count;
+
+ return count;
+ }
+
+ template <class Category = iterator_category>
+ typename std::enable_if<!std::is_same<Category,std::random_access_iterator_tag>::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<value_type>(*current_);
+ ++p;
+ ++current_;
+ }
+
+ position_ += (p - data);
+
+ return p - data;
+ }
+ };
+
+ template <class Source>
+ struct source_reader
+ {
+ using value_type = typename Source::value_type;
+ static constexpr std::size_t max_buffer_length = 16384;
+
+ template <class Container>
+ static
+ typename std::enable_if<std::is_convertible<value_type,typename Container::value_type>::value &&
+ type_traits::has_reserve<Container>::value &&
+ type_traits::has_data_exact<value_type*,Container>::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 <class Container>
+ static
+ typename std::enable_if<std::is_convertible<value_type,typename Container::value_type>::value &&
+ type_traits::has_reserve<Container>::value &&
+ !type_traits::has_data_exact<value_type*, Container>::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 <class Source>
+ constexpr std::size_t source_reader<Source>::max_buffer_length;
+
+ #if !defined(JSONCONS_NO_DEPRECATED)
+ using bin_stream_source = binary_stream_source;
+ #endif
+
+} // namespace jsoncons
+
+#endif