Skip to content

Commit 35ac459

Browse files
committed
Introduce class for streaming JSON to the output
Introduce a new json object class that streams the object immediately to an output instead of building the object in memory and then output it to the stream.
1 parent f3cb5bb commit 35ac459

File tree

5 files changed

+381
-19
lines changed

5 files changed

+381
-19
lines changed

src/util/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ SRC = arith_tools.cpp \
3737
json.cpp \
3838
json_expr.cpp \
3939
json_irep.cpp \
40+
json_stream.cpp \
4041
lispexpr.cpp \
4142
lispirep.cpp \
4243
memory_info.cpp \

src/util/json.cpp

+39-17
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ void jsont::escape_string(const std::string &src, std::ostream &out)
5050
}
5151
}
5252

53+
/// Recursive printing of the json object.
54+
/// \param out: The stream object to have the json printed to.
55+
/// \param indent: The indentation level.
5356
void jsont::output_rec(std::ostream &out, unsigned indent) const
5457
{
5558
switch(kind)
@@ -66,23 +69,7 @@ void jsont::output_rec(std::ostream &out, unsigned indent) const
6669

6770
case kindt::J_OBJECT:
6871
out << '{';
69-
for(objectt::const_iterator o_it=object.begin();
70-
o_it!=object.end();
71-
o_it++)
72-
{
73-
if(o_it!=object.begin())
74-
out << ',';
75-
76-
out << '\n';
77-
78-
out << std::string((indent+1)*2, ' ');
79-
80-
out << '"';
81-
escape_string(o_it->first, out);
82-
out << '"';
83-
out << ": ";
84-
o_it->second.output_rec(out, indent+1);
85-
}
72+
output_object(out, object, indent);
8673
if(!object.empty())
8774
{
8875
out << '\n';
@@ -133,6 +120,41 @@ void jsont::output_rec(std::ostream &out, unsigned indent) const
133120
}
134121
}
135122

123+
/// Basic handling of the printing of a JSON object.
124+
/// Dispatches to output_rec for most of the hard work.
125+
/// \param out: The stream that the JSON object is to be
126+
/// printed to.
127+
/// \param object: The JSON object.
128+
/// \param indent: The indentation level.
129+
void jsont::output_object(
130+
std::ostream &out,
131+
const objectt &object,
132+
unsigned indent)
133+
{
134+
for(objectt::const_iterator o_it = object.begin(); o_it != object.end();
135+
o_it++)
136+
{
137+
if(o_it != object.begin())
138+
out << ',';
139+
140+
// A JSON object always starts with an opening brace,
141+
// after which we put a newline.
142+
out << '\n';
143+
144+
out << std::string((indent + 1) * 2, ' ');
145+
146+
jsont::output_key(out, o_it->first);
147+
o_it->second.output_rec(out, indent + 1);
148+
}
149+
}
150+
151+
void jsont::output_key(std::ostream &out, const std::string &key)
152+
{
153+
out << '"';
154+
jsont::escape_string(key, out);
155+
out << "\": ";
156+
}
157+
136158
void jsont::swap(jsont &other)
137159
{
138160
std::swap(other.kind, kind);

src/util/json.h

+6-2
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,13 @@ class jsont
106106
return it->second;
107107
}
108108

109-
protected:
110109
void output_rec(std::ostream &, unsigned indent) const;
111-
static void escape_string(const std::string &, std::ostream &);
112110

113111
static const jsont null_json_object;
114112

113+
protected:
114+
static void escape_string(const std::string &, std::ostream &);
115+
115116
explicit jsont(kindt _kind):kind(_kind)
116117
{
117118
}
@@ -127,6 +128,9 @@ class jsont
127128

128129
typedef std::map<std::string, jsont> objectt;
129130
objectt object;
131+
static void
132+
output_object(std::ostream &out, const objectt &object, unsigned indent);
133+
static void output_key(std::ostream &out, const std::string &key);
130134

131135
std::string value;
132136
};

