aboutsummaryrefslogtreecommitdiff
path: root/include/jsoncons/sink.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'include/jsoncons/sink.hpp')
-rw-r--r--include/jsoncons/sink.hpp289
1 files changed, 289 insertions, 0 deletions
diff --git a/include/jsoncons/sink.hpp b/include/jsoncons/sink.hpp
new file mode 100644
index 0000000..84771a3
--- /dev/null
+++ b/include/jsoncons/sink.hpp
@@ -0,0 +1,289 @@
+// 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_SINK_HPP
+#define JSONCONS_SINK_HPP
+
+#include <stdexcept>
+#include <string>
+#include <vector>
+#include <ostream>
+#include <cmath>
+#include <exception>
+#include <memory> // std::addressof
+#include <cstring> // std::memcpy
+#include <jsoncons/config/jsoncons_config.hpp>
+#include <jsoncons/more_type_traits.hpp>
+
+namespace jsoncons {
+
+ // stream_sink
+
+ template <class CharT>
+ class stream_sink
+ {
+ public:
+ using value_type = CharT;
+ using container_type = std::basic_ostream<CharT>;
+
+ private:
+ static constexpr size_t default_buffer_length = 16384;
+
+ std::basic_ostream<CharT>* stream_ptr_;
+ std::vector<CharT> buffer_;
+ CharT * begin_buffer_;
+ const CharT* end_buffer_;
+ CharT* p_;
+
+ // Noncopyable
+ stream_sink(const stream_sink&) = delete;
+ stream_sink& operator=(const stream_sink&) = delete;
+
+ public:
+ stream_sink(stream_sink&&) = default;
+
+ stream_sink(std::basic_ostream<CharT>& os)
+ : stream_ptr_(std::addressof(os)), buffer_(default_buffer_length), begin_buffer_(buffer_.data()), end_buffer_(begin_buffer_+buffer_.size()), p_(begin_buffer_)
+ {
+ }
+ stream_sink(std::basic_ostream<CharT>& os, std::size_t buflen)
+ : stream_ptr_(std::addressof(os)), buffer_(buflen), begin_buffer_(buffer_.data()), end_buffer_(begin_buffer_+buffer_.size()), p_(begin_buffer_)
+ {
+ }
+ ~stream_sink() noexcept
+ {
+ stream_ptr_->write(begin_buffer_, buffer_length());
+ stream_ptr_->flush();
+ }
+
+ // Movable
+ stream_sink& operator=(stream_sink&&) = default;
+
+ void flush()
+ {
+ stream_ptr_->write(begin_buffer_, buffer_length());
+ stream_ptr_->flush();
+ p_ = buffer_.data();
+ }
+
+ void append(const CharT* s, std::size_t length)
+ {
+ std::size_t diff = end_buffer_ - p_;
+ if (diff >= length)
+ {
+ std::memcpy(p_, s, length*sizeof(CharT));
+ p_ += length;
+ }
+ else
+ {
+ stream_ptr_->write(begin_buffer_, buffer_length());
+ stream_ptr_->write(s,length);
+ p_ = begin_buffer_;
+ }
+ }
+
+ void push_back(CharT ch)
+ {
+ if (p_ < end_buffer_)
+ {
+ *p_++ = ch;
+ }
+ else
+ {
+ stream_ptr_->write(begin_buffer_, buffer_length());
+ p_ = begin_buffer_;
+ push_back(ch);
+ }
+ }
+ private:
+
+ std::size_t buffer_length() const
+ {
+ return p_ - begin_buffer_;
+ }
+ };
+
+ // binary_stream_sink
+
+ class binary_stream_sink
+ {
+ public:
+ typedef uint8_t value_type;
+ using container_type = std::basic_ostream<char>;
+ private:
+ static constexpr size_t default_buffer_length = 16384;
+
+ std::basic_ostream<char>* stream_ptr_;
+ std::vector<uint8_t> buffer_;
+ uint8_t * begin_buffer_;
+ const uint8_t* end_buffer_;
+ uint8_t* p_;
+
+ // Noncopyable
+ binary_stream_sink(const binary_stream_sink&) = delete;
+ binary_stream_sink& operator=(const binary_stream_sink&) = delete;
+
+ public:
+ binary_stream_sink(binary_stream_sink&&) = default;
+
+ binary_stream_sink(std::basic_ostream<char>& os)
+ : stream_ptr_(std::addressof(os)),
+ buffer_(default_buffer_length),
+ begin_buffer_(buffer_.data()),
+ end_buffer_(begin_buffer_+buffer_.size()),
+ p_(begin_buffer_)
+ {
+ }
+ binary_stream_sink(std::basic_ostream<char>& os, std::size_t buflen)
+ : stream_ptr_(std::addressof(os)),
+ buffer_(buflen),
+ begin_buffer_(buffer_.data()),
+ end_buffer_(begin_buffer_+buffer_.size()),
+ p_(begin_buffer_)
+ {
+ }
+ ~binary_stream_sink() noexcept
+ {
+ stream_ptr_->write((char*)begin_buffer_, buffer_length());
+ stream_ptr_->flush();
+ }
+
+ binary_stream_sink& operator=(binary_stream_sink&&) = default;
+
+ void flush()
+ {
+ stream_ptr_->write((char*)begin_buffer_, buffer_length());
+ p_ = buffer_.data();
+ }
+
+ void append(const uint8_t* s, std::size_t length)
+ {
+ std::size_t diff = end_buffer_ - p_;
+ if (diff >= length)
+ {
+ std::memcpy(p_, s, length*sizeof(uint8_t));
+ p_ += length;
+ }
+ else
+ {
+ stream_ptr_->write((char*)begin_buffer_, buffer_length());
+ stream_ptr_->write((const char*)s,length);
+ p_ = begin_buffer_;
+ }
+ }
+
+ void push_back(uint8_t ch)
+ {
+ if (p_ < end_buffer_)
+ {
+ *p_++ = ch;
+ }
+ else
+ {
+ stream_ptr_->write((char*)begin_buffer_, buffer_length());
+ p_ = begin_buffer_;
+ push_back(ch);
+ }
+ }
+ private:
+
+ std::size_t buffer_length() const
+ {
+ return p_ - begin_buffer_;
+ }
+ };
+
+ // string_sink
+
+ template <class StringT>
+ class string_sink
+ {
+ public:
+ using value_type = typename StringT::value_type;
+ using container_type = StringT;
+ private:
+ container_type* buf_ptr;
+
+ // Noncopyable
+ string_sink(const string_sink&) = delete;
+ string_sink& operator=(const string_sink&) = delete;
+ public:
+ string_sink(string_sink&& val) noexcept
+ : buf_ptr(nullptr)
+ {
+ std::swap(buf_ptr,val.buf_ptr);
+ }
+
+ string_sink(container_type& buf)
+ : buf_ptr(std::addressof(buf))
+ {
+ }
+
+ string_sink& operator=(string_sink&& val) noexcept
+ {
+ // TODO: Shouldn't val.buf_ptr be nullified?
+ // Also see move constructor above.
+ std::swap(buf_ptr,val.buf_ptr);
+ return *this;
+ }
+
+ void flush()
+ {
+ }
+
+ void append(const value_type* s, std::size_t length)
+ {
+ buf_ptr->insert(buf_ptr->end(), s, s+length);
+ }
+
+ void push_back(value_type ch)
+ {
+ buf_ptr->push_back(ch);
+ }
+ };
+
+ // bytes_sink
+
+ template <class Container, class = void>
+ class bytes_sink
+ {
+ };
+
+ template <class Container>
+ class bytes_sink<Container,typename std::enable_if<type_traits::is_back_insertable_byte_container<Container>::value>::type>
+ {
+ public:
+ using container_type = Container;
+ using value_type = typename Container::value_type;
+ private:
+ container_type* buf_ptr;
+
+ // Noncopyable
+ bytes_sink(const bytes_sink&) = delete;
+ bytes_sink& operator=(const bytes_sink&) = delete;
+ public:
+ bytes_sink(bytes_sink&&) = default;
+
+ bytes_sink(container_type& buf)
+ : buf_ptr(std::addressof(buf))
+ {
+ }
+
+ bytes_sink& operator=(bytes_sink&&) = default;
+
+ void flush()
+ {
+ }
+
+ void push_back(uint8_t ch)
+ {
+ buf_ptr->push_back(static_cast<value_type>(ch));
+ }
+ };
+
+} // namespace jsoncons
+
+#endif