identt
writer.h
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 RAPIDJSON_DIAG_OFF(c++98-compat)
46 #endif
47 
49 
51 // WriteFlag
52 
59 #ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS
60 #define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags
61 #endif
62 
64 enum WriteFlag {
65  kWriteNoFlags = 0,
66  kWriteValidateEncodingFlag = 1,
67  kWriteNanAndInfFlag = 2,
68  kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS
69 };
70 
72 
87 template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
88 class Writer {
89 public:
90  typedef typename SourceEncoding::Ch Ch;
91 
92  static const int kDefaultMaxDecimalPlaces = 324;
93 
95 
99  explicit
100  Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) :
101  os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
102 
103  explicit
104  Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
105  os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
106 
107 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
108  Writer(Writer&& rhs) :
109  os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) {
110  rhs.os_ = 0;
111  }
112 #endif
113 
115 
132  void Reset(OutputStream& os) {
133  os_ = &os;
134  hasRoot_ = false;
135  level_stack_.Clear();
136  }
137 
139 
142  bool IsComplete() const {
143  return hasRoot_ && level_stack_.Empty();
144  }
145 
146  int GetMaxDecimalPlaces() const {
147  return maxDecimalPlaces_;
148  }
149 
151 
171  void SetMaxDecimalPlaces(int maxDecimalPlaces) {
172  maxDecimalPlaces_ = maxDecimalPlaces;
173  }
174 
179 
180  bool Null() { Prefix(kNullType); return EndValue(WriteNull()); }
181  bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); }
182  bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt(i)); }
183  bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint(u)); }
184  bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt64(i64)); }
185  bool Uint64(uint64_t u64) { Prefix(kNumberType); return EndValue(WriteUint64(u64)); }
186 
188 
192  bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); }
193 
194  bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
195  RAPIDJSON_ASSERT(str != 0);
196  (void)copy;
197  Prefix(kNumberType);
198  return EndValue(WriteString(str, length));
199  }
200 
201  bool String(const Ch* str, SizeType length, bool copy = false) {
202  RAPIDJSON_ASSERT(str != 0);
203  (void)copy;
204  Prefix(kStringType);
205  return EndValue(WriteString(str, length));
206  }
207 
208 #if RAPIDJSON_HAS_STDSTRING
209  bool String(const std::basic_string<Ch>& str) {
210  return String(str.data(), SizeType(str.size()));
211  }
212 #endif
213 
214  bool StartObject() {
215  Prefix(kObjectType);
216  new (level_stack_.template Push<Level>()) Level(false);
217  return WriteStartObject();
218  }
219 
220  bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
221 
222  bool EndObject(SizeType memberCount = 0) {
223  (void)memberCount;
224  RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
225  RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
226  level_stack_.template Pop<Level>(1);
227  return EndValue(WriteEndObject());
228  }
229 
230  bool StartArray() {
231  Prefix(kArrayType);
232  new (level_stack_.template Push<Level>()) Level(true);
233  return WriteStartArray();
234  }
235 
236  bool EndArray(SizeType elementCount = 0) {
237  (void)elementCount;
238  RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
239  RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
240  level_stack_.template Pop<Level>(1);
241  return EndValue(WriteEndArray());
242  }
244 
247 
249  bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
250  bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
251 
253 
255 
262  bool RawValue(const Ch* json, size_t length, Type type) {
263  RAPIDJSON_ASSERT(json != 0);
264  Prefix(type);
265  return EndValue(WriteRawValue(json, length));
266  }
267 
268 protected:
270  struct Level {
271  Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
272  size_t valueCount;
273  bool inArray;
274  };
275 
276  static const size_t kDefaultLevelDepth = 32;
277 
278  bool WriteNull() {
279  PutReserve(*os_, 4);
280  PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true;
281  }
282 
283  bool WriteBool(bool b) {
284  if (b) {
285  PutReserve(*os_, 4);
286  PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e');
287  }
288  else {
289  PutReserve(*os_, 5);
290  PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e');
291  }
292  return true;
293  }
294 
295  bool WriteInt(int i) {
296  char buffer[11];
297  const char* end = internal::i32toa(i, buffer);
298  PutReserve(*os_, static_cast<size_t>(end - buffer));
299  for (const char* p = buffer; p != end; ++p)
300  PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
301  return true;
302  }
303 
304  bool WriteUint(unsigned u) {
305  char buffer[10];
306  const char* end = internal::u32toa(u, buffer);
307  PutReserve(*os_, static_cast<size_t>(end - buffer));
308  for (const char* p = buffer; p != end; ++p)
309  PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
310  return true;
311  }
312 
313  bool WriteInt64(int64_t i64) {
314  char buffer[21];
315  const char* end = internal::i64toa(i64, buffer);
316  PutReserve(*os_, static_cast<size_t>(end - buffer));
317  for (const char* p = buffer; p != end; ++p)
318  PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
319  return true;
320  }
321 
322  bool WriteUint64(uint64_t u64) {
323  char buffer[20];
324  char* end = internal::u64toa(u64, buffer);
325  PutReserve(*os_, static_cast<size_t>(end - buffer));
326  for (char* p = buffer; p != end; ++p)
327  PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
328  return true;
329  }
330 
331  bool WriteDouble(double d) {
332  if (internal::Double(d).IsNanOrInf()) {
333  if (!(writeFlags & kWriteNanAndInfFlag))
334  return false;
335  if (internal::Double(d).IsNan()) {
336  PutReserve(*os_, 3);
337  PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
338  return true;
339  }
340  if (internal::Double(d).Sign()) {
341  PutReserve(*os_, 9);
342  PutUnsafe(*os_, '-');
343  }
344  else
345  PutReserve(*os_, 8);
346  PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
347  PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
348  return true;
349  }
350 
351  char buffer[25];
352  char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
353  PutReserve(*os_, static_cast<size_t>(end - buffer));
354  for (char* p = buffer; p != end; ++p)
355  PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
356  return true;
357  }
358 
359  bool WriteString(const Ch* str, SizeType length) {
360  static const typename TargetEncoding::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
361  static const char escape[256] = {
362 #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
363  //0 1 2 3 4 5 6 7 8 9 A B C D E F
364  'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
365  'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
366  0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
367  Z16, Z16, // 30~4F
368  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
369  Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
370 #undef Z16
371  };
372 
373  if (TargetEncoding::supportUnicode)
374  PutReserve(*os_, 2 + length * 6); // "\uxxxx..."
375  else
376  PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..."
377 
378  PutUnsafe(*os_, '\"');
380  while (ScanWriteUnescapedString(is, length)) {
381  const Ch c = is.Peek();
382  if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) {
383  // Unicode escaping
384  unsigned codepoint;
385  if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint)))
386  return false;
387  PutUnsafe(*os_, '\\');
388  PutUnsafe(*os_, 'u');
389  if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
390  PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]);
391  PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]);
392  PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]);
393  PutUnsafe(*os_, hexDigits[(codepoint ) & 15]);
394  }
395  else {
396  RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
397  // Surrogate pair
398  unsigned s = codepoint - 0x010000;
399  unsigned lead = (s >> 10) + 0xD800;
400  unsigned trail = (s & 0x3FF) + 0xDC00;
401  PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]);
402  PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]);
403  PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]);
404  PutUnsafe(*os_, hexDigits[(lead ) & 15]);
405  PutUnsafe(*os_, '\\');
406  PutUnsafe(*os_, 'u');
407  PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]);
408  PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]);
409  PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]);
410  PutUnsafe(*os_, hexDigits[(trail ) & 15]);
411  }
412  }
413  else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)])) {
414  is.Take();
415  PutUnsafe(*os_, '\\');
416  PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(escape[static_cast<unsigned char>(c)]));
417  if (escape[static_cast<unsigned char>(c)] == 'u') {
418  PutUnsafe(*os_, '0');
419  PutUnsafe(*os_, '0');
420  PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]);
421  PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]);
422  }
423  }
424  else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
427  return false;
428  }
429  PutUnsafe(*os_, '\"');
430  return true;
431  }
432 
433  bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) {
434  return RAPIDJSON_LIKELY(is.Tell() < length);
435  }
436 
437  bool WriteStartObject() { os_->Put('{'); return true; }
438  bool WriteEndObject() { os_->Put('}'); return true; }
439  bool WriteStartArray() { os_->Put('['); return true; }
440  bool WriteEndArray() { os_->Put(']'); return true; }
441 
442  bool WriteRawValue(const Ch* json, size_t length) {
443  PutReserve(*os_, length);
444  for (size_t i = 0; i < length; i++) {
445  RAPIDJSON_ASSERT(json[i] != '\0');
446  PutUnsafe(*os_, json[i]);
447  }
448  return true;
449  }
450 
451  void Prefix(Type type) {
452  (void)type;
453  if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root
454  Level* level = level_stack_.template Top<Level>();
455  if (level->valueCount > 0) {
456  if (level->inArray)
457  os_->Put(','); // add comma if it is not the first element in array
458  else // in object
459  os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
460  }
461  if (!level->inArray && level->valueCount % 2 == 0)
462  RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
463  level->valueCount++;
464  }
465  else {
466  RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root.
467  hasRoot_ = true;
468  }
469  }
470 
471  // Flush the value if it is the top level one.
472  bool EndValue(bool ret) {
473  if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text
474  os_->Flush();
475  return ret;
476  }
477 
478  OutputStream* os_;
479  internal::Stack<StackAllocator> level_stack_;
480  int maxDecimalPlaces_;
481  bool hasRoot_;
482 
483 private:
484  // Prohibit copy constructor & assignment operator.
485  Writer(const Writer&);
486  Writer& operator=(const Writer&);
487 };
488 
489 // Full specialization for StringStream to prevent memory copying
490 
491 template<>
492 inline bool Writer<StringBuffer>::WriteInt(int i) {
493  char *buffer = os_->Push(11);
494  const char* end = internal::i32toa(i, buffer);
495  os_->Pop(static_cast<size_t>(11 - (end - buffer)));
496  return true;
497 }
498 
499 template<>
500 inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
501  char *buffer = os_->Push(10);
502  const char* end = internal::u32toa(u, buffer);
503  os_->Pop(static_cast<size_t>(10 - (end - buffer)));
504  return true;
505 }
506 
507 template<>
508 inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
509  char *buffer = os_->Push(21);
510  const char* end = internal::i64toa(i64, buffer);
511  os_->Pop(static_cast<size_t>(21 - (end - buffer)));
512  return true;
513 }
514 
515 template<>
516 inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
517  char *buffer = os_->Push(20);
518  const char* end = internal::u64toa(u, buffer);
519  os_->Pop(static_cast<size_t>(20 - (end - buffer)));
520  return true;
521 }
522 
523 template<>
524 inline bool Writer<StringBuffer>::WriteDouble(double d) {
525  if (internal::Double(d).IsNanOrInf()) {
526  // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag).
527  if (!(kWriteDefaultFlags & kWriteNanAndInfFlag))
528  return false;
529  if (internal::Double(d).IsNan()) {
530  PutReserve(*os_, 3);
531  PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
532  return true;
533  }
534  if (internal::Double(d).Sign()) {
535  PutReserve(*os_, 9);
536  PutUnsafe(*os_, '-');
537  }
538  else
539  PutReserve(*os_, 8);
540  PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
541  PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
542  return true;
543  }
544 
545  char *buffer = os_->Push(25);
546  char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
547  os_->Pop(static_cast<size_t>(25 - (end - buffer)));
548  return true;
549 }
550 
551 #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
552 template<>
553 inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
554  if (length < 16)
555  return RAPIDJSON_LIKELY(is.Tell() < length);
556 
557  if (!RAPIDJSON_LIKELY(is.Tell() < length))
558  return false;
559 
560  const char* p = is.src_;
561  const char* end = is.head_ + length;
562  const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
563  const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
564  if (nextAligned > end)
565  return true;
566 
567  while (p != nextAligned)
568  if (*p < 0x20 || *p == '\"' || *p == '\\') {
569  is.src_ = p;
570  return RAPIDJSON_LIKELY(is.Tell() < length);
571  }
572  else
573  os_->PutUnsafe(*p++);
574 
575  // The rest of string using SIMD
576  static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
577  static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
578  static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
579  const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
580  const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
581  const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
582 
583  for (; p != endAligned; p += 16) {
584  const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
585  const __m128i t1 = _mm_cmpeq_epi8(s, dq);
586  const __m128i t2 = _mm_cmpeq_epi8(s, bs);
587  const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
588  const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
589  unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
590  if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
591  SizeType len;
592 #ifdef _MSC_VER // Find the index of first escaped
593  unsigned long offset;
594  _BitScanForward(&offset, r);
595  len = offset;
596 #else
597  len = static_cast<SizeType>(__builtin_ffs(r) - 1);
598 #endif
599  char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
600  for (size_t i = 0; i < len; i++)
601  q[i] = p[i];
602 
603  p += len;
604  break;
605  }
606  _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s);
607  }
608 
609  is.src_ = p;
610  return RAPIDJSON_LIKELY(is.Tell() < length);
611 }
612 #endif // defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
613 
615 
616 #ifdef _MSC_VER
617 RAPIDJSON_DIAG_POP
618 #endif
619 
620 #ifdef __clang__
621 RAPIDJSON_DIAG_POP
622 #endif
623 
624 #endif // RAPIDJSON_RAPIDJSON_H_
Encoding conversion.
Definition: encodings.h:658
size_t valueCount
number of values in this level
Definition: writer.h:272
RAPIDJSON_NAMESPACE_BEGIN typedef unsigned SizeType
Size type (for string lengths, array sizes, etc.)
Definition: rapidjson.h:380
bool inArray
true if in array, otherwise in object
Definition: writer.h:273
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition: rapidjson.h:402
JSON writer.
Definition: fwd.h:95
object
Definition: rapidjson.h:607
Read-only string stream.
Definition: fwd.h:47
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
Definition: rapidjson.h:119
array
Definition: rapidjson.h:608
const Ch * src_
Current read position.
Definition: stream.h:124
bool RawValue(const Ch *json, size_t length, Type type)
Write a raw JSON value.
Definition: writer.h:262
false
Definition: rapidjson.h:605
bool Double(double d)
Writes the given double value to the stream.
Definition: writer.h:192
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
Definition: rapidjson.h:116
bool IsComplete() const
Checks whether the output is a complete JSON.
Definition: writer.h:142
Information for each nested level.
Definition: writer.h:270
string
Definition: rapidjson.h:609
number
Definition: rapidjson.h:610
#define RAPIDJSON_LIKELY(x)
Compiler branching hint for expression with high probability to be true.
Definition: rapidjson.h:455
Writer(OutputStream &os, StackAllocator *stackAllocator=0, size_t levelDepth=kDefaultLevelDepth)
Constructor.
Definition: writer.h:100
Definition: ieee754.h:23
void SetMaxDecimalPlaces(int maxDecimalPlaces)
Sets the maximum number of decimal places for double output.
Definition: writer.h:171
true
Definition: rapidjson.h:606
void Reset(OutputStream &os)
Reset the writer with a new stream.
Definition: writer.h:132
Type
Type of JSON value.
Definition: rapidjson.h:603
#define RAPIDJSON_UNLIKELY(x)
Compiler branching hint for expression with low probability to be true.
Definition: rapidjson.h:468
bool String(const Ch *str)
Simpler but slower overload.
Definition: writer.h:249
null
Definition: rapidjson.h:604
const Ch * head_
Original head of the string.
Definition: stream.h:125