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