• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*=============================================================================
2     Copyright (c) 2001, Daniel C. Nuffer
3     http://spirit.sourceforge.net/
4 
5   Distributed under the Boost Software License, Version 1.0. (See accompanying
6   file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 =============================================================================*/
8 #ifndef BOOST_SPIRIT_ITERATOR_MULTI_PASS_HPP
9 #define BOOST_SPIRIT_ITERATOR_MULTI_PASS_HPP
10 
11 #include <boost/config.hpp>
12 #include <boost/throw_exception.hpp>
13 #include <deque>
14 #include <iterator>
15 #include <iostream>
16 #include <algorithm>    // for std::swap
17 #include <exception>    // for std::exception
18 #include <boost/limits.hpp>
19 
20 #include <boost/spirit/home/classic/namespace.hpp>
21 #include <boost/spirit/home/classic/core/assert.hpp> // for BOOST_SPIRIT_ASSERT
22 #include <boost/spirit/home/classic/iterator/fixed_size_queue.hpp>
23 
24 #include <boost/spirit/home/classic/iterator/multi_pass_fwd.hpp>
25 
26 namespace boost { namespace spirit {
27 
28 BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
29 
30 namespace impl {
31     template <typename T>
32     inline void mp_swap(T& t1, T& t2);
33 }
34 
35 namespace multi_pass_policies
36 {
37 
38 ///////////////////////////////////////////////////////////////////////////////
39 // class ref_counted
40 // Implementation of an OwnershipPolicy used by multi_pass.
41 //
42 // Implementation modified from RefCounted class from the Loki library by
43 // Andrei Alexandrescu
44 ///////////////////////////////////////////////////////////////////////////////
45 class ref_counted
46 {
47     protected:
ref_counted()48         ref_counted()
49             : count(new std::size_t(1))
50         {}
51 
ref_counted(ref_counted const & x)52         ref_counted(ref_counted const& x)
53             : count(x.count)
54         {}
55 
56         // clone is called when a copy of the iterator is made, so increment
57         // the ref-count.
clone()58         void clone()
59         {
60             ++*count;
61         }
62 
63         // called when a copy is deleted.  Decrement the ref-count.  Return
64         // value of true indicates that the last copy has been released.
release()65         bool release()
66         {
67             if (!--*count)
68             {
69                 delete count;
70                 count = 0;
71                 return true;
72             }
73             return false;
74         }
75 
swap(ref_counted & x)76         void swap(ref_counted& x)
77         {
78             impl::mp_swap(count, x.count);
79         }
80 
81     public:
82         // returns true if there is only one iterator in existence.
83         // std_deque StoragePolicy will free it's buffered data if this
84         // returns true.
unique() const85         bool unique() const
86         {
87             return *count == 1;
88         }
89 
90     private:
91         std::size_t* count;
92 };
93 
94 ///////////////////////////////////////////////////////////////////////////////
95 // class first_owner
96 // Implementation of an OwnershipPolicy used by multi_pass
97 // This ownership policy dictates that the first iterator created will
98 // determine the lifespan of the shared components.  This works well for
99 // spirit, since no dynamic allocation of iterators is done, and all copies
100 // are make on the stack.
101 //
102 // There is a caveat about using this policy together with the std_deque
103 // StoragePolicy. Since first_owner always returns false from unique(),
104 // std_deque will only release the queued data if clear_queue() is called.
105 ///////////////////////////////////////////////////////////////////////////////
106 class first_owner
107 {
108     protected:
first_owner()109         first_owner()
110             : first(true)
111         {}
112 
first_owner(first_owner const &)113         first_owner(first_owner const&)
114             : first(false)
115         {}
116 
clone()117         void clone()
118         {
119         }
120 
121         // return true to indicate deletion of resources
release()122         bool release()
123         {
124             return first;
125         }
126 
swap(first_owner &)127         void swap(first_owner&)
128         {
129             // if we're the first, we still remain the first, even if assigned
130             // to, so don't swap first_.  swap is only called from operator=
131         }
132 
133     public:
unique() const134         bool unique() const
135         {
136             return false; // no way to know, so always return false
137         }
138 
139     private:
140         bool first;
141 };
142 
143 ///////////////////////////////////////////////////////////////////////////////
144 // class illegal_backtracking
145 // thrown by buf_id_check CheckingPolicy if an instance of an iterator is
146 // used after another one has invalidated the queue
147 ///////////////////////////////////////////////////////////////////////////////
148 class BOOST_SYMBOL_VISIBLE illegal_backtracking : public std::exception
149 {
150 public:
151 
illegal_backtracking()152     illegal_backtracking() BOOST_NOEXCEPT_OR_NOTHROW {}
~illegal_backtracking()153     ~illegal_backtracking() BOOST_NOEXCEPT_OR_NOTHROW BOOST_OVERRIDE {}
154 
155     const char*
what() const156     what() const BOOST_NOEXCEPT_OR_NOTHROW BOOST_OVERRIDE
157     { return "BOOST_SPIRIT_CLASSIC_NS::illegal_backtracking"; }
158 };
159 
160 ///////////////////////////////////////////////////////////////////////////////
161 // class buf_id_check
162 // Implementation of the CheckingPolicy used by multi_pass
163 // This policy is most effective when used together with the std_deque
164 // StoragePolicy.
165 // If used with the fixed_size_queue StoragePolicy, it will not detect
166 // iterator dereferences that are out of the range of the queue.
167 ///////////////////////////////////////////////////////////////////////////////
168 class buf_id_check
169 {
170     protected:
buf_id_check()171         buf_id_check()
172             : shared_buf_id(new unsigned long(0))
173             , buf_id(0)
174         {}
175 
buf_id_check(buf_id_check const & x)176         buf_id_check(buf_id_check const& x)
177             : shared_buf_id(x.shared_buf_id)
178             , buf_id(x.buf_id)
179         {}
180 
181         // will be called from the destructor of the last iterator.
destroy()182         void destroy()
183         {
184             delete shared_buf_id;
185             shared_buf_id = 0;
186         }
187 
swap(buf_id_check & x)188         void swap(buf_id_check& x)
189         {
190             impl::mp_swap(shared_buf_id, x.shared_buf_id);
191             impl::mp_swap(buf_id, x.buf_id);
192         }
193 
194         // called to verify that everything is okay.
check_if_valid() const195         void check_if_valid() const
196         {
197             if (buf_id != *shared_buf_id)
198             {
199                 boost::throw_exception(illegal_backtracking());
200             }
201         }
202 
203         // called from multi_pass::clear_queue, so we can increment the count
clear_queue()204         void clear_queue()
205         {
206             ++*shared_buf_id;
207             ++buf_id;
208         }
209 
210     private:
211         unsigned long* shared_buf_id;
212         unsigned long buf_id;
213 };
214 
215 ///////////////////////////////////////////////////////////////////////////////
216 // class no_check
217 // Implementation of the CheckingPolicy used by multi_pass
218 // It does not do anything :-)
219 ///////////////////////////////////////////////////////////////////////////////
220 class no_check
221 {
222     protected:
no_check()223         no_check() {}
no_check(no_check const &)224         no_check(no_check const&) {}
destroy()225         void destroy() {}
swap(no_check &)226         void swap(no_check&) {}
check_if_valid() const227         void check_if_valid() const {}
clear_queue()228         void clear_queue() {}
229 };
230 
231 ///////////////////////////////////////////////////////////////////////////////
232 // class std_deque
233 // Implementation of the StoragePolicy used by multi_pass
234 // This stores all data in a std::deque, and keeps an offset to the current
235 // position. It stores all the data unless there is only one
236 // iterator using the queue.
237 // Note: a position is used instead of an iterator, because a push_back on
238 // a deque can invalidate any iterators.
239 ///////////////////////////////////////////////////////////////////////////////
240 class std_deque
241 {
242     public:
243 
244 template <typename ValueT>
245 class inner
246 {
247     private:
248 
249         typedef std::deque<ValueT> queue_type;
250         queue_type* queuedElements;
251         mutable typename queue_type::size_type queuePosition;
252 
253     protected:
inner()254         inner()
255             : queuedElements(new queue_type)
256             , queuePosition(0)
257         {}
258 
inner(inner const & x)259         inner(inner const& x)
260             : queuedElements(x.queuedElements)
261             , queuePosition(x.queuePosition)
262         {}
263 
264         // will be called from the destructor of the last iterator.
destroy()265         void destroy()
266         {
267             BOOST_SPIRIT_ASSERT(NULL != queuedElements);
268             delete queuedElements;
269             queuedElements = 0;
270         }
271 
swap(inner & x)272         void swap(inner& x)
273         {
274             impl::mp_swap(queuedElements, x.queuedElements);
275             impl::mp_swap(queuePosition, x.queuePosition);
276         }
277 
278         // This is called when the iterator is dereferenced.  It's a template
279         // method so we can recover the type of the multi_pass iterator
280         // and call unique and access the m_input data member.
281         template <typename MultiPassT>
dereference(MultiPassT const & mp)282         static typename MultiPassT::reference dereference(MultiPassT const& mp)
283         {
284             if (mp.queuePosition == mp.queuedElements->size())
285             {
286                 // check if this is the only iterator
287                 if (mp.unique())
288                 {
289                     // free up the memory used by the queue.
290                     if (mp.queuedElements->size() > 0)
291                     {
292                         mp.queuedElements->clear();
293                         mp.queuePosition = 0;
294                     }
295                 }
296                 return mp.get_input();
297             }
298             else
299             {
300                 return (*mp.queuedElements)[mp.queuePosition];
301             }
302         }
303 
304         // This is called when the iterator is incremented.  It's a template
305         // method so we can recover the type of the multi_pass iterator
306         // and call unique and access the m_input data member.
307         template <typename MultiPassT>
increment(MultiPassT & mp)308         static void increment(MultiPassT& mp)
309         {
310             if (mp.queuePosition == mp.queuedElements->size())
311             {
312                 // check if this is the only iterator
313                 if (mp.unique())
314                 {
315                     // free up the memory used by the queue.
316                     if (mp.queuedElements->size() > 0)
317                     {
318                         mp.queuedElements->clear();
319                         mp.queuePosition = 0;
320                     }
321                 }
322                 else
323                 {
324                     mp.queuedElements->push_back(mp.get_input());
325                     ++mp.queuePosition;
326                 }
327                 mp.advance_input();
328             }
329             else
330             {
331                 ++mp.queuePosition;
332             }
333 
334         }
335 
336         // called to forcibly clear the queue
clear_queue()337         void clear_queue()
338         {
339             queuedElements->clear();
340             queuePosition = 0;
341         }
342 
343         // called to determine whether the iterator is an eof iterator
344         template <typename MultiPassT>
is_eof(MultiPassT const & mp)345         static bool is_eof(MultiPassT const& mp)
346         {
347             return mp.queuePosition == mp.queuedElements->size() &&
348                 mp.input_at_eof();
349         }
350 
351         // called by operator==
equal_to(inner const & x) const352         bool equal_to(inner const& x) const
353         {
354             return queuePosition == x.queuePosition;
355         }
356 
357         // called by operator<
less_than(inner const & x) const358         bool less_than(inner const& x) const
359         {
360             return queuePosition < x.queuePosition;
361         }
362 }; // class inner
363 
364 }; // class std_deque
365 
366 
367 ///////////////////////////////////////////////////////////////////////////////
368 // class fixed_size_queue
369 // Implementation of the StoragePolicy used by multi_pass
370 // fixed_size_queue keeps a circular buffer (implemented by
371 // BOOST_SPIRIT_CLASSIC_NS::fixed_size_queue class) that is size N+1 and stores N elements.
372 // It is up to the user to ensure that there is enough look ahead for their
373 // grammar.  Currently there is no way to tell if an iterator is pointing
374 // to forgotten data.  The leading iterator will put an item in the queue
375 // and remove one when it is incremented.  No dynamic allocation is done,
376 // except on creation of the queue (fixed_size_queue constructor).
377 ///////////////////////////////////////////////////////////////////////////////
378 template < std::size_t N>
379 class fixed_size_queue
380 {
381     public:
382 
383 template <typename ValueT>
384 class inner
385 {
386     private:
387 
388         typedef BOOST_SPIRIT_CLASSIC_NS::fixed_size_queue<ValueT, N> queue_type;
389         queue_type * queuedElements;
390         mutable typename queue_type::iterator queuePosition;
391 
392     protected:
inner()393         inner()
394             : queuedElements(new queue_type)
395             , queuePosition(queuedElements->begin())
396         {}
397 
inner(inner const & x)398         inner(inner const& x)
399             : queuedElements(x.queuedElements)
400             , queuePosition(x.queuePosition)
401         {}
402 
403         // will be called from the destructor of the last iterator.
destroy()404         void destroy()
405         {
406             BOOST_SPIRIT_ASSERT(NULL != queuedElements);
407             delete queuedElements;
408             queuedElements = 0;
409         }
410 
swap(inner & x)411         void swap(inner& x)
412         {
413             impl::mp_swap(queuedElements, x.queuedElements);
414             impl::mp_swap(queuePosition, x.queuePosition);
415         }
416 
417         // This is called when the iterator is dereferenced.  It's a template
418         // method so we can recover the type of the multi_pass iterator
419         // and access the m_input data member.
420         template <typename MultiPassT>
dereference(MultiPassT const & mp)421         static typename MultiPassT::reference dereference(MultiPassT const& mp)
422         {
423             if (mp.queuePosition == mp.queuedElements->end())
424             {
425                 return mp.get_input();
426             }
427             else
428             {
429                 return *mp.queuePosition;
430             }
431         }
432 
433         // This is called when the iterator is incremented.  It's a template
434         // method so we can recover the type of the multi_pass iterator
435         // and access the m_input data member.
436         template <typename MultiPassT>
increment(MultiPassT & mp)437         static void increment(MultiPassT& mp)
438         {
439             if (mp.queuePosition == mp.queuedElements->end())
440             {
441                 // don't let the queue get larger than N
442                 if (mp.queuedElements->size() >= N)
443                     mp.queuedElements->pop_front();
444 
445                 mp.queuedElements->push_back(mp.get_input());
446                 mp.advance_input();
447             }
448             ++mp.queuePosition;
449         }
450 
451         // no-op
clear_queue()452         void clear_queue()
453         {}
454 
455         // called to determine whether the iterator is an eof iterator
456         template <typename MultiPassT>
is_eof(MultiPassT const & mp)457         static bool is_eof(MultiPassT const& mp)
458         {
459             return mp.queuePosition == mp.queuedElements->end() &&
460                 mp.input_at_eof();
461         }
462 
463         // called by operator==
equal_to(inner const & x) const464         bool equal_to(inner const& x) const
465         {
466             return queuePosition == x.queuePosition;
467         }
468 
469         // called by operator<
less_than(inner const & x) const470         bool less_than(inner const& x) const
471         {
472             return queuePosition < x.queuePosition;
473         }
474 }; // class inner
475 
476 }; // class fixed_size_queue
477 
478 
479 ///////////////////////////////////////////////////////////////////////////////
480 // class input_iterator
481 // Implementation of the InputPolicy used by multi_pass
482 // input_iterator encapsulates an input iterator of type InputT
483 ///////////////////////////////////////////////////////////////////////////////
484 class input_iterator
485 {
486     public:
487 
488 template <typename InputT>
489 class inner
490 {
491     private:
492         typedef
493             typename std::iterator_traits<InputT>::value_type
494             result_type;
495 
496     public:
497         typedef result_type value_type;
498 
499     private:
500         struct Data {
Databoost::spirit::multi_pass_policies::input_iterator::inner::Data501             Data(InputT const &input_)
502             :   input(input_), was_initialized(false)
503             {}
504 
505             InputT input;
506             value_type curtok;
507             bool was_initialized;
508         };
509 
510        // Needed by compilers not implementing the resolution to DR45. For
511        // reference, see
512        // http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#45.
513 
514        friend struct Data;
515 
516     public:
517         typedef
518             typename std::iterator_traits<InputT>::difference_type
519             difference_type;
520         typedef
521             typename std::iterator_traits<InputT>::pointer
522             pointer;
523         typedef
524             typename std::iterator_traits<InputT>::reference
525             reference;
526 
527     protected:
inner()528         inner()
529             : data(0)
530         {}
531 
inner(InputT x)532         inner(InputT x)
533             : data(new Data(x))
534         {}
535 
inner(inner const & x)536         inner(inner const& x)
537             : data(x.data)
538         {}
539 
destroy()540         void destroy()
541         {
542             delete data;
543             data = 0;
544         }
545 
same_input(inner const & x) const546         bool same_input(inner const& x) const
547         {
548             return data == x.data;
549         }
550 
551         typedef
552             typename std::iterator_traits<InputT>::value_type
553             value_t;
swap(inner & x)554         void swap(inner& x)
555         {
556             impl::mp_swap(data, x.data);
557         }
558 
ensure_initialized() const559         void ensure_initialized() const
560         {
561             if (data && !data->was_initialized) {
562                 data->curtok = *data->input;      // get the first token
563                 data->was_initialized = true;
564             }
565         }
566 
567     public:
get_input() const568         reference get_input() const
569         {
570             BOOST_SPIRIT_ASSERT(NULL != data);
571             ensure_initialized();
572             return data->curtok;
573         }
574 
advance_input()575         void advance_input()
576         {
577             BOOST_SPIRIT_ASSERT(NULL != data);
578             data->was_initialized = false;        // should get the next token
579             ++data->input;
580         }
581 
input_at_eof() const582         bool input_at_eof() const
583         {
584             return !data || data->input == InputT();
585         }
586 
587     private:
588         Data *data;
589 };
590 
591 };
592 
593 ///////////////////////////////////////////////////////////////////////////////
594 // class lex_input
595 // Implementation of the InputPolicy used by multi_pass
596 // lex_input gets tokens (ints) from yylex()
597 ///////////////////////////////////////////////////////////////////////////////
598 class lex_input
599 {
600     public:
601 
602 template <typename InputT>
603 class inner
604 {
605     public:
606         typedef int value_type;
607     typedef std::ptrdiff_t difference_type;
608         typedef int* pointer;
609         typedef int& reference;
610 
611     protected:
inner()612         inner()
613             : curtok(new int(0))
614         {}
615 
inner(InputT x)616         inner(InputT x)
617             : curtok(new int(x))
618         {}
619 
inner(inner const & x)620         inner(inner const& x)
621             : curtok(x.curtok)
622         {}
623 
destroy()624         void destroy()
625         {
626             delete curtok;
627             curtok = 0;
628         }
629 
same_input(inner const & x) const630         bool same_input(inner const& x) const
631         {
632             return curtok == x.curtok;
633         }
634 
swap(inner & x)635         void swap(inner& x)
636         {
637             impl::mp_swap(curtok, x.curtok);
638         }
639 
640     public:
get_input() const641         reference get_input() const
642         {
643             return *curtok;
644         }
645 
advance_input()646         void advance_input()
647         {
648             extern int yylex();
649             *curtok = yylex();
650         }
651 
input_at_eof() const652         bool input_at_eof() const
653         {
654             return *curtok == 0;
655         }
656 
657     private:
658         int* curtok;
659 
660 };
661 
662 };
663 
664 ///////////////////////////////////////////////////////////////////////////////
665 // class functor_input
666 // Implementation of the InputPolicy used by multi_pass
667 // functor_input gets tokens from a functor
668 // Note: the functor must have a typedef for result_type
669 // It also must have a static variable of type result_type defined to
670 // represent eof that is called eof.
671 ///////////////////////////////////////////////////////////////////////////////
672 class functor_input
673 {
674     public:
675 
676 template <typename FunctorT>
677 class inner
678 {
679     typedef typename FunctorT::result_type result_type;
680     public:
681         typedef result_type value_type;
682     typedef std::ptrdiff_t difference_type;
683         typedef result_type* pointer;
684         typedef result_type& reference;
685 
686     protected:
inner()687         inner()
688             : ftor(0)
689             , curtok(0)
690         {}
691 
inner(FunctorT const & x)692         inner(FunctorT const& x)
693             : ftor(new FunctorT(x))
694             , curtok(new result_type((*ftor)()))
695         {}
696 
inner(inner const & x)697         inner(inner const& x)
698             : ftor(x.ftor)
699             , curtok(x.curtok)
700         {}
701 
destroy()702         void destroy()
703         {
704             delete ftor;
705             ftor = 0;
706             delete curtok;
707             curtok = 0;
708         }
709 
same_input(inner const & x) const710         bool same_input(inner const& x) const
711         {
712             return ftor == x.ftor;
713         }
714 
swap(inner & x)715         void swap(inner& x)
716         {
717             impl::mp_swap(curtok, x.curtok);
718             impl::mp_swap(ftor, x.ftor);
719         }
720 
721     public:
get_input() const722         reference get_input() const
723         {
724             return *curtok;
725         }
726 
advance_input()727         void advance_input()
728         {
729             if (curtok) {
730                 *curtok = (*ftor)();
731             }
732         }
733 
input_at_eof() const734         bool input_at_eof() const
735         {
736             return !curtok || *curtok == ftor->eof;
737         }
738 
get_functor() const739         FunctorT& get_functor() const
740         {
741             return *ftor;
742         }
743 
744 
745     private:
746         FunctorT* ftor;
747         result_type* curtok;
748 
749 };
750 
751 };
752 
753 } // namespace multi_pass_policies
754 
755 ///////////////////////////////////////////////////////////////////////////////
756 // iterator_base_creator
757 ///////////////////////////////////////////////////////////////////////////////
758 
759 namespace iterator_ { namespace impl {
760 
761 // Meta-function to generate a std::iterator<>-like base class for multi_pass.
762 template <typename InputPolicyT, typename InputT>
763 struct iterator_base_creator
764 {
765     typedef typename InputPolicyT::BOOST_NESTED_TEMPLATE inner<InputT> input_t;
766 
767     struct type {
768         typedef std::forward_iterator_tag iterator_category;
769         typedef typename input_t::value_type value_type;
770         typedef typename input_t::difference_type difference_type;
771         typedef typename input_t::pointer pointer;
772         typedef typename input_t::reference reference;
773     };
774 };
775 
776 }}
777 
778 ///////////////////////////////////////////////////////////////////////////////
779 // class template multi_pass
780 ///////////////////////////////////////////////////////////////////////////////
781 
782 // The default multi_pass instantiation uses a ref-counted std_deque scheme.
783 template
784 <
785     typename InputT,
786     typename InputPolicy,
787     typename OwnershipPolicy,
788     typename CheckingPolicy,
789     typename StoragePolicy
790 >
791 class multi_pass
792     : public OwnershipPolicy
793     , public CheckingPolicy
794     , public StoragePolicy::template inner<
795                 typename InputPolicy::template inner<InputT>::value_type>
796     , public InputPolicy::template inner<InputT>
797     , public iterator_::impl::iterator_base_creator<InputPolicy, InputT>::type
798 {
799         typedef OwnershipPolicy OP;
800         typedef CheckingPolicy CHP;
801         typedef typename StoragePolicy::template inner<
802             typename InputPolicy::template inner<InputT>::value_type> SP;
803         typedef typename InputPolicy::template inner<InputT> IP;
804         typedef typename
805             iterator_::impl::iterator_base_creator<InputPolicy, InputT>::type
806             IB;
807 
808     public:
809         typedef typename IB::value_type value_type;
810         typedef typename IB::difference_type difference_type;
811         typedef typename IB::reference reference;
812         typedef typename IB::pointer pointer;
813         typedef InputT iterator_type;
814 
815         multi_pass();
816         explicit multi_pass(InputT input);
817 
818 #if BOOST_WORKAROUND(__GLIBCPP__, == 20020514)
819         multi_pass(int);
820 #endif // BOOST_WORKAROUND(__GLIBCPP__, == 20020514)
821 
822         ~multi_pass();
823 
824         multi_pass(multi_pass const&);
825         multi_pass& operator=(multi_pass const&);
826 
827         void swap(multi_pass& x);
828 
829         reference operator*() const;
830         pointer operator->() const;
831         multi_pass& operator++();
832         multi_pass operator++(int);
833 
834         void clear_queue();
835 
836         bool operator==(const multi_pass& y) const;
837         bool operator<(const multi_pass& y) const;
838 
839     private: // helper functions
840         bool is_eof() const;
841 };
842 
843 template
844 <
845     typename InputT,
846     typename InputPolicy,
847     typename OwnershipPolicy,
848     typename CheckingPolicy,
849     typename StoragePolicy
850 >
851 inline
852 multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
multi_pass()853 multi_pass()
854     : OP()
855     , CHP()
856     , SP()
857     , IP()
858 {
859 }
860 
861 template
862 <
863     typename InputT,
864     typename InputPolicy,
865     typename OwnershipPolicy,
866     typename CheckingPolicy,
867     typename StoragePolicy
868 >
869 inline
870 multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
multi_pass(InputT input)871 multi_pass(InputT input)
872     : OP()
873     , CHP()
874     , SP()
875     , IP(input)
876 {
877 }
878 
879 #if BOOST_WORKAROUND(__GLIBCPP__, == 20020514)
880     // The standard library shipped with gcc-3.1 has a bug in
881     // bits/basic_string.tcc. It tries  to use iter::iter(0) to
882     // construct an iterator. Ironically, this  happens in sanity
883     // checking code that isn't required by the standard.
884     // The workaround is to provide an additional constructor that
885     // ignores its int argument and behaves like the default constructor.
886 template
887 <
888     typename InputT,
889     typename InputPolicy,
890     typename OwnershipPolicy,
891     typename CheckingPolicy,
892     typename StoragePolicy
893 >
894 inline
895 multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
multi_pass(int)896 multi_pass(int)
897     : OP()
898     , CHP()
899     , SP()
900     , IP()
901 {
902 }
903 #endif // BOOST_WORKAROUND(__GLIBCPP__, == 20020514)
904 
905 template
906 <
907     typename InputT,
908     typename InputPolicy,
909     typename OwnershipPolicy,
910     typename CheckingPolicy,
911     typename StoragePolicy
912 >
913 inline
914 multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
~multi_pass()915 ~multi_pass()
916 {
917     if (OP::release())
918     {
919         CHP::destroy();
920         SP::destroy();
921         IP::destroy();
922     }
923 }
924 
925 template
926 <
927     typename InputT,
928     typename InputPolicy,
929     typename OwnershipPolicy,
930     typename CheckingPolicy,
931     typename StoragePolicy
932 >
933 inline
934 multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
multi_pass(multi_pass const & x)935 multi_pass(
936         multi_pass const& x)
937     : OP(x)
938     , CHP(x)
939     , SP(x)
940     , IP(x)
941 {
942     OP::clone();
943 }
944 
945 template
946 <
947     typename InputT,
948     typename InputPolicy,
949     typename OwnershipPolicy,
950     typename CheckingPolicy,
951     typename StoragePolicy
952 >
953 inline
954 multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>&
955 multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
operator =(multi_pass const & x)956 operator=(
957         multi_pass const& x)
958 {
959     multi_pass temp(x);
960     temp.swap(*this);
961     return *this;
962 }
963 
964 template
965 <
966     typename InputT,
967     typename InputPolicy,
968     typename OwnershipPolicy,
969     typename CheckingPolicy,
970     typename StoragePolicy
971 >
972 inline void
973 multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
swap(multi_pass & x)974 swap(multi_pass& x)
975 {
976     OP::swap(x);
977     CHP::swap(x);
978     SP::swap(x);
979     IP::swap(x);
980 }
981 
982 template
983 <
984     typename InputT,
985     typename InputPolicy,
986     typename OwnershipPolicy,
987     typename CheckingPolicy,
988     typename StoragePolicy
989 >
990 inline
991 typename multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
992 reference
993 multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
operator *() const994 operator*() const
995 {
996     CHP::check_if_valid();
997     return SP::dereference(*this);
998 }
999 
1000 template
1001 <
1002     typename InputT,
1003     typename InputPolicy,
1004     typename OwnershipPolicy,
1005     typename CheckingPolicy,
1006     typename StoragePolicy
1007 >
1008 inline
1009 typename multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
1010 pointer
1011 multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
operator ->() const1012 operator->() const
1013 {
1014     return &(operator*());
1015 }
1016 
1017 template
1018 <
1019     typename InputT,
1020     typename InputPolicy,
1021     typename OwnershipPolicy,
1022     typename CheckingPolicy,
1023     typename StoragePolicy
1024 >
1025 inline
1026 multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>&
1027 multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
operator ++()1028 operator++()
1029 {
1030     CHP::check_if_valid();
1031     SP::increment(*this);
1032     return *this;
1033 }
1034 
1035 template
1036 <
1037     typename InputT,
1038     typename InputPolicy,
1039     typename OwnershipPolicy,
1040     typename CheckingPolicy,
1041     typename StoragePolicy
1042 >
1043 inline
1044 multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>
1045 multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
operator ++(int)1046 operator++(int)
1047 {
1048     multi_pass
1049     <
1050         InputT,
1051         InputPolicy,
1052         OwnershipPolicy,
1053         CheckingPolicy,
1054         StoragePolicy
1055     > tmp(*this);
1056 
1057     ++*this;
1058 
1059     return tmp;
1060 }
1061 
1062 template
1063 <
1064     typename InputT,
1065     typename InputPolicy,
1066     typename OwnershipPolicy,
1067     typename CheckingPolicy,
1068     typename StoragePolicy
1069 >
1070 inline void
1071 multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
clear_queue()1072 clear_queue()
1073 {
1074     SP::clear_queue();
1075     CHP::clear_queue();
1076 }
1077 
1078 template
1079 <
1080     typename InputT,
1081     typename InputPolicy,
1082     typename OwnershipPolicy,
1083     typename CheckingPolicy,
1084     typename StoragePolicy
1085 >
1086 inline bool
1087 multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
is_eof() const1088 is_eof() const
1089 {
1090     return SP::is_eof(*this);
1091 }
1092 
1093 ///// Comparisons
1094 template
1095 <
1096     typename InputT,
1097     typename InputPolicy,
1098     typename OwnershipPolicy,
1099     typename CheckingPolicy,
1100     typename StoragePolicy
1101 >
1102 inline bool
1103 multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
operator ==(const multi_pass<InputT,InputPolicy,OwnershipPolicy,CheckingPolicy,StoragePolicy> & y) const1104 operator==(const multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy,
1105         StoragePolicy>& y) const
1106 {
1107     bool is_eof_ = SP::is_eof(*this);
1108     bool y_is_eof_ = SP::is_eof(y);
1109 
1110     if (is_eof_ && y_is_eof_)
1111     {
1112         return true;  // both are EOF
1113     }
1114     else if (is_eof_ ^ y_is_eof_)
1115     {
1116         return false; // one is EOF, one isn't
1117     }
1118     else if (!IP::same_input(y))
1119     {
1120         return false;
1121     }
1122     else
1123     {
1124         return SP::equal_to(y);
1125     }
1126 }
1127 
1128 template
1129 <
1130     typename InputT,
1131     typename InputPolicy,
1132     typename OwnershipPolicy,
1133     typename CheckingPolicy,
1134     typename StoragePolicy
1135 >
1136 inline bool
1137 multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
operator <(const multi_pass<InputT,InputPolicy,OwnershipPolicy,CheckingPolicy,StoragePolicy> & y) const1138 operator<(const multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy,
1139         StoragePolicy>& y) const
1140 {
1141     return SP::less_than(y);
1142 }
1143 
1144 template
1145 <
1146     typename InputT,
1147     typename InputPolicy,
1148     typename OwnershipPolicy,
1149     typename CheckingPolicy,
1150     typename StoragePolicy
1151 >
1152 inline
operator !=(const multi_pass<InputT,InputPolicy,OwnershipPolicy,CheckingPolicy,StoragePolicy> & x,const multi_pass<InputT,InputPolicy,OwnershipPolicy,CheckingPolicy,StoragePolicy> & y)1153 bool operator!=(
1154         const multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy,
1155                         StoragePolicy>& x,
1156         const multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy,
1157                         StoragePolicy>& y)
1158 {
1159     return !(x == y);
1160 }
1161 
1162 template
1163 <
1164     typename InputT,
1165     typename InputPolicy,
1166     typename OwnershipPolicy,
1167     typename CheckingPolicy,
1168     typename StoragePolicy
1169 >
1170 inline
operator >(const multi_pass<InputT,InputPolicy,OwnershipPolicy,CheckingPolicy,StoragePolicy> & x,const multi_pass<InputT,InputPolicy,OwnershipPolicy,CheckingPolicy,StoragePolicy> & y)1171 bool operator>(
1172         const multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy,
1173                         StoragePolicy>& x,
1174         const multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy,
1175                         StoragePolicy>& y)
1176 {
1177     return y < x;
1178 }
1179 
1180 template
1181 <
1182     typename InputT,
1183     typename InputPolicy,
1184     typename OwnershipPolicy,
1185     typename CheckingPolicy,
1186     typename StoragePolicy
1187 >
1188 inline
operator >=(const multi_pass<InputT,InputPolicy,OwnershipPolicy,CheckingPolicy,StoragePolicy> & x,const multi_pass<InputT,InputPolicy,OwnershipPolicy,CheckingPolicy,StoragePolicy> & y)1189 bool operator>=(
1190         const multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy,
1191                         StoragePolicy>& x,
1192         const multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy,
1193                         StoragePolicy>& y)
1194 {
1195     return !(x < y);
1196 }
1197 
1198 template
1199 <
1200     typename InputT,
1201     typename InputPolicy,
1202     typename OwnershipPolicy,
1203     typename CheckingPolicy,
1204     typename StoragePolicy
1205 >
1206 inline
operator <=(const multi_pass<InputT,InputPolicy,OwnershipPolicy,CheckingPolicy,StoragePolicy> & x,const multi_pass<InputT,InputPolicy,OwnershipPolicy,CheckingPolicy,StoragePolicy> & y)1207 bool operator<=(
1208         const multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy,
1209                         StoragePolicy>& x,
1210         const multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy,
1211                         StoragePolicy>& y)
1212 {
1213     return !(y < x);
1214 }
1215 
1216 ///// Generator function
1217 template <typename InputT>
1218 inline multi_pass<InputT,
1219     multi_pass_policies::input_iterator, multi_pass_policies::ref_counted,
1220     multi_pass_policies::buf_id_check, multi_pass_policies::std_deque>
make_multi_pass(InputT i)1221 make_multi_pass(InputT i)
1222 {
1223     return multi_pass<InputT,
1224         multi_pass_policies::input_iterator, multi_pass_policies::ref_counted,
1225         multi_pass_policies::buf_id_check, multi_pass_policies::std_deque>(i);
1226 }
1227 
1228 // this could be a template typedef, since such a thing doesn't
1229 // exist in C++, we'll use inheritance to accomplish the same thing.
1230 
1231 template <typename InputT, std::size_t N>
1232 class look_ahead :
1233     public multi_pass<
1234         InputT,
1235         multi_pass_policies::input_iterator,
1236         multi_pass_policies::first_owner,
1237         multi_pass_policies::no_check,
1238         multi_pass_policies::fixed_size_queue<N> >
1239 {
1240         typedef multi_pass<
1241             InputT,
1242             multi_pass_policies::input_iterator,
1243             multi_pass_policies::first_owner,
1244             multi_pass_policies::no_check,
1245             multi_pass_policies::fixed_size_queue<N> > base_t;
1246     public:
look_ahead()1247         look_ahead()
1248             : base_t() {}
1249 
look_ahead(InputT x)1250         explicit look_ahead(InputT x)
1251             : base_t(x) {}
1252 
look_ahead(look_ahead const & x)1253         look_ahead(look_ahead const& x)
1254             : base_t(x) {}
1255 
1256 #if BOOST_WORKAROUND(__GLIBCPP__, == 20020514)
look_ahead(int)1257         look_ahead(int)         // workaround for a bug in the library
1258             : base_t() {}       // shipped with gcc 3.1
1259 #endif // BOOST_WORKAROUND(__GLIBCPP__, == 20020514)
1260 
1261     // default generated operators destructor and assignment operator are okay.
1262 };
1263 
1264 template
1265 <
1266     typename InputT,
1267     typename InputPolicy,
1268     typename OwnershipPolicy,
1269     typename CheckingPolicy,
1270     typename StoragePolicy
1271 >
swap(multi_pass<InputT,InputPolicy,OwnershipPolicy,CheckingPolicy,StoragePolicy> & x,multi_pass<InputT,InputPolicy,OwnershipPolicy,CheckingPolicy,StoragePolicy> & y)1272 void swap(
1273     multi_pass<
1274         InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy
1275     > &x,
1276     multi_pass<
1277         InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy
1278     > &y)
1279 {
1280     x.swap(y);
1281 }
1282 
1283 namespace impl {
1284 
1285     template <typename T>
mp_swap(T & t1,T & t2)1286     inline void mp_swap(T& t1, T& t2)
1287     {
1288         using std::swap;
1289         using BOOST_SPIRIT_CLASSIC_NS::swap;
1290         swap(t1, t2);
1291     }
1292 }
1293 
1294 BOOST_SPIRIT_CLASSIC_NAMESPACE_END
1295 
1296 }} // namespace BOOST_SPIRIT_CLASSIC_NS
1297 
1298 #endif // BOOST_SPIRIT_ITERATOR_MULTI_PASS_HPP
1299