identt
prettywriter.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_PRETTYWRITER_H_
16 #define RAPIDJSON_PRETTYWRITER_H_
17 
18 #include "writer.h"
19 
20 #ifdef __GNUC__
21 RAPIDJSON_DIAG_PUSH
22 RAPIDJSON_DIAG_OFF(effc++)
23 #endif
24 
25 #if defined(__clang__)
26 RAPIDJSON_DIAG_PUSH
27 RAPIDJSON_DIAG_OFF(c++98-compat)
28 #endif
29 
31 
33 
35 enum PrettyFormatOptions {
36  kFormatDefault = 0,
37  kFormatSingleLineArray = 1
38 };
39 
41 
47 template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
48 class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> {
49 public:
51  typedef typename Base::Ch Ch;
52 
54 
58  explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
59  Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}
60 
61 
62  explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
63  Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
64 
65 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
66  PrettyWriter(PrettyWriter&& rhs) :
67  Base(std::forward<PrettyWriter>(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {}
68 #endif
69 
71 
75  PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
76  RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
77  indentChar_ = indentChar;
78  indentCharCount_ = indentCharCount;
79  return *this;
80  }
81 
83 
85  PrettyWriter& SetFormatOptions(PrettyFormatOptions options) {
86  formatOptions_ = options;
87  return *this;
88  }
89 
94 
95  bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); }
96  bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); }
97  bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); }
98  bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); }
99  bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); }
100  bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); }
101  bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }
102 
103  bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
104  RAPIDJSON_ASSERT(str != 0);
105  (void)copy;
106  PrettyPrefix(kNumberType);
107  return Base::WriteString(str, length);
108  }
109 
110  bool String(const Ch* str, SizeType length, bool copy = false) {
111  RAPIDJSON_ASSERT(str != 0);
112  (void)copy;
113  PrettyPrefix(kStringType);
114  return Base::WriteString(str, length);
115  }
116 
117 #if RAPIDJSON_HAS_STDSTRING
118  bool String(const std::basic_string<Ch>& str) {
119  return String(str.data(), SizeType(str.size()));
120  }
121 #endif
122 
123  bool StartObject() {
124  PrettyPrefix(kObjectType);
125  new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
126  return Base::WriteStartObject();
127  }
128 
129  bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
130 
131 #if RAPIDJSON_HAS_STDSTRING
132  bool Key(const std::basic_string<Ch>& str) {
133  return Key(str.data(), SizeType(str.size()));
134  }
135 #endif
136 
137  bool EndObject(SizeType memberCount = 0) {
138  (void)memberCount;
139  RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
140  RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
141  bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
142 
143  if (!empty) {
144  Base::os_->Put('\n');
145  WriteIndent();
146  }
147  bool ret = Base::WriteEndObject();
148  (void)ret;
149  RAPIDJSON_ASSERT(ret == true);
150  if (Base::level_stack_.Empty()) // end of json text
151  Base::os_->Flush();
152  return true;
153  }
154 
155  bool StartArray() {
156  PrettyPrefix(kArrayType);
157  new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
158  return Base::WriteStartArray();
159  }
160 
161  bool EndArray(SizeType memberCount = 0) {
162  (void)memberCount;
163  RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
164  RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
165  bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
166 
167  if (!empty && !(formatOptions_ & kFormatSingleLineArray)) {
168  Base::os_->Put('\n');
169  WriteIndent();
170  }
171  bool ret = Base::WriteEndArray();
172  (void)ret;
173  RAPIDJSON_ASSERT(ret == true);
174  if (Base::level_stack_.Empty()) // end of json text
175  Base::os_->Flush();
176  return true;
177  }
178 
180 
183 
185  bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
186  bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
187 
189 
191 
199  bool RawValue(const Ch* json, size_t length, Type type) {
200  RAPIDJSON_ASSERT(json != 0);
201  PrettyPrefix(type);
202  return Base::WriteRawValue(json, length);
203  }
204 
205 protected:
206  void PrettyPrefix(Type type) {
207  (void)type;
208  if (Base::level_stack_.GetSize() != 0) { // this value is not at root
209  typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
210 
211  if (level->inArray) {
212  if (level->valueCount > 0) {
213  Base::os_->Put(','); // add comma if it is not the first element in array
214  if (formatOptions_ & kFormatSingleLineArray)
215  Base::os_->Put(' ');
216  }
217 
218  if (!(formatOptions_ & kFormatSingleLineArray)) {
219  Base::os_->Put('\n');
220  WriteIndent();
221  }
222  }
223  else { // in object
224  if (level->valueCount > 0) {
225  if (level->valueCount % 2 == 0) {
226  Base::os_->Put(',');
227  Base::os_->Put('\n');
228  }
229  else {
230  Base::os_->Put(':');
231  Base::os_->Put(' ');
232  }
233  }
234  else
235  Base::os_->Put('\n');
236 
237  if (level->valueCount % 2 == 0)
238  WriteIndent();
239  }
240  if (!level->inArray && level->valueCount % 2 == 0)
241  RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
242  level->valueCount++;
243  }
244  else {
245  RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root.
246  Base::hasRoot_ = true;
247  }
248  }
249 
250  void WriteIndent() {
251  size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
252  PutN(*Base::os_, static_cast<typename TargetEncoding::Ch>(indentChar_), count);
253  }
254 
255  Ch indentChar_;
256  unsigned indentCharCount_;
257  PrettyFormatOptions formatOptions_;
258 
259 private:
260  // Prohibit copy constructor & assignment operator.
261  PrettyWriter(const PrettyWriter&);
262  PrettyWriter& operator=(const PrettyWriter&);
263 };
264 
266 
267 #if defined(__clang__)
268 RAPIDJSON_DIAG_POP
269 #endif
270 
271 #ifdef __GNUC__
272 RAPIDJSON_DIAG_POP
273 #endif
274 
275 #endif // RAPIDJSON_RAPIDJSON_H_
bool RawValue(const Ch *json, size_t length, Type type)
Write a raw JSON value.
Definition: prettywriter.h:199
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
PrettyWriter & SetIndent(Ch indentChar, unsigned indentCharCount)
Set custom indentation.
Definition: prettywriter.h:75
bool String(const Ch *str)
Simpler but slower overload.
Definition: prettywriter.h:185
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
Definition: rapidjson.h:119
array
Definition: rapidjson.h:608
false
Definition: rapidjson.h:605
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
Definition: rapidjson.h:116
Information for each nested level.
Definition: writer.h:270
string
Definition: rapidjson.h:609
number
Definition: rapidjson.h:610
PrettyWriter(OutputStream &os, StackAllocator *allocator=0, size_t levelDepth=Base::kDefaultLevelDepth)
Constructor.
Definition: prettywriter.h:58
true
Definition: rapidjson.h:606
Type
Type of JSON value.
Definition: rapidjson.h:603
PrettyWriter & SetFormatOptions(PrettyFormatOptions options)
Set pretty writer formatting options.
Definition: prettywriter.h:85
Writer with indentation and spacing.
Definition: fwd.h:100
null
Definition: rapidjson.h:604