Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / json_spirit / json_spirit_writer_template.h
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
21 namespace 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