rapidjson
A fast JSON parser/generator for C++ with both SAX/DOM style API
 All Classes Functions Variables Typedefs Pages
prettywriter.h
1 #ifndef RAPIDJSON_PRETTYWRITER_H_
2 #define RAPIDJSON_PRETTYWRITER_H_
3 
4 #include "writer.h"
5 
6 namespace rapidjson {
7 
8 //! Writer with indentation and spacing.
9 /*!
10  \tparam Stream Type of ouptut stream.
11  \tparam Encoding Encoding of both source strings and output.
12  \tparam Allocator Type of allocator for allocating memory of stack.
13 */
14 template<typename Stream, typename Encoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
15 class PrettyWriter : public Writer<Stream, Encoding, Allocator> {
16 public:
18  typedef typename Base::Ch Ch;
19 
20  //! Constructor
21  /*! \param stream Output stream.
22  \param allocator User supplied allocator. If it is null, it will create a private one.
23  \param levelDepth Initial capacity of
24  */
25  PrettyWriter(Stream& stream, Allocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
26  Base(stream, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
27 
28  //! Set custom indentation.
29  /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\t', '\n', '\r').
30  \param indentCharCount Number of indent characters for each indentation level.
31  \note The default indentation is 4 spaces.
32  */
33  PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
34  RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
35  indentChar_ = indentChar;
36  indentCharCount_ = indentCharCount;
37  return *this;
38  }
39 
40  //@name Implementation of Handler.
41  //@{
42 
43  PrettyWriter& Null() { PrettyPrefix(kNullType); Base::WriteNull(); return *this; }
44  PrettyWriter& Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); Base::WriteBool(b); return *this; }
45  PrettyWriter& Int(int i) { PrettyPrefix(kNumberType); Base::WriteInt(i); return *this; }
46  PrettyWriter& Uint(unsigned u) { PrettyPrefix(kNumberType); Base::WriteUint(u); return *this; }
47  PrettyWriter& Int64(int64_t i64) { PrettyPrefix(kNumberType); Base::WriteInt64(i64); return *this; }
48  PrettyWriter& Uint64(uint64_t u64) { PrettyPrefix(kNumberType); Base::WriteUint64(u64); return *this; }
49  PrettyWriter& Double(double d) { PrettyPrefix(kNumberType); Base::WriteDouble(d); return *this; }
50 
51  PrettyWriter& String(const Ch* str, SizeType length, bool copy = false) {
52  (void)copy;
53  PrettyPrefix(kStringType);
54  Base::WriteString(str, length);
55  return *this;
56  }
57 
58  PrettyWriter& StartObject() {
59  PrettyPrefix(kObjectType);
60  new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
61  Base::WriteStartObject();
62  return *this;
63  }
64 
65  PrettyWriter& EndObject(SizeType memberCount = 0) {
66  (void)memberCount;
67  RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
68  RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
69  bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
70 
71  if (!empty) {
72  Base::stream_.Put('\n');
73  WriteIndent();
74  }
75  Base::WriteEndObject();
76  return *this;
77  }
78 
79  PrettyWriter& StartArray() {
80  PrettyPrefix(kArrayType);
81  new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
82  Base::WriteStartArray();
83  return *this;
84  }
85 
86  PrettyWriter& EndArray(SizeType memberCount = 0) {
87  (void)memberCount;
88  RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
89  RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
90  bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
91 
92  if (!empty) {
93  Base::stream_.Put('\n');
94  WriteIndent();
95  }
96  Base::WriteEndArray();
97  return *this;
98  }
99 
100  //@}
101 
102  //! Simpler but slower overload.
103  PrettyWriter& String(const Ch* str) { return String(str, internal::StrLen(str)); }
104 
105 protected:
106  void PrettyPrefix(Type type) {
107  (void)type;
108  if (Base::level_stack_.GetSize() != 0) { // this value is not at root
109  typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
110 
111  if (level->inArray) {
112  if (level->valueCount > 0) {
113  Base::stream_.Put(','); // add comma if it is not the first element in array
114  Base::stream_.Put('\n');
115  }
116  else
117  Base::stream_.Put('\n');
118  WriteIndent();
119  }
120  else { // in object
121  if (level->valueCount > 0) {
122  if (level->valueCount % 2 == 0) {
123  Base::stream_.Put(',');
124  Base::stream_.Put('\n');
125  }
126  else {
127  Base::stream_.Put(':');
128  Base::stream_.Put(' ');
129  }
130  }
131  else
132  Base::stream_.Put('\n');
133 
134  if (level->valueCount % 2 == 0)
135  WriteIndent();
136  }
137  if (!level->inArray && level->valueCount % 2 == 0)
138  RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
139  level->valueCount++;
140  }
141  else
142  RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
143  }
144 
145  void WriteIndent() {
146  size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
147  PutN(Base::stream_, indentChar_, count);
148  }
149 
150  Ch indentChar_;
151  unsigned indentCharCount_;
152 };
153 
154 } // namespace rapidjson
155 
156 #endif // RAPIDJSON_RAPIDJSON_H_