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 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
|
/* Copyright (C) 2014 SkySQL Ab, MariaDB Corporation Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
class Json_writer;
/*
Single_line_formatting_helper is used by Json_writer to do better formatting
of JSON documents.
The idea is to catch arrays that can be printed on one line:
arrayName : [ "boo", 123, 456 ]
and actually print them on one line. Arrrays that occupy too much space on
the line, or have nested members cannot be printed on one line.
We hook into JSON printing functions and try to detect the pattern. While
detecting the pattern, we will accumulate "boo", 123, 456 as strings.
Then,
- either the pattern is broken, and we print the elements out,
- or the pattern lasts till the end of the array, and we print the
array on one line.
*/
class Single_line_formatting_helper
{
enum enum_state
{
INACTIVE,
ADD_MEMBER,
IN_ARRAY,
DISABLED
};
/*
This works like a finite automaton.
state=DISABLED means the helper is disabled - all on_XXX functions will
return false (which means "not handled") and do nothing.
+->-+
| v
INACTIVE ---> ADD_MEMBER ---> IN_ARRAY--->-+
^ |
+------------------<--------------------+
For other states:
INACTIVE - initial state, we have nothing.
ADD_MEMBER - add_member() was called, the buffer has "member_name\0".
IN_ARRAY - start_array() was called.
*/
enum enum_state state;
enum { MAX_LINE_LEN= 80 };
char buffer[80];
/* The data in the buffer is located between buffer[0] and buf_ptr */
char *buf_ptr;
uint line_len;
Json_writer *owner;
public:
Single_line_formatting_helper() : state(INACTIVE), buf_ptr(buffer) {}
void init(Json_writer *owner_arg) { owner= owner_arg; }
bool on_add_member(const char *name);
bool on_start_array();
bool on_end_array();
void on_start_object();
// on_end_object() is not needed.
bool on_add_str(const char *str);
void flush_on_one_line();
void disable_and_flush();
};
/*
A class to write well-formed JSON documents. The documents are also formatted
for human readability.
*/
class Json_writer
{
public:
/* Add a member. We must be in an object. */
Json_writer& add_member(const char *name);
/* Add atomic values */
void add_str(const char* val);
void add_str(const String &str);
void add_ll(longlong val);
void add_ull(ulonglong val);
void add_size(longlong val);
void add_double(double val);
void add_bool(bool val);
void add_null();
private:
void add_unquoted_str(const char* val);
public:
/* Start a child object */
void start_object();
void start_array();
void end_object();
void end_array();
Json_writer() :
indent_level(0), document_start(true), element_started(false),
first_child(true)
{
fmt_helper.init(this);
}
private:
// TODO: a stack of (name, bool is_object_or_array) elements.
int indent_level;
enum { INDENT_SIZE = 2 };
friend class Single_line_formatting_helper;
friend class Json_writer_nesting_guard;
bool document_start;
bool element_started;
bool first_child;
Single_line_formatting_helper fmt_helper;
void append_indent();
void start_element();
void start_sub_element();
//const char *new_member_name;
public:
String output;
};
/*
RAII-based helper class to detect incorrect use of Json_writer.
The idea is that a function typically must leave Json_writer at the same
identation level as it was when it was invoked. Leaving it at a different
level typically means we forgot to close an object or an array
So, here is a way to guard
void foo(Json_writer *writer)
{
Json_writer_nesting_guard(writer);
.. do something with writer
// at the end of the function, ~Json_writer_nesting_guard() is called
// and it makes sure that the nesting is the same as when the function was
// entered.
}
*/
class Json_writer_nesting_guard
{
Json_writer* writer;
int indent_level;
public:
Json_writer_nesting_guard(Json_writer *writer_arg) :
writer(writer_arg),
indent_level(writer->indent_level)
{}
~Json_writer_nesting_guard()
{
DBUG_ASSERT(indent_level == writer->indent_level);
}
};
|