]> git.proxmox.com Git - ceph.git/blame - ceph/src/json_spirit/json_spirit_writer_template.h
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / json_spirit / json_spirit_writer_template.h
CommitLineData
7c673cae
FG
1#ifndef JSON_SPIRIT_WRITER_TEMPLATE\r
2#define JSON_SPIRIT_WRITER_TEMPLATE\r
3\r
4// Copyright John W. Wilkinson 2007 - 2011\r
5// Distributed under the MIT License, see accompanying file LICENSE.txt\r
6\r
7// json spirit version 4.05\r
8\r
9#if defined(_MSC_VER) && (_MSC_VER >= 1020)\r
10# pragma once\r
11#endif\r
12\r
13#include "json_spirit_value.h"\r
14#include "json_spirit_writer_options.h"\r
15\r
16#include <cassert>\r
17#include <sstream>\r
18#include <iomanip>\r
19#include <boost/io/ios_state.hpp>\r
20\r
21namespace json_spirit\r
22{\r
23 inline char to_hex_char( unsigned int c )\r
24 {\r
25 assert( c <= 0xF );\r
26\r
27 const char ch = static_cast< char >( c );\r
28\r
29 if( ch < 10 ) return '0' + ch;\r
30\r
31 return 'A' - 10 + ch;\r
32 }\r
33\r
34 template< class String_type >\r
35 String_type non_printable_to_string( unsigned int c )\r
36 {\r
37 String_type result( 6, '\\' );\r
38\r
39 result[1] = 'u';\r
40\r
41 result[ 5 ] = to_hex_char( c & 0x000F ); c >>= 4;\r
42 result[ 4 ] = to_hex_char( c & 0x000F ); c >>= 4;\r
43 result[ 3 ] = to_hex_char( c & 0x000F ); c >>= 4;\r
44 result[ 2 ] = to_hex_char( c & 0x000F );\r
45\r
46 return result;\r
47 }\r
48\r
49 template< typename Char_type, class String_type >\r
50 bool add_esc_char( Char_type c, String_type& s )\r
51 {\r
52 switch( c )\r
53 {\r
54 case '"': s += to_str< String_type >( "\\\"" ); return true;\r
55 case '\\': s += to_str< String_type >( "\\\\" ); return true;\r
56 case '\b': s += to_str< String_type >( "\\b" ); return true;\r
57 case '\f': s += to_str< String_type >( "\\f" ); return true;\r
58 case '\n': s += to_str< String_type >( "\\n" ); return true;\r
59 case '\r': s += to_str< String_type >( "\\r" ); return true;\r
60 case '\t': s += to_str< String_type >( "\\t" ); return true;\r
61 }\r
62\r
63 return false;\r
64 }\r
65\r
66 template< class String_type >\r
67 String_type add_esc_chars( const String_type& s, bool raw_utf8 )\r
68 {\r
69 typedef typename String_type::const_iterator Iter_type;\r
70 typedef typename String_type::value_type Char_type;\r
71\r
72 String_type result;\r
73\r
74 const Iter_type end( s.end() );\r
75\r
76 for( Iter_type i = s.begin(); i != end; ++i )\r
77 {\r
78 const Char_type c( *i );\r
79\r
80 if( add_esc_char( c, result ) ) continue;\r
81\r
82 if( raw_utf8 )\r
83 {\r
84 result += c;\r
85 }\r
86 else\r
87 {\r
88 const wint_t unsigned_c( ( c >= 0 ) ? c : 256 + c );\r
89\r
90 if( iswprint( unsigned_c ) )\r
91 {\r
92 result += c;\r
93 }\r
94 else\r
95 {\r
96 result += non_printable_to_string< String_type >( unsigned_c );\r
97 }\r
98 }\r
99 }\r
100\r
101 return result;\r
102 }\r
103\r
104 template< class Ostream >\r
105 void append_double( Ostream& os, const double d, const int precision )\r
106 {\r
107 os << std::showpoint << std::setprecision( precision ) << d;\r
108 }\r
109\r
110 template< class String_type >\r
111 void erase_and_extract_exponent( String_type& str, String_type& exp )\r
112 {\r
113 const typename String_type::size_type exp_start= str.find( 'e' );\r
114\r
115 if( exp_start != String_type::npos )\r
116 {\r
117 exp = str.substr( exp_start );\r
118 str.erase( exp_start );\r
119 }\r
120 }\r
121\r
122 template< class String_type >\r
123 typename String_type::size_type find_first_non_zero( const String_type& str )\r
124 {\r
125 typename String_type::size_type result = str.size() - 1;\r
126\r
127 for( ; result != 0; --result )\r
128 {\r
129 if( str[ result ] != '0' )\r
130 {\r
131 break;\r
132 }\r
133 }\r
134\r
135 return result;\r
136 }\r
137\r
138 template< class String_type >\r
139 void remove_trailing( String_type& str )\r
140 {\r
141 String_type exp;\r
142\r
143 erase_and_extract_exponent( str, exp );\r
144\r
145 const typename String_type::size_type first_non_zero = find_first_non_zero( str );\r
146\r
147 if( first_non_zero != 0 )\r
148 {\r
149 const int offset = str[first_non_zero] == '.' ? 2 : 1; // note zero digits following a decimal point is non standard\r
150 str.erase( first_non_zero + offset );\r
151 }\r
152\r
153 str += exp;\r
154 }\r
155\r
156 // this class generates the JSON text,\r
157 // it keeps track of the indentation level etc.\r
158 //\r
159 template< class Value_type, class Ostream_type >\r
160 class Generator\r
161 {\r
162 typedef typename Value_type::Config_type Config_type;\r
163 typedef typename Config_type::String_type String_type;\r
164 typedef typename Config_type::Object_type Object_type;\r
165 typedef typename Config_type::Array_type Array_type;\r
166 typedef typename String_type::value_type Char_type;\r
167 typedef typename Object_type::value_type Obj_member_type;\r
168\r
169 public:\r
170\r
171 Generator( const Value_type& value, Ostream_type& os, unsigned int options )\r
172 : os_( os )\r
173 , indentation_level_( 0 )\r
174 , pretty_( ( options & pretty_print ) != 0 || ( options & single_line_arrays ) != 0 )\r
175 , raw_utf8_( ( options & raw_utf8 ) != 0 )\r
176 , remove_trailing_zeros_( ( options & remove_trailing_zeros ) != 0 )\r
177 , single_line_arrays_( ( options & single_line_arrays ) != 0 )\r
178 , ios_saver_( os )\r
179 {\r
180 output( value );\r
181 }\r
182\r
183 private:\r
184\r
185 void output( const Value_type& value )\r
186 {\r
187 switch( value.type() )\r
188 {\r
189 case obj_type: output( value.get_obj() ); break;\r
190 case array_type: output( value.get_array() ); break;\r
191 case str_type: output( value.get_str() ); break;\r
192 case bool_type: output( value.get_bool() ); break;\r
193 case real_type: output( value.get_real() ); break;\r
194 case int_type: output_int( value ); break;\r
195 case null_type: os_ << "null"; break;\r
196 default: assert( false );\r
197 }\r
198 }\r
199\r
200 void output( const Object_type& obj )\r
201 {\r
202 output_array_or_obj( obj, '{', '}' );\r
203 }\r
204\r
205 void output( const Obj_member_type& member )\r
206 {\r
207 output( Config_type::get_name( member ) ); space(); \r
208 os_ << ':'; space(); \r
209 output( Config_type::get_value( member ) );\r
210 }\r
211\r
212 void output_int( const Value_type& value )\r
213 {\r
214 if( value.is_uint64() )\r
215 {\r
216 os_ << value.get_uint64();\r
217 }\r
218 else\r
219 {\r
220 os_ << value.get_int64();\r
221 }\r
222 }\r
223\r
224 void output( const String_type& s )\r
225 {\r
226 os_ << '"' << add_esc_chars( s, raw_utf8_ ) << '"';\r
227 }\r
228\r
229 void output( bool b )\r
230 {\r
231 os_ << to_str< String_type >( b ? "true" : "false" );\r
232 }\r
233\r
234 void output( double d )\r
235 {\r
236 if( remove_trailing_zeros_ )\r
237 {\r
238 std::basic_ostringstream< Char_type > os;\r
239\r
240 append_double( os, d, 16 ); // note precision is 16 so that we get some trailing space that we can remove,\r
241 // otherwise, 0.1234 gets converted to "0.12399999..."\r
242\r
243 String_type str = os.str();\r
244\r
245 remove_trailing( str );\r
246\r
247 os_ << str;\r
248 }\r
249 else\r
250 {\r
251 append_double( os_, d, 17 );\r
252 }\r
253 }\r
254\r
255 static bool contains_composite_elements( const Array_type& arr )\r
256 {\r
257 for( typename Array_type::const_iterator i = arr.begin(); i != arr.end(); ++i )\r
258 {\r
259 const Value_type& val = *i;\r
260\r
261 if( val.type() == obj_type ||\r
262 val.type() == array_type )\r
263 {\r
264 return true;\r
265 }\r
266 }\r
267\r
268 return false;\r
269 }\r
270\r
271 template< class Iter >\r
272 void output_composite_item( Iter i, Iter last )\r
273 {\r
274 output( *i );\r
275\r
276 if( ++i != last )\r
277 {\r
278 os_ << ',';\r
279 }\r
280 }\r
281\r
282 void output( const Array_type& arr )\r
283 {\r
284 if( single_line_arrays_ && !contains_composite_elements( arr ) )\r
285 {\r
286 os_ << '['; space();\r
287 \r
288 for( typename Array_type::const_iterator i = arr.begin(); i != arr.end(); ++i )\r
289 {\r
290 output_composite_item( i, arr.end() );\r
291\r
292 space();\r
293 }\r
294\r
295 os_ << ']';\r
296 }\r
297 else\r
298 {\r
299 output_array_or_obj( arr, '[', ']' );\r
300 }\r
301 }\r
302\r
303 template< class T >\r
304 void output_array_or_obj( const T& t, Char_type start_char, Char_type end_char )\r
305 {\r
306 os_ << start_char; new_line();\r
307\r
308 ++indentation_level_;\r
309 \r
310 for( typename T::const_iterator i = t.begin(); i != t.end(); ++i )\r
311 {\r
312 indent();\r
313\r
314 output_composite_item( i, t.end() );\r
315\r
316 new_line();\r
317 }\r
318\r
319 --indentation_level_;\r
320\r
321 indent(); os_ << end_char;\r
322 }\r
323 \r
324 void indent()\r
325 {\r
326 if( !pretty_ ) return;\r
327\r
328 for( int i = 0; i < indentation_level_; ++i )\r
329 { \r
330 os_ << " ";\r
331 }\r
332 }\r
333\r
334 void space()\r
335 {\r
336 if( pretty_ ) os_ << ' ';\r
337 }\r
338\r
339 void new_line()\r
340 {\r
341 if( pretty_ ) os_ << '\n';\r
342 }\r
343\r
344 Generator& operator=( const Generator& ); // to prevent "assignment operator could not be generated" warning\r
345\r
346 Ostream_type& os_;\r
347 int indentation_level_;\r
348 bool pretty_;\r
349 bool raw_utf8_;\r
350 bool remove_trailing_zeros_;\r
351 bool single_line_arrays_;\r
352 boost::io::basic_ios_all_saver< Char_type > ios_saver_; // so that ostream state is reset after control is returned to the caller\r
353 };\r
354\r
355 // writes JSON Value to a stream, e.g.\r
356 //\r
357 // write_stream( value, os, pretty_print );\r
358 //\r
359 template< class Value_type, class Ostream_type >\r
360 void write_stream( const Value_type& value, Ostream_type& os, unsigned int options = 0 )\r
361 {\r
362 os << std::dec;\r
363 Generator< Value_type, Ostream_type >( value, os, options );\r
364 }\r
365\r
366 // writes JSON Value to a stream, e.g.\r
367 //\r
368 // const string json_str = write( value, pretty_print );\r
369 //\r
370 template< class Value_type >\r
371 typename Value_type::String_type write_string( const Value_type& value, unsigned int options = 0 )\r
372 {\r
373 typedef typename Value_type::String_type::value_type Char_type;\r
374\r
375 std::basic_ostringstream< Char_type > os;\r
376\r
377 write_stream( value, os, options );\r
378\r
379 return os.str();\r
380 }\r
381}\r
382\r
383#endif\r