// // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // Official repository: https://github.com/boostorg/json // #ifndef BOOST_JSON_DETAIL_STREAM_HPP #define BOOST_JSON_DETAIL_STREAM_HPP BOOST_JSON_NS_BEGIN namespace detail { class const_stream { friend class local_const_stream; char const* p_; char const* end_; public: const_stream() = default; const_stream( const_stream const&) = default; const_stream( char const* data, std::size_t size) noexcept : p_(data) , end_(data + size) { } size_t used(char const* begin) const noexcept { return static_cast< size_t>(p_ - begin); } size_t remain() const noexcept { return end_ - p_; } char const* data() const noexcept { return p_; } operator bool() const noexcept { return p_ < end_; } // unchecked char operator*() const noexcept { BOOST_ASSERT(p_ < end_); return *p_; } // unchecked const_stream& operator++() noexcept { BOOST_ASSERT(p_ < end_); ++p_; return *this; } void skip(std::size_t n) noexcept { BOOST_ASSERT(n <= remain()); p_ += n; } void skip_to(const char* p) noexcept { BOOST_ASSERT(p <= end_ && p >= p_); p_ = p; } }; class local_const_stream : public const_stream { const_stream& src_; public: explicit local_const_stream( const_stream& src) noexcept : const_stream(src) , src_(src) { } ~local_const_stream() { src_.p_ = p_; } void clip(std::size_t n) noexcept { if(static_cast( src_.end_ - p_) > n) end_ = p_ + n; else end_ = src_.end_; } }; class const_stream_wrapper { const char*& p_; const char* const end_; friend class clipped_const_stream; public: const_stream_wrapper( const char*& p, const char* end) : p_(p) , end_(end) { } void operator++() noexcept { ++p_; } void operator+=(std::size_t n) noexcept { p_ += n; } void operator=(const char* p) noexcept { p_ = p; } char operator*() const noexcept { return *p_; } operator bool() const noexcept { return p_ < end_; } const char* begin() const noexcept { return p_; } const char* end() const noexcept { return end_; } std::size_t remain() const noexcept { return end_ - p_; } std::size_t remain(const char* p) const noexcept { return end_ - p; } std::size_t used(const char* p) const noexcept { return p_ - p; } }; class clipped_const_stream : public const_stream_wrapper { const char* clip_; public: clipped_const_stream( const char*& p, const char* end) : const_stream_wrapper(p, end) , clip_(end) { } void operator=(const char* p) { p_ = p; } const char* end() const noexcept { return clip_; } operator bool() const noexcept { return p_ < clip_; } std::size_t remain() const noexcept { return clip_ - p_; } std::size_t remain(const char* p) const noexcept { return clip_ - p; } void clip(std::size_t n) noexcept { if(static_cast( end_ - p_) > n) clip_ = p_ + n; else clip_ = end_; } }; //-------------------------------------- class stream { friend class local_stream; char* p_; char* end_; public: stream( stream const&) = default; stream( char* data, std::size_t size) noexcept : p_(data) , end_(data + size) { } size_t used(char* begin) const noexcept { return static_cast< size_t>(p_ - begin); } size_t remain() const noexcept { return end_ - p_; } char* data() noexcept { return p_; } operator bool() const noexcept { return p_ < end_; } // unchecked char& operator*() noexcept { BOOST_ASSERT(p_ < end_); return *p_; } // unchecked stream& operator++() noexcept { BOOST_ASSERT(p_ < end_); ++p_; return *this; } // unchecked void append( char const* src, std::size_t n) noexcept { BOOST_ASSERT(remain() >= n); std::memcpy(p_, src, n); p_ += n; } // unchecked void append(char c) noexcept { BOOST_ASSERT(p_ < end_); *p_++ = c; } void advance(std::size_t n) noexcept { BOOST_ASSERT(remain() >= n); p_ += n; } }; class local_stream : public stream { stream& src_; public: explicit local_stream( stream& src) : stream(src) , src_(src) { } ~local_stream() { src_.p_ = p_; } }; } // detail BOOST_JSON_NS_END #endif