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