1    	#ifndef JSON_SPIRIT_READER_TEMPLATE
2    	#define JSON_SPIRIT_READER_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_error_position.h"
15   	
16   	#include "common/utf8.h"
17   	
18   	#define BOOST_SPIRIT_THREADSAFE  // uncomment for multithreaded use, requires linking to boost.thread
19   	
20   	#include <boost/bind.hpp>
21   	#include <boost/function.hpp>
22   	#include <boost/version.hpp>
23   	
24   	#if BOOST_VERSION >= 103800
25   	    #include <boost/spirit/include/classic_core.hpp>
26   	    #include <boost/spirit/include/classic_confix.hpp>
27   	    #include <boost/spirit/include/classic_escape_char.hpp>
28   	    #include <boost/spirit/include/classic_multi_pass.hpp>
29   	    #include <boost/spirit/include/classic_position_iterator.hpp>
30   	    #define spirit_namespace boost::spirit::classic
31   	#else
32   	    #include <boost/spirit/core.hpp>
33   	    #include <boost/spirit/utility/confix.hpp>
34   	    #include <boost/spirit/utility/escape_char.hpp>
35   	    #include <boost/spirit/iterator/multi_pass.hpp>
36   	    #include <boost/spirit/iterator/position_iterator.hpp>
37   	    #define spirit_namespace boost::spirit
38   	#endif
39   	
40   	#include "include/ceph_assert.h"
41   	
42   	namespace json_spirit
43   	{
44   	    const spirit_namespace::int_parser < boost::int64_t >  int64_p  = spirit_namespace::int_parser < boost::int64_t  >();
45   	    const spirit_namespace::uint_parser< boost::uint64_t > uint64_p = spirit_namespace::uint_parser< boost::uint64_t >();
46   	
47   	    template< class Iter_type >
48   	    bool is_eq( Iter_type first, Iter_type last, const char* c_str )
49   	    {
50   	        for( Iter_type i = first; i != last; ++i, ++c_str )
51   	        {
52   	            if( *c_str == 0 ) return false;
53   	
54   	            if( *i != *c_str ) return false;
55   	        }
56   	
57   	        return true;
58   	    }
59   	
60   	    template< class Char_type >
61   	    Char_type hex_to_num( const Char_type c )
62   	    {
63   	        if( ( c >= '0' ) && ( c <= '9' ) ) return c - '0';
64   	        if( ( c >= 'a' ) && ( c <= 'f' ) ) return c - 'a' + 10;
65   	        if( ( c >= 'A' ) && ( c <= 'F' ) ) return c - 'A' + 10;
66   	        return 0;
67   	    }
68   	
69   	    template< class Char_type, class Iter_type >
70   	    Char_type hex_str_to_char( Iter_type& begin )
71   	    {
72   	        const Char_type c1( *( ++begin ) );
73   	        const Char_type c2( *( ++begin ) );
74   	
75   	        return ( hex_to_num( c1 ) << 4 ) + hex_to_num( c2 );
76   	    }       
77   	
78   	    template< class String_type, class Iter_type >
79   	    String_type unicode_str_to_utf8( Iter_type& begin );
80   	
81   	    template<>
82   	    std::string unicode_str_to_utf8( std::string::const_iterator & begin )
83   	    {
84   	        typedef std::string::value_type Char_type;
85   	
86   	        const Char_type c1( *( ++begin ) );
87   	        const Char_type c2( *( ++begin ) );
88   	        const Char_type c3( *( ++begin ) );
89   	        const Char_type c4( *( ++begin ) );
90   	
91   	        unsigned long uc = ( hex_to_num( c1 ) << 12 ) + 
92   	                           ( hex_to_num( c2 ) <<  8 ) + 
93   	                           ( hex_to_num( c3 ) <<  4 ) + 
94   	                           hex_to_num( c4 );
95   	
96   	        unsigned char buf[7];  // MAX_UTF8_SZ is 6 (see src/common/utf8.c)
97   	        int r = encode_utf8(uc, buf);
98   	        if (r >= 0) {
99   	            return std::string(reinterpret_cast<char *>(buf), r);
100  	        }
101  	        return std::string("_");
102  	    }
103  	
104  	    template< class String_type >
105  	    void append_esc_char_and_incr_iter( String_type& s, 
106  	                                        typename String_type::const_iterator& begin, 
107  	                                        typename String_type::const_iterator end )
108  	    {
109  	        typedef typename String_type::value_type Char_type;
110  	             
111  	        const Char_type c2( *begin );
112  	
(1) Event switch_selector_expr_is_constant: selector expression is constant
(2) Event caretline: ^
Also see events: [template_instantiation_context][template_instantiation_context]
113  	        switch( c2 )
114  	        {
115  	            case 't':  s += '\t'; break;
116  	            case 'b':  s += '\b'; break;
117  	            case 'f':  s += '\f'; break;
118  	            case 'n':  s += '\n'; break;
119  	            case 'r':  s += '\r'; break;
120  	            case '\\': s += '\\'; break;
121  	            case '/':  s += '/';  break;
122  	            case '"':  s += '"';  break;
123  	            case 'x':  
124  	            {
125  	                if( end - begin >= 3 )  //  expecting "xHH..."
126  	                {
127  	                    s += hex_str_to_char< Char_type >( begin );  
128  	                }
129  	                break;
130  	            }
131  	            case 'u':  
132  	            {
133  	                if( end - begin >= 5 )  //  expecting "uHHHH..."
134  	                {
135  	                    s += unicode_str_to_utf8< String_type >( begin );
136  	                }
137  	                break;
138  	            }
139  	        }
140  	    }
141  	
142  	    template< class String_type >
143  	    String_type substitute_esc_chars( typename String_type::const_iterator begin, 
144  	                                   typename String_type::const_iterator end )
145  	    {
146  	        typedef typename String_type::const_iterator Iter_type;
147  	
148  	        if( end - begin < 2 ) return String_type( begin, end );
149  	
150  	        String_type result;
151  	        
152  	        result.reserve( end - begin );
153  	
154  	        const Iter_type end_minus_1( end - 1 );
155  	
156  	        Iter_type substr_start = begin;
157  	        Iter_type i = begin;
158  	
159  	        for( ; i < end_minus_1; ++i )
160  	        {
161  	            if( *i == '\\' )
162  	            {
163  	                result.append( substr_start, i );
164  	
165  	                ++i;  // skip the '\'
166  	             
167  	                append_esc_char_and_incr_iter( result, i, end );
168  	
169  	                substr_start = i + 1;
170  	            }
171  	        }
172  	
173  	        result.append( substr_start, end );
174  	
175  	        return result;
176  	    }
177  	
178  	    template< class String_type >
179  	    String_type get_str_( typename String_type::const_iterator begin, 
180  	                       typename String_type::const_iterator end )
181  	    {
182  	        ceph_assert( end - begin >= 2 );
183  	
184  	        typedef typename String_type::const_iterator Iter_type;
185  	
186  	        Iter_type str_without_quotes( ++begin );
187  	        Iter_type end_without_quotes( --end );
188  	
(3) Event template_instantiation_context: instantiation of "String_type json_spirit::substitute_esc_chars<String_type>(String_type::const_iterator, String_type::const_iterator) [with String_type=std::string]" at line 189
Also see events: [switch_selector_expr_is_constant][caretline][template_instantiation_context]
189  	        return substitute_esc_chars< String_type >( str_without_quotes, end_without_quotes );
190  	    }
191  	
192  	    inline std::string get_str( std::string::const_iterator begin, std::string::const_iterator end )
193  	    {
(4) Event template_instantiation_context: instantiation of "String_type json_spirit::get_str_<String_type>(String_type::const_iterator, String_type::const_iterator) [with String_type=std::string]" at line 194
Also see events: [switch_selector_expr_is_constant][caretline][template_instantiation_context]
194  	        return get_str_< std::string >( begin, end );
195  	    }
196  	
197  	// Need this guard else it tries to instantiate unicode_str_to_utf8 with a
198  	// std::wstring, which isn't presently implemented
199  	#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING )
200  	    inline std::wstring get_str( std::wstring::const_iterator begin, std::wstring::const_iterator end )
201  	    {
202  	        return get_str_< std::wstring >( begin, end );
203  	    }
204  	#endif
205  	
206  	    template< class String_type, class Iter_type >
207  	    String_type get_str( Iter_type begin, Iter_type end )
208  	    {
209  	        const String_type tmp( begin, end );  // convert multipass iterators to string iterators
210  	
211  	        return get_str( tmp.begin(), tmp.end() );
212  	    }
213  	
214  	    // this class's methods get called by the spirit parse resulting
215  	    // in the creation of a JSON object or array
216  	    //
217  	    // NB Iter_type could be a std::string iterator, wstring iterator, a position iterator or a multipass iterator
218  	    //
219  	    template< class Value_type, class Iter_type >
220  	    class Semantic_actions 
221  	    {
222  	    public:
223  	
224  	        typedef typename Value_type::Config_type Config_type;
225  	        typedef typename Config_type::String_type String_type;
226  	        typedef typename Config_type::Object_type Object_type;
227  	        typedef typename Config_type::Array_type Array_type;
228  	        typedef typename String_type::value_type Char_type;
229  	
230  	        Semantic_actions( Value_type& value )
231  	        :   value_( value )
232  	        ,   current_p_( 0 )
233  	        {
234  	        }
235  	
236  	        void begin_obj( Char_type c )
237  	        {
238  	            ceph_assert( c == '{' );
239  	
240  	            begin_compound< Object_type >();
241  	        }
242  	
243  	        void end_obj( Char_type c )
244  	        {
245  	            ceph_assert( c == '}' );
246  	
247  	            end_compound();
248  	        }
249  	
250  	        void begin_array( Char_type c )
251  	        {
252  	            ceph_assert( c == '[' );
253  	     
254  	            begin_compound< Array_type >();
255  	        }
256  	
257  	        void end_array( Char_type c )
258  	        {
259  	            ceph_assert( c == ']' );
260  	
261  	            end_compound();
262  	        }
263  	
264  	        void new_name( Iter_type begin, Iter_type end )
265  	        {
266  	            ceph_assert( current_p_->type() == obj_type );
267  	
268  	            name_ = get_str< String_type >( begin, end );
269  	        }
270  	
271  	        void new_str( Iter_type begin, Iter_type end )
272  	        {
273  	            add_to_current( get_str< String_type >( begin, end ) );
274  	        }
275  	
276  	        void new_true( Iter_type begin, Iter_type end )
277  	        {
278  	            ceph_assert( is_eq( begin, end, "true" ) );
279  	
280  	            add_to_current( true );
281  	        }
282  	
283  	        void new_false( Iter_type begin, Iter_type end )
284  	        {
285  	            ceph_assert( is_eq( begin, end, "false" ) );
286  	
287  	            add_to_current( false );
288  	        }
289  	
290  	        void new_null( Iter_type begin, Iter_type end )
291  	        {
292  	            ceph_assert( is_eq( begin, end, "null" ) );
293  	
294  	            add_to_current( Value_type() );
295  	        }
296  	
297  	        void new_int( boost::int64_t i )
298  	        {
299  	            add_to_current( i );
300  	        }
301  	
302  	        void new_uint64( boost::uint64_t ui )
303  	        {
304  	            add_to_current( ui );
305  	        }
306  	
307  	        void new_real( double d )
308  	        {
309  	            add_to_current( d );
310  	        }
311  	
312  	    private:
313  	
314  	        Semantic_actions& operator=( const Semantic_actions& ); 
315  	                                    // to prevent "assignment operator could not be generated" warning
316  	
317  	        Value_type* add_first( const Value_type& value )
318  	        {
319  	            ceph_assert( current_p_ == 0 );
320  	
321  	            value_ = value;
322  	            current_p_ = &value_;
323  	            return current_p_;
324  	        }
325  	
326  	        template< class Array_or_obj >
327  	        void begin_compound()
328  	        {
329  	            if( current_p_ == 0 )
330  	            {
331  	                add_first( Array_or_obj() );
332  	            }
333  	            else
334  	            {
335  	                stack_.push_back( current_p_ );
336  	
337  	                Array_or_obj new_array_or_obj;   // avoid copy by building new array or object in place
338  	
339  	                current_p_ = add_to_current( new_array_or_obj );
340  	            }
341  	        }
342  	
343  	        void end_compound()
344  	        {
345  	            if( current_p_ != &value_ )
346  	            {
347  	                current_p_ = stack_.back();
348  	                
349  	                stack_.pop_back();
350  	            }    
351  	        }
352  	
353  	        Value_type* add_to_current( const Value_type& value )
354  	        {
355  	            if( current_p_ == 0 )
356  	            {
357  	                return add_first( value );
358  	            }
359  	            else if( current_p_->type() == array_type )
360  	            {
361  	                current_p_->get_array().push_back( value );
362  	
363  	                return &current_p_->get_array().back(); 
364  	            }
365  	            
366  	            ceph_assert( current_p_->type() == obj_type );
367  	
368  	            return &Config_type::add( current_p_->get_obj(), name_, value );
369  	        }
370  	
371  	        Value_type& value_;             // this is the object or array that is being created
372  	        Value_type* current_p_;         // the child object or array that is currently being constructed
373  	
374  	        std::vector< Value_type* > stack_;   // previous child objects and arrays
375  	
376  	        String_type name_;              // of current name/value pair
377  	    };
378  	
379  	    template< typename Iter_type >
380  	    void throw_error( spirit_namespace::position_iterator< Iter_type > i, const std::string& reason )
381  	    {
382  	        throw Error_position( i.get_position().line, i.get_position().column, reason );
383  	    }
384  	
385  	    template< typename Iter_type >
386  	    void throw_error( Iter_type i, const std::string& reason )
387  	    {
388  	       throw reason;
389  	    }
390  	
391  	    // the spirit grammar 
392  	    //
393  	    template< class Value_type, class Iter_type >
394  	    class Json_grammer : public spirit_namespace::grammar< Json_grammer< Value_type, Iter_type > >
395  	    {
396  	    public:
397  	
398  	        typedef Semantic_actions< Value_type, Iter_type > Semantic_actions_t;
399  	
400  	        Json_grammer( Semantic_actions_t& semantic_actions )
401  	        :   actions_( semantic_actions )
402  	        {
403  	        }
404  	
405  	        static void throw_not_value( Iter_type begin, Iter_type end )
406  	        {
407  	    	    throw_error( begin, "not a value" );
408  	        }
409  	
410  	        static void throw_not_array( Iter_type begin, Iter_type end )
411  	        {
412  	    	    throw_error( begin, "not an array" );
413  	        }
414  	
415  	        static void throw_not_object( Iter_type begin, Iter_type end )
416  	        {
417  	    	    throw_error( begin, "not an object" );
418  	        }
419  	
420  	        static void throw_not_pair( Iter_type begin, Iter_type end )
421  	        {
422  	    	    throw_error( begin, "not a pair" );
423  	        }
424  	
425  	        static void throw_not_colon( Iter_type begin, Iter_type end )
426  	        {
427  	    	    throw_error( begin, "no colon in pair" );
428  	        }
429  	
430  	        static void throw_not_string( Iter_type begin, Iter_type end )
431  	        {
432  	    	    throw_error( begin, "not a string" );
433  	        }
434  	
435  	        template< typename ScannerT >
436  	        class definition
437  	        {
438  	        public:
439  	
440  	            definition( const Json_grammer& self )
441  	            {
442  	                using namespace spirit_namespace;
443  	
444  	                typedef typename Value_type::String_type::value_type Char_type;
445  	
446  	                // first we convert the semantic action class methods to functors with the 
447  	                // parameter signature expected by spirit
448  	
449  	                typedef boost::function< void( Char_type )            > Char_action;
450  	                typedef boost::function< void( Iter_type, Iter_type ) > Str_action;
451  	                typedef boost::function< void( double )               > Real_action;
452  	                typedef boost::function< void( boost::int64_t )       > Int_action;
453  	                typedef boost::function< void( boost::uint64_t )      > Uint64_action;
454  	
455  	                Char_action   begin_obj  ( boost::bind( &Semantic_actions_t::begin_obj,   &self.actions_, _1 ) );
456  	                Char_action   end_obj    ( boost::bind( &Semantic_actions_t::end_obj,     &self.actions_, _1 ) );
457  	                Char_action   begin_array( boost::bind( &Semantic_actions_t::begin_array, &self.actions_, _1 ) );
458  	                Char_action   end_array  ( boost::bind( &Semantic_actions_t::end_array,   &self.actions_, _1 ) );
459  	                Str_action    new_name   ( boost::bind( &Semantic_actions_t::new_name,    &self.actions_, _1, _2 ) );
460  	                Str_action    new_str    ( boost::bind( &Semantic_actions_t::new_str,     &self.actions_, _1, _2 ) );
461  	                Str_action    new_true   ( boost::bind( &Semantic_actions_t::new_true,    &self.actions_, _1, _2 ) );
462  	                Str_action    new_false  ( boost::bind( &Semantic_actions_t::new_false,   &self.actions_, _1, _2 ) );
463  	                Str_action    new_null   ( boost::bind( &Semantic_actions_t::new_null,    &self.actions_, _1, _2 ) );
464  	                Real_action   new_real   ( boost::bind( &Semantic_actions_t::new_real,    &self.actions_, _1 ) );
465  	                Int_action    new_int    ( boost::bind( &Semantic_actions_t::new_int,     &self.actions_, _1 ) );
466  	                Uint64_action new_uint64 ( boost::bind( &Semantic_actions_t::new_uint64,  &self.actions_, _1 ) );
467  	
468  	                // actual grammar
469  	
470  	                json_
471  	                    = value_ | eps_p[ &throw_not_value ]
472  	                    ;
473  	
474  	                value_
475  	                    = string_[ new_str ] 
476  	                    | number_ 
477  	                    | object_ 
478  	                    | array_ 
479  	                    | str_p( "true" ) [ new_true  ] 
480  	                    | str_p( "false" )[ new_false ] 
481  	                    | str_p( "null" ) [ new_null  ]
482  	                    ;
483  	
484  	                object_ 
485  	                    = ch_p('{')[ begin_obj ]
486  	                    >> !members_
487  	                    >> ( ch_p('}')[ end_obj ] | eps_p[ &throw_not_object ] )
488  	                    ;
489  	
490  	                members_
491  	                    = pair_ >> *( ',' >> pair_  | ch_p(',') )
492  	                    ;
493  	
494  	                pair_
495  	                    = string_[ new_name ]
496  	                    >> ( ':' | eps_p[ &throw_not_colon ] )
497  	                    >> ( value_ | eps_p[ &throw_not_value ] )
498  	                    ;
499  	
500  	                array_
501  	                    = ch_p('[')[ begin_array ]
502  	                    >> !elements_
503  	                    >> ( ch_p(']')[ end_array ] | eps_p[ &throw_not_array ] )
504  	                    ;
505  	
506  	                elements_
507  	                    = value_ >> *( ',' >> value_ | ch_p(',') )
508  	                    ;
509  	
510  	                string_ 
511  	                    = lexeme_d // this causes white space inside a string to be retained
512  	                      [
513  	                          confix_p
514  	                          ( 
515  	                              '"', 
516  	                              *lex_escape_ch_p,
517  	                              '"'
518  	                          ) 
519  	                      ]
520  	                    ;
521  	
522  	                number_
523  	                    = strict_real_p[ new_real   ] 
524  	                    | int64_p      [ new_int    ]
525  	                    | uint64_p     [ new_uint64 ]
526  	                    ;
527  	            }
528  	
529  	            spirit_namespace::rule< ScannerT > json_, object_, members_, pair_, array_, elements_, value_, string_, number_;
530  	
531  	            const spirit_namespace::rule< ScannerT >& start() const { return json_; }
532  	        };
533  	
534  	    private:
535  	
536  	        Json_grammer& operator=( const Json_grammer& ); // to prevent "assignment operator could not be generated" warning
537  	
538  	        Semantic_actions_t& actions_;
539  	    };
540  	
541  	    template< class Iter_type, class Value_type >
542  	    void add_posn_iter_and_read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value )
543  	    {
544  	        typedef spirit_namespace::position_iterator< Iter_type > Posn_iter_t;
545  	
546  	        const Posn_iter_t posn_begin( begin, end );
547  	        const Posn_iter_t posn_end( end, end );
548  	     
549  	        read_range_or_throw( posn_begin, posn_end, value );
550  	    }
551  	
552  	    template< class Istream_type >
553  	    struct Multi_pass_iters
554  	    {
555  	        typedef typename Istream_type::char_type Char_type;
556  	        typedef std::istream_iterator< Char_type, Char_type > istream_iter;
557  	        typedef spirit_namespace::multi_pass< istream_iter > Mp_iter;
558  	
559  	        Multi_pass_iters( Istream_type& is )
560  	        {
561  	            is.unsetf( std::ios::skipws );
562  	
563  	            begin_ = spirit_namespace::make_multi_pass( istream_iter( is ) );
564  	            end_   = spirit_namespace::make_multi_pass( istream_iter() );
565  	        }
566  	
567  	        Mp_iter begin_;
568  	        Mp_iter end_;
569  	    };
570  	
571  	    // reads a JSON Value from a pair of input iterators throwing an exception on invalid input, e.g.
572  	    //
573  	    // string::const_iterator start = str.begin();
574  	    // const string::const_iterator next = read_range_or_throw( str.begin(), str.end(), value );
575  	    //
576  	    // The iterator 'next' will point to the character past the 
577  	    // last one read.
578  	    //
579  	    template< class Iter_type, class Value_type >
580  	    Iter_type read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value )
581  	    {
582  	        Semantic_actions< Value_type, Iter_type > semantic_actions( value );
583  	     
584  	        const spirit_namespace::parse_info< Iter_type > info = 
585  	                            spirit_namespace::parse( begin, end, 
586  	                                                    Json_grammer< Value_type, Iter_type >( semantic_actions ), 
587  	                                                    spirit_namespace::space_p );
588  	
589  	        if( !info.hit )
590  	        {
591  	            ceph_assert( false ); // in theory exception should already have been thrown
592  	            throw_error( info.stop, "error" );
593  	        }
594  	
595  	        return info.stop;
596  	    }
597  	
598  	    // reads a JSON Value from a pair of input iterators, e.g.
599  	    //
600  	    // string::const_iterator start = str.begin();
601  	    // const bool success = read_string( start, str.end(), value );
602  	    //
603  	    // The iterator 'start' will point to the character past the 
604  	    // last one read.
605  	    //
606  	    template< class Iter_type, class Value_type >
607  	    bool read_range( Iter_type& begin, Iter_type end, Value_type& value )
608  	    {
609  	        try
610  	        {
611  	            begin = read_range_or_throw( begin, end, value );
612  	
613  	            return true;
614  	        }
615  	        catch( ... )
616  	        {
617  	            return false;
618  	        }
619  	    }
620  	
621  	    // reads a JSON Value from a string, e.g.
622  	    //
623  	    // const bool success = read_string( str, value );
624  	    //
625  	    template< class String_type, class Value_type >
626  	    bool read_string( const String_type& s, Value_type& value )
627  	    {
628  	        typename String_type::const_iterator begin = s.begin();
629  	
630  	        return read_range( begin, s.end(), value );
631  	    }
632  	
633  	    // reads a JSON Value from a string throwing an exception on invalid input, e.g.
634  	    //
635  	    // read_string_or_throw( is, value );
636  	    //
637  	    template< class String_type, class Value_type >
638  	    void read_string_or_throw( const String_type& s, Value_type& value )
639  	    {
640  	        add_posn_iter_and_read_range_or_throw( s.begin(), s.end(), value );
641  	    }
642  	
643  	    // reads a JSON Value from a stream, e.g.
644  	    //
645  	    // const bool success = read_stream( is, value );
646  	    //
647  	    template< class Istream_type, class Value_type >
648  	    bool read_stream( Istream_type& is, Value_type& value )
649  	    {
650  	        Multi_pass_iters< Istream_type > mp_iters( is );
651  	
652  	        return read_range( mp_iters.begin_, mp_iters.end_, value );
653  	    }
654  	
655  	    // reads a JSON Value from a stream throwing an exception on invalid input, e.g.
656  	    //
657  	    // read_stream_or_throw( is, value );
658  	    //
659  	    template< class Istream_type, class Value_type >
660  	    void read_stream_or_throw( Istream_type& is, Value_type& value )
661  	    {
662  	        const Multi_pass_iters< Istream_type > mp_iters( is );
663  	
664  	        add_posn_iter_and_read_range_or_throw( mp_iters.begin_, mp_iters.end_, value );
665  	    }
666  	}
667  	
668  	#endif
669