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