summaryrefslogtreecommitdiff
path: root/include/rapidjson/prettywriter.h
blob: 238ff5ff629aa29ca9bd6dde1ea9dddd24ff9c4d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#ifndef RAPIDJSON_PRETTYWRITER_H_
#define RAPIDJSON_PRETTYWRITER_H_

#include "writer.h"

namespace rapidjson {

//! Writer with indentation and spacing.
/*!
	\tparam Stream Type of ouptut stream.
	\tparam Encoding Encoding of both source strings and output.
	\tparam Allocator Type of allocator for allocating memory of stack.
*/
template<typename Stream, typename Encoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
class PrettyWriter : public Writer<Stream, Encoding, Allocator> {
public:
	typedef Writer<Stream, Encoding, Allocator> Base;
	typedef typename Base::Ch Ch;

	//! Constructor
	/*! \param stream Output stream.
		\param allocator User supplied allocator. If it is null, it will create a private one.
		\param levelDepth Initial capacity of 
	*/
	PrettyWriter(Stream& stream, Allocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : 
		Base(stream, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}

	//! Set custom indentation.
	/*! \param indentChar		Character for indentation. Must be whitespace character (' ', '\t', '\n', '\r').
		\param indentCharCount	Number of indent characters for each indentation level.
		\note The default indentation is 4 spaces.
	*/
	PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
		RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
		indentChar_ = indentChar;
		indentCharCount_ = indentCharCount;
		return *this;
	}

	//@name Implementation of Handler.
	//@{

	PrettyWriter& Null()				{ PrettyPrefix(kNullType);   Base::WriteNull();			return *this; }
	PrettyWriter& Bool(bool b)			{ PrettyPrefix(b ? kTrueType : kFalseType); Base::WriteBool(b); return *this; }
	PrettyWriter& Int(int i)			{ PrettyPrefix(kNumberType); Base::WriteInt(i);			return *this; }
	PrettyWriter& Uint(unsigned u)		{ PrettyPrefix(kNumberType); Base::WriteUint(u);		return *this; }
	PrettyWriter& Int64(int64_t i64)	{ PrettyPrefix(kNumberType); Base::WriteInt64(i64);		return *this; }
	PrettyWriter& Uint64(uint64_t u64)	{ PrettyPrefix(kNumberType); Base::WriteUint64(u64);	return *this; }
	PrettyWriter& Double(double d)		{ PrettyPrefix(kNumberType); Base::WriteDouble(d);		return *this; }

	PrettyWriter& String(const Ch* str, SizeType length, bool copy = false) {
		(void)copy;
		PrettyPrefix(kStringType);
		Base::WriteString(str, length);
		return *this;
	}

	PrettyWriter& StartObject() {
		PrettyPrefix(kObjectType);
		new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
		Base::WriteStartObject();
		return *this;
	}

	PrettyWriter& EndObject(SizeType memberCount = 0) {
		(void)memberCount;
		RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
		RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
		bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;

		if (!empty) {
			Base::stream_.Put('\n');
			WriteIndent();
		}
		Base::WriteEndObject();
		return *this;
	}

	PrettyWriter& StartArray() {
		PrettyPrefix(kArrayType);
		new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
		Base::WriteStartArray();
		return *this;
	}

	PrettyWriter& EndArray(SizeType memberCount = 0) {
		(void)memberCount;
		RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
		RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
		bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;

		if (!empty) {
			Base::stream_.Put('\n');
			WriteIndent();
		}
		Base::WriteEndArray();
		return *this;
	}

	//@}

	//! Simpler but slower overload.
	PrettyWriter& String(const Ch* str) { return String(str, internal::StrLen(str)); }

protected:
	void PrettyPrefix(Type type) {
		(void)type;
		if (Base::level_stack_.GetSize() != 0) { // this value is not at root
			typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();

			if (level->inArray) {
				if (level->valueCount > 0) {
					Base::stream_.Put(','); // add comma if it is not the first element in array
					Base::stream_.Put('\n');
				}
				else
					Base::stream_.Put('\n');
				WriteIndent();
			}
			else {	// in object
				if (level->valueCount > 0) {
					if (level->valueCount % 2 == 0) {
						Base::stream_.Put(',');
						Base::stream_.Put('\n');
					}
					else {
						Base::stream_.Put(':');
						Base::stream_.Put(' ');
					}
				}
				else
					Base::stream_.Put('\n');

				if (level->valueCount % 2 == 0)
					WriteIndent();
			}
			if (!level->inArray && level->valueCount % 2 == 0)
				RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name
			level->valueCount++;
		}
		else
			RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
	}

	void WriteIndent()  {
		size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
		PutN(Base::stream_, indentChar_, count);
	}

	Ch indentChar_;
	unsigned indentCharCount_;
};

} // namespace rapidjson

#endif // RAPIDJSON_RAPIDJSON_H_