| 1 | // Tencent is pleased to support the open source community by making RapidJSON available. |
| 2 | // |
| 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. |
| 4 | // |
| 5 | // Licensed under the MIT License (the "License"); you may not use this file except |
| 6 | // in compliance with the License. You may obtain a copy of the License at |
| 7 | // |
| 8 | // http://opensource.org/licenses/MIT |
| 9 | // |
| 10 | // Unless required by applicable law or agreed to in writing, software distributed |
| 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR |
| 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the |
| 13 | // specific language governing permissions and limitations under the License. |
| 14 | |
| 15 | #include "rapidjson.h" |
| 16 | |
| 17 | #ifndef RAPIDJSON_STREAM_H_ |
| 18 | #define RAPIDJSON_STREAM_H_ |
| 19 | |
| 20 | #include "encodings.h" |
| 21 | |
| 22 | RAPIDJSON_NAMESPACE_BEGIN |
| 23 | |
| 24 | /////////////////////////////////////////////////////////////////////////////// |
| 25 | // Stream |
| 26 | |
| 27 | /*! \class rapidjson::Stream |
| 28 | \brief Concept for reading and writing characters. |
| 29 | |
| 30 | For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd(). |
| 31 | |
| 32 | For write-only stream, only need to implement Put() and Flush(). |
| 33 | |
| 34 | \code |
| 35 | concept Stream { |
| 36 | typename Ch; //!< Character type of the stream. |
| 37 | |
| 38 | //! Read the current character from stream without moving the read cursor. |
| 39 | Ch Peek() const; |
| 40 | |
| 41 | //! Read the current character from stream and moving the read cursor to next character. |
| 42 | Ch Take(); |
| 43 | |
| 44 | //! Get the current read cursor. |
| 45 | //! \return Number of characters read from start. |
| 46 | size_t Tell(); |
| 47 | |
| 48 | //! Begin writing operation at the current read pointer. |
| 49 | //! \return The begin writer pointer. |
| 50 | Ch* PutBegin(); |
| 51 | |
| 52 | //! Write a character. |
| 53 | void Put(Ch c); |
| 54 | |
| 55 | //! Flush the buffer. |
| 56 | void Flush(); |
| 57 | |
| 58 | //! End the writing operation. |
| 59 | //! \param begin The begin write pointer returned by PutBegin(). |
| 60 | //! \return Number of characters written. |
| 61 | size_t PutEnd(Ch* begin); |
| 62 | } |
| 63 | \endcode |
| 64 | */ |
| 65 | |
| 66 | //! Provides additional information for stream. |
| 67 | /*! |
| 68 | By using traits pattern, this type provides a default configuration for stream. |
| 69 | For custom stream, this type can be specialized for other configuration. |
| 70 | See TEST(Reader, CustomStringStream) in readertest.cpp for example. |
| 71 | */ |
| 72 | template<typename Stream> |
| 73 | struct StreamTraits { |
| 74 | //! Whether to make local copy of stream for optimization during parsing. |
| 75 | /*! |
| 76 | By default, for safety, streams do not use local copy optimization. |
| 77 | Stream that can be copied fast should specialize this, like StreamTraits<StringStream>. |
| 78 | */ |
| 79 | enum { copyOptimization = 0 }; |
| 80 | }; |
| 81 | |
| 82 | //! Reserve n characters for writing to a stream. |
| 83 | template<typename Stream> |
| 84 | inline void PutReserve(Stream& stream, size_t count) { |
| 85 | (void)stream; |
| 86 | (void)count; |
| 87 | } |
| 88 | |
| 89 | //! Write character to a stream, presuming buffer is reserved. |
| 90 | template<typename Stream> |
| 91 | inline void PutUnsafe(Stream& stream, typename Stream::Ch c) { |
| 92 | stream.Put(c); |
| 93 | } |
| 94 | |
| 95 | //! Put N copies of a character to a stream. |
| 96 | template<typename Stream, typename Ch> |
| 97 | inline void PutN(Stream& stream, Ch c, size_t n) { |
| 98 | PutReserve(stream, n); |
| 99 | for (size_t i = 0; i < n; i++) |
| 100 | PutUnsafe(stream, c); |
| 101 | } |
| 102 | |
| 103 | /////////////////////////////////////////////////////////////////////////////// |
| 104 | // StringStream |
| 105 | |
| 106 | //! Read-only string stream. |
| 107 | /*! \note implements Stream concept |
| 108 | */ |
| 109 | template <typename Encoding> |
| 110 | struct GenericStringStream { |
| 111 | typedef typename Encoding::Ch Ch; |
| 112 | |
| 113 | GenericStringStream(const Ch *src) : src_(src), head_(src) {} |
| 114 | |
| 115 | Ch Peek() const { return *src_; } |
| 116 | Ch Take() { return *src_++; } |
| 117 | size_t Tell() const { return static_cast<size_t>(src_ - head_); } |
| 118 | |
| 119 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } |
| 120 | void Put(Ch) { RAPIDJSON_ASSERT(false); } |
| 121 | void Flush() { RAPIDJSON_ASSERT(false); } |
| 122 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } |
| 123 | |
| 124 | const Ch* src_; //!< Current read position. |
| 125 | const Ch* head_; //!< Original head of the string. |
| 126 | }; |
| 127 | |
| 128 | template <typename Encoding> |
| 129 | struct StreamTraits<GenericStringStream<Encoding> > { |
| 130 | enum { copyOptimization = 1 }; |
| 131 | }; |
| 132 | |
| 133 | //! String stream with UTF8 encoding. |
| 134 | typedef GenericStringStream<UTF8<> > StringStream; |
| 135 | |
| 136 | /////////////////////////////////////////////////////////////////////////////// |
| 137 | // InsituStringStream |
| 138 | |
| 139 | //! A read-write string stream. |
| 140 | /*! This string stream is particularly designed for in-situ parsing. |
| 141 | \note implements Stream concept |
| 142 | */ |
| 143 | template <typename Encoding> |
| 144 | struct GenericInsituStringStream { |
| 145 | typedef typename Encoding::Ch Ch; |
| 146 | |
| 147 | GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {} |
| 148 | |
| 149 | // Read |
| 150 | Ch Peek() { return *src_; } |
| 151 | Ch Take() { return *src_++; } |
| 152 | size_t Tell() { return static_cast<size_t>(src_ - head_); } |
| 153 | |
| 154 | // Write |
| 155 | void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } |
| 156 | |
| 157 | Ch* PutBegin() { return dst_ = src_; } |
| 158 | size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); } |
| 159 | void Flush() {} |
| 160 | |
| 161 | Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } |
| 162 | void Pop(size_t count) { dst_ -= count; } |
| 163 | |
| 164 | Ch* src_; |
| 165 | Ch* dst_; |
| 166 | Ch* head_; |
| 167 | }; |
| 168 | |
| 169 | template <typename Encoding> |
| 170 | struct StreamTraits<GenericInsituStringStream<Encoding> > { |
| 171 | enum { copyOptimization = 1 }; |
| 172 | }; |
| 173 | |
| 174 | //! Insitu string stream with UTF8 encoding. |
| 175 | typedef GenericInsituStringStream<UTF8<> > InsituStringStream; |
| 176 | |
| 177 | RAPIDJSON_NAMESPACE_END |
| 178 | |
| 179 | #endif // RAPIDJSON_STREAM_H_ |
| 180 | |