| 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 | #ifndef RAPIDJSON_WRITER_H_ | 
|---|
| 16 | #define RAPIDJSON_WRITER_H_ | 
|---|
| 17 |  | 
|---|
| 18 | #include "stream.h" | 
|---|
| 19 | #include "internal/stack.h" | 
|---|
| 20 | #include "internal/strfunc.h" | 
|---|
| 21 | #include "internal/dtoa.h" | 
|---|
| 22 | #include "internal/itoa.h" | 
|---|
| 23 | #include "stringbuffer.h" | 
|---|
| 24 | #include <new>      // placement new | 
|---|
| 25 |  | 
|---|
| 26 | #if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) | 
|---|
| 27 | #include <intrin.h> | 
|---|
| 28 | #pragma intrinsic(_BitScanForward) | 
|---|
| 29 | #endif | 
|---|
| 30 | #ifdef RAPIDJSON_SSE42 | 
|---|
| 31 | #include <nmmintrin.h> | 
|---|
| 32 | #elif defined(RAPIDJSON_SSE2) | 
|---|
| 33 | #include <emmintrin.h> | 
|---|
| 34 | #endif | 
|---|
| 35 |  | 
|---|
| 36 | #ifdef _MSC_VER | 
|---|
| 37 | RAPIDJSON_DIAG_PUSH | 
|---|
| 38 | RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant | 
|---|
| 39 | #endif | 
|---|
| 40 |  | 
|---|
| 41 | #ifdef __clang__ | 
|---|
| 42 | RAPIDJSON_DIAG_PUSH | 
|---|
| 43 | RAPIDJSON_DIAG_OFF(padded) | 
|---|
| 44 | RAPIDJSON_DIAG_OFF(unreachable-code) | 
|---|
| 45 | #endif | 
|---|
| 46 |  | 
|---|
| 47 | RAPIDJSON_NAMESPACE_BEGIN | 
|---|
| 48 |  | 
|---|
| 49 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 50 | // WriteFlag | 
|---|
| 51 |  | 
|---|
| 52 | /*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS | 
|---|
| 53 | \ingroup RAPIDJSON_CONFIG | 
|---|
| 54 | \brief User-defined kWriteDefaultFlags definition. | 
|---|
| 55 |  | 
|---|
| 56 | User can define this as any \c WriteFlag combinations. | 
|---|
| 57 | */ | 
|---|
| 58 | #ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS | 
|---|
| 59 | #define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags | 
|---|
| 60 | #endif | 
|---|
| 61 |  | 
|---|
| 62 | //! Combination of writeFlags | 
|---|
| 63 | enum WriteFlag { | 
|---|
| 64 | kWriteNoFlags = 0,              //!< No flags are set. | 
|---|
| 65 | kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings. | 
|---|
| 66 | kWriteNanAndInfFlag = 2,        //!< Allow writing of Infinity, -Infinity and NaN. | 
|---|
| 67 | kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS  //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS | 
|---|
| 68 | }; | 
|---|
| 69 |  | 
|---|
| 70 | //! JSON writer | 
|---|
| 71 | /*! Writer implements the concept Handler. | 
|---|
| 72 | It generates JSON text by events to an output os. | 
|---|
| 73 |  | 
|---|
| 74 | User may programmatically calls the functions of a writer to generate JSON text. | 
|---|
| 75 |  | 
|---|
| 76 | On the other side, a writer can also be passed to objects that generates events, | 
|---|
| 77 |  | 
|---|
| 78 | for example Reader::Parse() and Document::Accept(). | 
|---|
| 79 |  | 
|---|
| 80 | \tparam OutputStream Type of output stream. | 
|---|
| 81 | \tparam SourceEncoding Encoding of source string. | 
|---|
| 82 | \tparam TargetEncoding Encoding of output stream. | 
|---|
| 83 | \tparam StackAllocator Type of allocator for allocating memory of stack. | 
|---|
| 84 | \note implements Handler concept | 
|---|
| 85 | */ | 
|---|
| 86 | template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> | 
|---|
| 87 | class Writer { | 
|---|
| 88 | public: | 
|---|
| 89 | typedef typename SourceEncoding::Ch Ch; | 
|---|
| 90 |  | 
|---|
| 91 | static const int kDefaultMaxDecimalPlaces = 324; | 
|---|
| 92 |  | 
|---|
| 93 | //! Constructor | 
|---|
| 94 | /*! \param os Output stream. | 
|---|
| 95 | \param stackAllocator User supplied allocator. If it is null, it will create a private one. | 
|---|
| 96 | \param levelDepth Initial capacity of stack. | 
|---|
| 97 | */ | 
|---|
| 98 | explicit | 
|---|
| 99 | Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) : | 
|---|
| 100 | os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} | 
|---|
| 101 |  | 
|---|
| 102 | explicit | 
|---|
| 103 | Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : | 
|---|
| 104 | os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} | 
|---|
| 105 |  | 
|---|
| 106 | //! Reset the writer with a new stream. | 
|---|
| 107 | /*! | 
|---|
| 108 | This function reset the writer with a new stream and default settings, | 
|---|
| 109 | in order to make a Writer object reusable for output multiple JSONs. | 
|---|
| 110 |  | 
|---|
| 111 | \param os New output stream. | 
|---|
| 112 | \code | 
|---|
| 113 | Writer<OutputStream> writer(os1); | 
|---|
| 114 | writer.StartObject(); | 
|---|
| 115 | // ... | 
|---|
| 116 | writer.EndObject(); | 
|---|
| 117 |  | 
|---|
| 118 | writer.Reset(os2); | 
|---|
| 119 | writer.StartObject(); | 
|---|
| 120 | // ... | 
|---|
| 121 | writer.EndObject(); | 
|---|
| 122 | \endcode | 
|---|
| 123 | */ | 
|---|
| 124 | void Reset(OutputStream& os) { | 
|---|
| 125 | os_ = &os; | 
|---|
| 126 | hasRoot_ = false; | 
|---|
| 127 | level_stack_.Clear(); | 
|---|
| 128 | } | 
|---|
| 129 |  | 
|---|
| 130 | //! Checks whether the output is a complete JSON. | 
|---|
| 131 | /*! | 
|---|
| 132 | A complete JSON has a complete root object or array. | 
|---|
| 133 | */ | 
|---|
| 134 | bool IsComplete() const { | 
|---|
| 135 | return hasRoot_ && level_stack_.Empty(); | 
|---|
| 136 | } | 
|---|
| 137 |  | 
|---|
| 138 | int GetMaxDecimalPlaces() const { | 
|---|
| 139 | return maxDecimalPlaces_; | 
|---|
| 140 | } | 
|---|
| 141 |  | 
|---|
| 142 | //! Sets the maximum number of decimal places for double output. | 
|---|
| 143 | /*! | 
|---|
| 144 | This setting truncates the output with specified number of decimal places. | 
|---|
| 145 |  | 
|---|
| 146 | For example, | 
|---|
| 147 |  | 
|---|
| 148 | \code | 
|---|
| 149 | writer.SetMaxDecimalPlaces(3); | 
|---|
| 150 | writer.StartArray(); | 
|---|
| 151 | writer.Double(0.12345);                 // "0.123" | 
|---|
| 152 | writer.Double(0.0001);                  // "0.0" | 
|---|
| 153 | writer.Double(1.234567890123456e30);    // "1.234567890123456e30" (do not truncate significand for positive exponent) | 
|---|
| 154 | writer.Double(1.23e-4);                 // "0.0"                  (do truncate significand for negative exponent) | 
|---|
| 155 | writer.EndArray(); | 
|---|
| 156 | \endcode | 
|---|
| 157 |  | 
|---|
| 158 | The default setting does not truncate any decimal places. You can restore to this setting by calling | 
|---|
| 159 | \code | 
|---|
| 160 | writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces); | 
|---|
| 161 | \endcode | 
|---|
| 162 | */ | 
|---|
| 163 | void SetMaxDecimalPlaces(int maxDecimalPlaces) { | 
|---|
| 164 | maxDecimalPlaces_ = maxDecimalPlaces; | 
|---|
| 165 | } | 
|---|
| 166 |  | 
|---|
| 167 | /*!@name Implementation of Handler | 
|---|
| 168 | \see Handler | 
|---|
| 169 | */ | 
|---|
| 170 | //@{ | 
|---|
| 171 |  | 
|---|
| 172 | bool Null()                 { Prefix(kNullType);   return EndValue(WriteNull()); } | 
|---|
| 173 | bool Bool(bool b)           { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); } | 
|---|
| 174 | bool Int(int i)             { Prefix(kNumberType); return EndValue(WriteInt(i)); } | 
|---|
| 175 | bool Uint(unsigned u)       { Prefix(kNumberType); return EndValue(WriteUint(u)); } | 
|---|
| 176 | bool Int64(int64_t i64)     { Prefix(kNumberType); return EndValue(WriteInt64(i64)); } | 
|---|
| 177 | bool Uint64(uint64_t u64)   { Prefix(kNumberType); return EndValue(WriteUint64(u64)); } | 
|---|
| 178 |  | 
|---|
| 179 | //! Writes the given \c double value to the stream | 
|---|
| 180 | /*! | 
|---|
| 181 | \param d The value to be written. | 
|---|
| 182 | \return Whether it is succeed. | 
|---|
| 183 | */ | 
|---|
| 184 | bool Double(double d)       { Prefix(kNumberType); return EndValue(WriteDouble(d)); } | 
|---|
| 185 |  | 
|---|
| 186 | bool RawNumber(const Ch* str, SizeType length, bool copy = false) { | 
|---|
| 187 | (void)copy; | 
|---|
| 188 | Prefix(kNumberType); | 
|---|
| 189 | return EndValue(WriteString(str, length)); | 
|---|
| 190 | } | 
|---|
| 191 |  | 
|---|
| 192 | bool String(const Ch* str, SizeType length, bool copy = false) { | 
|---|
| 193 | (void)copy; | 
|---|
| 194 | Prefix(kStringType); | 
|---|
| 195 | return EndValue(WriteString(str, length)); | 
|---|
| 196 | } | 
|---|
| 197 |  | 
|---|
| 198 | #if RAPIDJSON_HAS_STDSTRING | 
|---|
| 199 | bool String(const std::basic_string<Ch>& str) { | 
|---|
| 200 | return String(str.data(), SizeType(str.size())); | 
|---|
| 201 | } | 
|---|
| 202 | #endif | 
|---|
| 203 |  | 
|---|
| 204 | bool StartObject() { | 
|---|
| 205 | Prefix(kObjectType); | 
|---|
| 206 | new (level_stack_.template Push<Level>()) Level(false); | 
|---|
| 207 | return WriteStartObject(); | 
|---|
| 208 | } | 
|---|
| 209 |  | 
|---|
| 210 | bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } | 
|---|
| 211 |  | 
|---|
| 212 | bool EndObject(SizeType memberCount = 0) { | 
|---|
| 213 | (void)memberCount; | 
|---|
| 214 | RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); | 
|---|
| 215 | RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray); | 
|---|
| 216 | level_stack_.template Pop<Level>(1); | 
|---|
| 217 | return EndValue(WriteEndObject()); | 
|---|
| 218 | } | 
|---|
| 219 |  | 
|---|
| 220 | bool StartArray() { | 
|---|
| 221 | Prefix(kArrayType); | 
|---|
| 222 | new (level_stack_.template Push<Level>()) Level(true); | 
|---|
| 223 | return WriteStartArray(); | 
|---|
| 224 | } | 
|---|
| 225 |  | 
|---|
| 226 | bool EndArray(SizeType elementCount = 0) { | 
|---|
| 227 | (void)elementCount; | 
|---|
| 228 | RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); | 
|---|
| 229 | RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray); | 
|---|
| 230 | level_stack_.template Pop<Level>(1); | 
|---|
| 231 | return EndValue(WriteEndArray()); | 
|---|
| 232 | } | 
|---|
| 233 | //@} | 
|---|
| 234 |  | 
|---|
| 235 | /*! @name Convenience extensions */ | 
|---|
| 236 | //@{ | 
|---|
| 237 |  | 
|---|
| 238 | //! Simpler but slower overload. | 
|---|
| 239 | bool String(const Ch* str) { return String(str, internal::StrLen(str)); } | 
|---|
| 240 | bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } | 
|---|
| 241 |  | 
|---|
| 242 | //@} | 
|---|
| 243 |  | 
|---|
| 244 | //! Write a raw JSON value. | 
|---|
| 245 | /*! | 
|---|
| 246 | For user to write a stringified JSON as a value. | 
|---|
| 247 |  | 
|---|
| 248 | \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. | 
|---|
| 249 | \param length Length of the json. | 
|---|
| 250 | \param type Type of the root of json. | 
|---|
| 251 | */ | 
|---|
| 252 | bool RawValue(const Ch* json, size_t length, Type type) { Prefix(type); return EndValue(WriteRawValue(json, length)); } | 
|---|
| 253 |  | 
|---|
| 254 | protected: | 
|---|
| 255 | //! Information for each nested level | 
|---|
| 256 | struct Level { | 
|---|
| 257 | Level(bool inArray_) : valueCount(0), inArray(inArray_) {} | 
|---|
| 258 | size_t valueCount;  //!< number of values in this level | 
|---|
| 259 | bool inArray;       //!< true if in array, otherwise in object | 
|---|
| 260 | }; | 
|---|
| 261 |  | 
|---|
| 262 | static const size_t kDefaultLevelDepth = 32; | 
|---|
| 263 |  | 
|---|
| 264 | bool WriteNull()  { | 
|---|
| 265 | PutReserve(*os_, 4); | 
|---|
| 266 | PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true; | 
|---|
| 267 | } | 
|---|
| 268 |  | 
|---|
| 269 | bool WriteBool(bool b)  { | 
|---|
| 270 | if (b) { | 
|---|
| 271 | PutReserve(*os_, 4); | 
|---|
| 272 | PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e'); | 
|---|
| 273 | } | 
|---|
| 274 | else { | 
|---|
| 275 | PutReserve(*os_, 5); | 
|---|
| 276 | PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e'); | 
|---|
| 277 | } | 
|---|
| 278 | return true; | 
|---|
| 279 | } | 
|---|
| 280 |  | 
|---|
| 281 | bool WriteInt(int i) { | 
|---|
| 282 | char buffer[11]; | 
|---|
| 283 | const char* end = internal::i32toa(i, buffer); | 
|---|
| 284 | PutReserve(*os_, static_cast<size_t>(end - buffer)); | 
|---|
| 285 | for (const char* p = buffer; p != end; ++p) | 
|---|
| 286 | PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p)); | 
|---|
| 287 | return true; | 
|---|
| 288 | } | 
|---|
| 289 |  | 
|---|
| 290 | bool WriteUint(unsigned u) { | 
|---|
| 291 | char buffer[10]; | 
|---|
| 292 | const char* end = internal::u32toa(u, buffer); | 
|---|
| 293 | PutReserve(*os_, static_cast<size_t>(end - buffer)); | 
|---|
| 294 | for (const char* p = buffer; p != end; ++p) | 
|---|
| 295 | PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p)); | 
|---|
| 296 | return true; | 
|---|
| 297 | } | 
|---|
| 298 |  | 
|---|
| 299 | bool WriteInt64(int64_t i64) { | 
|---|
| 300 | char buffer[21]; | 
|---|
| 301 | const char* end = internal::i64toa(i64, buffer); | 
|---|
| 302 | PutReserve(*os_, static_cast<size_t>(end - buffer)); | 
|---|
| 303 | for (const char* p = buffer; p != end; ++p) | 
|---|
| 304 | PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p)); | 
|---|
| 305 | return true; | 
|---|
| 306 | } | 
|---|
| 307 |  | 
|---|
| 308 | bool WriteUint64(uint64_t u64) { | 
|---|
| 309 | char buffer[20]; | 
|---|
| 310 | char* end = internal::u64toa(u64, buffer); | 
|---|
| 311 | PutReserve(*os_, static_cast<size_t>(end - buffer)); | 
|---|
| 312 | for (char* p = buffer; p != end; ++p) | 
|---|
| 313 | PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p)); | 
|---|
| 314 | return true; | 
|---|
| 315 | } | 
|---|
| 316 |  | 
|---|
| 317 | bool WriteDouble(double d) { | 
|---|
| 318 | if (internal::Double(d).IsNanOrInf()) { | 
|---|
| 319 | if (!(writeFlags & kWriteNanAndInfFlag)) | 
|---|
| 320 | return false; | 
|---|
| 321 | if (internal::Double(d).IsNan()) { | 
|---|
| 322 | PutReserve(*os_, 3); | 
|---|
| 323 | PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); | 
|---|
| 324 | return true; | 
|---|
| 325 | } | 
|---|
| 326 | if (internal::Double(d).Sign()) { | 
|---|
| 327 | PutReserve(*os_, 9); | 
|---|
| 328 | PutUnsafe(*os_, '-'); | 
|---|
| 329 | } | 
|---|
| 330 | else | 
|---|
| 331 | PutReserve(*os_, 8); | 
|---|
| 332 | PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); | 
|---|
| 333 | PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); | 
|---|
| 334 | return true; | 
|---|
| 335 | } | 
|---|
| 336 |  | 
|---|
| 337 | char buffer[25]; | 
|---|
| 338 | char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); | 
|---|
| 339 | PutReserve(*os_, static_cast<size_t>(end - buffer)); | 
|---|
| 340 | for (char* p = buffer; p != end; ++p) | 
|---|
| 341 | PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p)); | 
|---|
| 342 | return true; | 
|---|
| 343 | } | 
|---|
| 344 |  | 
|---|
| 345 | bool WriteString(const Ch* str, SizeType length)  { | 
|---|
| 346 | static const typename TargetEncoding::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; | 
|---|
| 347 | static const char escape[256] = { | 
|---|
| 348 | #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 | 
|---|
| 349 | //0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F | 
|---|
| 350 | 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00 | 
|---|
| 351 | 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10 | 
|---|
| 352 | 0,   0, '"',   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, // 20 | 
|---|
| 353 | Z16, Z16,                                                                       // 30~4F | 
|---|
| 354 | 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,'\\',   0,   0,   0, // 50 | 
|---|
| 355 | Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16                                // 60~FF | 
|---|
| 356 | #undef Z16 | 
|---|
| 357 | }; | 
|---|
| 358 |  | 
|---|
| 359 | if (TargetEncoding::supportUnicode) | 
|---|
| 360 | PutReserve(*os_, 2 + length * 6); // "\uxxxx..." | 
|---|
| 361 | else | 
|---|
| 362 | PutReserve(*os_, 2 + length * 12);  // "\uxxxx\uyyyy..." | 
|---|
| 363 |  | 
|---|
| 364 | PutUnsafe(*os_, '\"'); | 
|---|
| 365 | GenericStringStream<SourceEncoding> is(str); | 
|---|
| 366 | while (ScanWriteUnescapedString(is, length)) { | 
|---|
| 367 | const Ch c = is.Peek(); | 
|---|
| 368 | if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) { | 
|---|
| 369 | // Unicode escaping | 
|---|
| 370 | unsigned codepoint; | 
|---|
| 371 | if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint))) | 
|---|
| 372 | return false; | 
|---|
| 373 | PutUnsafe(*os_, '\\'); | 
|---|
| 374 | PutUnsafe(*os_, 'u'); | 
|---|
| 375 | if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) { | 
|---|
| 376 | PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]); | 
|---|
| 377 | PutUnsafe(*os_, hexDigits[(codepoint >>  8) & 15]); | 
|---|
| 378 | PutUnsafe(*os_, hexDigits[(codepoint >>  4) & 15]); | 
|---|
| 379 | PutUnsafe(*os_, hexDigits[(codepoint      ) & 15]); | 
|---|
| 380 | } | 
|---|
| 381 | else { | 
|---|
| 382 | RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF); | 
|---|
| 383 | // Surrogate pair | 
|---|
| 384 | unsigned s = codepoint - 0x010000; | 
|---|
| 385 | unsigned lead = (s >> 10) + 0xD800; | 
|---|
| 386 | unsigned trail = (s & 0x3FF) + 0xDC00; | 
|---|
| 387 | PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]); | 
|---|
| 388 | PutUnsafe(*os_, hexDigits[(lead >>  8) & 15]); | 
|---|
| 389 | PutUnsafe(*os_, hexDigits[(lead >>  4) & 15]); | 
|---|
| 390 | PutUnsafe(*os_, hexDigits[(lead      ) & 15]); | 
|---|
| 391 | PutUnsafe(*os_, '\\'); | 
|---|
| 392 | PutUnsafe(*os_, 'u'); | 
|---|
| 393 | PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]); | 
|---|
| 394 | PutUnsafe(*os_, hexDigits[(trail >>  8) & 15]); | 
|---|
| 395 | PutUnsafe(*os_, hexDigits[(trail >>  4) & 15]); | 
|---|
| 396 | PutUnsafe(*os_, hexDigits[(trail      ) & 15]); | 
|---|
| 397 | } | 
|---|
| 398 | } | 
|---|
| 399 | else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)]))  { | 
|---|
| 400 | is.Take(); | 
|---|
| 401 | PutUnsafe(*os_, '\\'); | 
|---|
| 402 | PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(escape[static_cast<unsigned char>(c)])); | 
|---|
| 403 | if (escape[static_cast<unsigned char>(c)] == 'u') { | 
|---|
| 404 | PutUnsafe(*os_, '0'); | 
|---|
| 405 | PutUnsafe(*os_, '0'); | 
|---|
| 406 | PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]); | 
|---|
| 407 | PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]); | 
|---|
| 408 | } | 
|---|
| 409 | } | 
|---|
| 410 | else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? | 
|---|
| 411 | Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) : | 
|---|
| 412 | Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_)))) | 
|---|
| 413 | return false; | 
|---|
| 414 | } | 
|---|
| 415 | PutUnsafe(*os_, '\"'); | 
|---|
| 416 | return true; | 
|---|
| 417 | } | 
|---|
| 418 |  | 
|---|
| 419 | bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) { | 
|---|
| 420 | return RAPIDJSON_LIKELY(is.Tell() < length); | 
|---|
| 421 | } | 
|---|
| 422 |  | 
|---|
| 423 | bool WriteStartObject() { os_->Put('{'); return true; } | 
|---|
| 424 | bool WriteEndObject()   { os_->Put('}'); return true; } | 
|---|
| 425 | bool WriteStartArray()  { os_->Put('['); return true; } | 
|---|
| 426 | bool WriteEndArray()    { os_->Put(']'); return true; } | 
|---|
| 427 |  | 
|---|
| 428 | bool WriteRawValue(const Ch* json, size_t length) { | 
|---|
| 429 | PutReserve(*os_, length); | 
|---|
| 430 | for (size_t i = 0; i < length; i++) { | 
|---|
| 431 | RAPIDJSON_ASSERT(json[i] != '\0'); | 
|---|
| 432 | PutUnsafe(*os_, json[i]); | 
|---|
| 433 | } | 
|---|
| 434 | return true; | 
|---|
| 435 | } | 
|---|
| 436 |  | 
|---|
| 437 | void Prefix(Type type) { | 
|---|
| 438 | (void)type; | 
|---|
| 439 | if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root | 
|---|
| 440 | Level* level = level_stack_.template Top<Level>(); | 
|---|
| 441 | if (level->valueCount > 0) { | 
|---|
| 442 | if (level->inArray) | 
|---|
| 443 | os_->Put(','); // add comma if it is not the first element in array | 
|---|
| 444 | else  // in object | 
|---|
| 445 | os_->Put((level->valueCount % 2 == 0) ? ',' : ':'); | 
|---|
| 446 | } | 
|---|
| 447 | if (!level->inArray && level->valueCount % 2 == 0) | 
|---|
| 448 | RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name | 
|---|
| 449 | level->valueCount++; | 
|---|
| 450 | } | 
|---|
| 451 | else { | 
|---|
| 452 | RAPIDJSON_ASSERT(!hasRoot_);    // Should only has one and only one root. | 
|---|
| 453 | hasRoot_ = true; | 
|---|
| 454 | } | 
|---|
| 455 | } | 
|---|
| 456 |  | 
|---|
| 457 | // Flush the value if it is the top level one. | 
|---|
| 458 | bool EndValue(bool ret) { | 
|---|
| 459 | if (RAPIDJSON_UNLIKELY(level_stack_.Empty()))   // end of json text | 
|---|
| 460 | os_->Flush(); | 
|---|
| 461 | return ret; | 
|---|
| 462 | } | 
|---|
| 463 |  | 
|---|
| 464 | OutputStream* os_; | 
|---|
| 465 | internal::Stack<StackAllocator> level_stack_; | 
|---|
| 466 | int maxDecimalPlaces_; | 
|---|
| 467 | bool hasRoot_; | 
|---|
| 468 |  | 
|---|
| 469 | private: | 
|---|
| 470 | // Prohibit copy constructor & assignment operator. | 
|---|
| 471 | Writer(const Writer&); | 
|---|
| 472 | Writer& operator=(const Writer&); | 
|---|
| 473 | }; | 
|---|
| 474 |  | 
|---|
| 475 | // Full specialization for StringStream to prevent memory copying | 
|---|
| 476 |  | 
|---|
| 477 | template<> | 
|---|
| 478 | inline bool Writer<StringBuffer>::WriteInt(int i) { | 
|---|
| 479 | char *buffer = os_->Push(11); | 
|---|
| 480 | const char* end = internal::i32toa(i, buffer); | 
|---|
| 481 | os_->Pop(static_cast<size_t>(11 - (end - buffer))); | 
|---|
| 482 | return true; | 
|---|
| 483 | } | 
|---|
| 484 |  | 
|---|
| 485 | template<> | 
|---|
| 486 | inline bool Writer<StringBuffer>::WriteUint(unsigned u) { | 
|---|
| 487 | char *buffer = os_->Push(10); | 
|---|
| 488 | const char* end = internal::u32toa(u, buffer); | 
|---|
| 489 | os_->Pop(static_cast<size_t>(10 - (end - buffer))); | 
|---|
| 490 | return true; | 
|---|
| 491 | } | 
|---|
| 492 |  | 
|---|
| 493 | template<> | 
|---|
| 494 | inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) { | 
|---|
| 495 | char *buffer = os_->Push(21); | 
|---|
| 496 | const char* end = internal::i64toa(i64, buffer); | 
|---|
| 497 | os_->Pop(static_cast<size_t>(21 - (end - buffer))); | 
|---|
| 498 | return true; | 
|---|
| 499 | } | 
|---|
| 500 |  | 
|---|
| 501 | template<> | 
|---|
| 502 | inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) { | 
|---|
| 503 | char *buffer = os_->Push(20); | 
|---|
| 504 | const char* end = internal::u64toa(u, buffer); | 
|---|
| 505 | os_->Pop(static_cast<size_t>(20 - (end - buffer))); | 
|---|
| 506 | return true; | 
|---|
| 507 | } | 
|---|
| 508 |  | 
|---|
| 509 | template<> | 
|---|
| 510 | inline bool Writer<StringBuffer>::WriteDouble(double d) { | 
|---|
| 511 | if (internal::Double(d).IsNanOrInf()) { | 
|---|
| 512 | // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag). | 
|---|
| 513 | if (!(kWriteDefaultFlags & kWriteNanAndInfFlag)) | 
|---|
| 514 | return false; | 
|---|
| 515 | if (internal::Double(d).IsNan()) { | 
|---|
| 516 | PutReserve(*os_, 3); | 
|---|
| 517 | PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); | 
|---|
| 518 | return true; | 
|---|
| 519 | } | 
|---|
| 520 | if (internal::Double(d).Sign()) { | 
|---|
| 521 | PutReserve(*os_, 9); | 
|---|
| 522 | PutUnsafe(*os_, '-'); | 
|---|
| 523 | } | 
|---|
| 524 | else | 
|---|
| 525 | PutReserve(*os_, 8); | 
|---|
| 526 | PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); | 
|---|
| 527 | PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); | 
|---|
| 528 | return true; | 
|---|
| 529 | } | 
|---|
| 530 |  | 
|---|
| 531 | char *buffer = os_->Push(25); | 
|---|
| 532 | char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); | 
|---|
| 533 | os_->Pop(static_cast<size_t>(25 - (end - buffer))); | 
|---|
| 534 | return true; | 
|---|
| 535 | } | 
|---|
| 536 |  | 
|---|
| 537 | #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) | 
|---|
| 538 | template<> | 
|---|
| 539 | inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) { | 
|---|
| 540 | if (length < 16) | 
|---|
| 541 | return RAPIDJSON_LIKELY(is.Tell() < length); | 
|---|
| 542 |  | 
|---|
| 543 | if (!RAPIDJSON_LIKELY(is.Tell() < length)) | 
|---|
| 544 | return false; | 
|---|
| 545 |  | 
|---|
| 546 | const char* p = is.src_; | 
|---|
| 547 | const char* end = is.head_ + length; | 
|---|
| 548 | const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15)); | 
|---|
| 549 | const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15)); | 
|---|
| 550 | if (nextAligned > end) | 
|---|
| 551 | return true; | 
|---|
| 552 |  | 
|---|
| 553 | while (p != nextAligned) | 
|---|
| 554 | if (*p < 0x20 || *p == '\"' || *p == '\\') { | 
|---|
| 555 | is.src_ = p; | 
|---|
| 556 | return RAPIDJSON_LIKELY(is.Tell() < length); | 
|---|
| 557 | } | 
|---|
| 558 | else | 
|---|
| 559 | os_->PutUnsafe(*p++); | 
|---|
| 560 |  | 
|---|
| 561 | // The rest of string using SIMD | 
|---|
| 562 | static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; | 
|---|
| 563 | static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; | 
|---|
| 564 | static const char space[16]  = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; | 
|---|
| 565 | const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0])); | 
|---|
| 566 | const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0])); | 
|---|
| 567 | const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0])); | 
|---|
| 568 |  | 
|---|
| 569 | for (; p != endAligned; p += 16) { | 
|---|
| 570 | const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p)); | 
|---|
| 571 | const __m128i t1 = _mm_cmpeq_epi8(s, dq); | 
|---|
| 572 | const __m128i t2 = _mm_cmpeq_epi8(s, bs); | 
|---|
| 573 | const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 | 
|---|
| 574 | const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); | 
|---|
| 575 | unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x)); | 
|---|
| 576 | if (RAPIDJSON_UNLIKELY(r != 0)) {   // some of characters is escaped | 
|---|
| 577 | SizeType len; | 
|---|
| 578 | #ifdef _MSC_VER         // Find the index of first escaped | 
|---|
| 579 | unsigned long offset; | 
|---|
| 580 | _BitScanForward(&offset, r); | 
|---|
| 581 | len = offset; | 
|---|
| 582 | #else | 
|---|
| 583 | len = static_cast<SizeType>(__builtin_ffs(r) - 1); | 
|---|
| 584 | #endif | 
|---|
| 585 | char* q = reinterpret_cast<char*>(os_->PushUnsafe(len)); | 
|---|
| 586 | for (size_t i = 0; i < len; i++) | 
|---|
| 587 | q[i] = p[i]; | 
|---|
| 588 |  | 
|---|
| 589 | p += len; | 
|---|
| 590 | break; | 
|---|
| 591 | } | 
|---|
| 592 | _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s); | 
|---|
| 593 | } | 
|---|
| 594 |  | 
|---|
| 595 | is.src_ = p; | 
|---|
| 596 | return RAPIDJSON_LIKELY(is.Tell() < length); | 
|---|
| 597 | } | 
|---|
| 598 | #endif // defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) | 
|---|
| 599 |  | 
|---|
| 600 | RAPIDJSON_NAMESPACE_END | 
|---|
| 601 |  | 
|---|
| 602 | #ifdef _MSC_VER | 
|---|
| 603 | RAPIDJSON_DIAG_POP | 
|---|
| 604 | #endif | 
|---|
| 605 |  | 
|---|
| 606 | #ifdef __clang__ | 
|---|
| 607 | RAPIDJSON_DIAG_POP | 
|---|
| 608 | #endif | 
|---|
| 609 |  | 
|---|
| 610 | #endif // RAPIDJSON_RAPIDJSON_H_ | 
|---|
| 611 |  | 
|---|