Flow123d  JS_before_hm-913-g695b665
json_spirit_writer_template.h
Go to the documentation of this file.
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"
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 ); break;
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  {
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 >
273  {
274  output( *i );
275 
276  if( ++i != last )
277  {
278  os_ << ',';
279  }
280  }
281 
282  void output( const Array_type& arr )
283  {
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 
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 
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_;
348  bool pretty_;
349  bool raw_utf8_;
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;
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
String_type non_printable_to_string(unsigned int c)
String_type add_esc_chars(const String_type &s, bool raw_utf8)
void output(const String_type &s)
void erase_and_extract_exponent(String_type &str, String_type &exp)
String_type::value_type Char_type
Value_type::String_type write_string(const Value_type &value, unsigned int options=0)
void append_double(Ostream &os, const double d, const int precision)
Generator & operator=(const Generator &)
boost::io::basic_ios_all_saver< Char_type > ios_saver_
Object_type::value_type Obj_member_type
void output_int(const Value_type &value)
static constexpr bool value
Definition: json.hpp:87
bool add_esc_char(Char_type c, String_type &s)
char to_hex_char(unsigned int c)
Config_type::Array_type Array_type
void output(const Array_type &arr)
void write_stream(const Value_type &value, Ostream_type &os, unsigned int options=0)
void output_composite_item(Iter i, Iter last)
Config_type::String_type String_type
int get_value(const Value &value, Type_to_type< int >)
void remove_trailing(String_type &str)
void output(const Value_type &value)
String_type::size_type find_first_non_zero(const String_type &str)
void output_array_or_obj(const T &t, Char_type start_char, Char_type end_char)
Generator(const Value_type &value, Ostream_type &os, unsigned int options)
void output(const Obj_member_type &member)
Value_type::Config_type Config_type
Config_type::Object_type Object_type
static bool contains_composite_elements(const Array_type &arr)
void output(const Object_type &obj)
General iterator template. Provides iterator over objects of type ObjectIn in some container...