~ubuntu-branches/ubuntu/raring/ceph/raring

« back to all changes in this revision

Viewing changes to src/json_spirit/json_spirit_writer_template.h

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2012-06-08 15:54:37 UTC
  • mfrom: (1.1.8) (0.1.13 sid)
  • Revision ID: package-import@ubuntu.com-20120608155437-gy3j9k6wzv7w4gn9
Tags: 0.44.1-1ubuntu1
* Merge from Debian unstable.  Remaining changes:
  - d/control: Switch from libcryptopp to libnss as libcryptopp
    is not seeded.
  - d/control,d/rules: Move from python-support to dh_python2.
  - d/patches/manpage_updates*.patch: cherry picked upstream manpage
    updates warning about lack of encryption, per MIR review.
  - d/rules,d/control: Drop radosgw since libfcgi is not in main and
    the code may not be suitable for LTS.
  - d/rules,d/control: Drop tcmalloc since google perftools is not
    in main yet.
  - d/rules,d/control: Drop ceph-fuse entirely per MIR review
    recommendation.
* d/patches/fix-radosgw-tests.patch: Cherry picked patch from upstream
  VCS to fixup tests to conditionally use radosgw if enabled.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
        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 );
 
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
        {
 
238
            if( remove_trailing_zeros_ )
 
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 >
 
274
        void output_composite_item( Iter i, Iter last )
 
275
        {
 
276
            output( *i );
 
277
 
 
278
            if( ++i != last )
 
279
            {
 
280
                os_ << ',';
 
281
            }
 
282
        }
 
283
 
 
284
        void output( const Array_type& arr )
 
285
        {
 
286
            if( single_line_arrays_ && !contains_composite_elements( arr )  )
 
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
 
 
310
            ++indentation_level_;
 
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
 
 
321
            --indentation_level_;
 
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_;
 
349
        int indentation_level_;
 
350
        bool pretty_;
 
351
        bool raw_utf8_;
 
352
        bool remove_trailing_zeros_;
 
353
        bool single_line_arrays_;
 
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;
 
365
        Generator< Value_type, Ostream_type >( value, os, options );
 
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