src/util/json_stream.cpp

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/*******************************************************************\
2+
3+
Module:
4+
5+
Author: Peter Schrammel
6+
7+
\*******************************************************************/
8+
9+
#include "json_stream.h"
10+
11+
#include <ostream>
12+
13+
/// Output the element delimiter to the output stream
14+
void json_streamt::output_delimiter()
15+
{
16+
if(!first)
17+
out << ',';
18+
else
19+
first = false;
20+
out << '\n';
21+
out << std::string((indent + 1) * 2, ' ');
22+
}
23+
24+
/// Construct a new JSON array stream
25+
/// \param out: output stream
26+
/// \param indent: indentation level
27+
json_stream_arrayt::json_stream_arrayt(std::ostream &out, unsigned indent)
28+
: json_streamt(out, indent)
29+
{
30+
out << '[';
31+
}
32+
33+
/// Output the non-streaming JSON objects and closes the current child stream
34+
void json_stream_arrayt::output_child_stream()
35+
{
36+
if(!object.empty())
37+
{
38+
output_delimiter();
39+
object["array_element"].output_rec(out, indent + 1);
40+
object.clear();
41+
}
42+
if(child_stream)
43+
{
44+
child_stream->close();
45+
child_stream = nullptr;
46+
}
47+
}
48+
49+
/// Output the finalizing character for a JSON array
50+
void json_stream_arrayt::output_finalizer()
51+
{
52+
out << '\n' << std::string(indent * 2, ' ');
53+
out << ']';
54+
}
55+
56+
/// Constructor for json_stream_objectt.
57+
/// \param out: The stream that is to be used to output the JSON object.
58+
/// \param indent: Current indentation level.
59+
json_stream_objectt::json_stream_objectt(std::ostream &out, unsigned indent)
60+
: json_streamt(out, indent)
61+
{
62+
out << '{';
63+
}
64+
65+
/// Create a new JSON array child stream.
66+
json_stream_arrayt &json_streamt::create_child_stream_array()
67+
{
68+
child_stream =
69+
std::unique_ptr<json_streamt>(new json_stream_arrayt(out, indent + 1));
70+
return static_cast<json_stream_arrayt &>(*child_stream);
71+
}
72+
73+
/// Create a new JSON object child stream.
74+
json_stream_objectt &json_streamt::create_child_stream_object()
75+
{
76+
child_stream =
77+
std::unique_ptr<json_streamt>(new json_stream_objectt(out, indent + 1));
78+
return static_cast<json_stream_objectt &>(*child_stream);
79+
}
80+
81+
/// Add a JSON object child stream
82+
json_stream_objectt &json_stream_arrayt::push_back_stream_object()
83+
{
84+
PRECONDITION(open);
85+
// To ensure consistency of the output, we flush and
86+
// close the current child stream before creating the new one.
87+
output_child_stream();
88+
output_delimiter();
89+
return create_child_stream_object();
90+
}
91+
92+
/// Add a JSON array child stream
93+
json_stream_arrayt &json_stream_arrayt::push_back_stream_array()
94+
{
95+
PRECONDITION(open);
96+
// To ensure consistency of the output, we flush and
97+
// close the current child stream before creating the new one.
98+
output_child_stream();
99+
output_delimiter();
100+
return create_child_stream_array();
101+
}
102+
103+
/// Add a JSON object stream for a specific key
104+
/// \param key: key of the JSON property
105+
json_stream_objectt &
106+
json_stream_objectt::push_back_stream_object(const std::string &key)
107+
{
108+
PRECONDITION(open);
109+
// To ensure consistency of the output, we flush and
110+
// close the current child stream before creating the new one.
111+
output_child_stream();
112+
output_delimiter();
113+
jsont::output_key(out, key);
114+
return create_child_stream_object();
115+
}
116+
117+
/// Add a JSON array stream for a specific key
118+
/// \param key: key of the JSON property
119+
json_stream_arrayt &
120+
json_stream_objectt::push_back_stream_array(const std::string &key)
121+
{
122+
PRECONDITION(open);
123+
// To ensure consistency of the output, we flush and
124+
// close the current child stream before creating the new one.
125+
output_child_stream();
126+
output_delimiter();
127+
jsont::output_key(out, key);
128+
return create_child_stream_array();
129+
}
130+
131+
/// Output non-streaming JSON properties and flushes and closes
132+
/// the child stream
133+
void json_stream_objectt::output_child_stream()
134+
{
135+
for(const auto &obj : object)
136+
{
137+
output_delimiter();
138+
jsont::output_key(out, obj.first);
139+
obj.second.output_rec(out, indent + 1);
140+
}
141+
object.clear();
142+
if(child_stream)
143+
{
144+
child_stream->close();
145+
child_stream = nullptr;
146+
}
147+
}
148+
149+
/// Output the finalizing character for a JSON object
150+
void json_stream_objectt::output_finalizer()
151+
{
152+
jsont::output_object(out, object, indent);
153+
out << '\n' << std::string(indent * 2, ' ');
154+
out << '}';
155+
}

0 commit comments

Comments
 (0)