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