]>
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> | |
7c673cae FG |
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> | |
7c673cae FG |
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: | |
48 | ref_counted() | |
49 | : count(new std::size_t(1)) | |
50 | {} | |
51 | ||
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. | |
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. | |
65 | bool release() | |
66 | { | |
67 | if (!--*count) | |
68 | { | |
69 | delete count; | |
70 | count = 0; | |
71 | return true; | |
72 | } | |
73 | return false; | |
74 | } | |
75 | ||
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. | |
85 | 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: | |
109 | first_owner() | |
110 | : first(true) | |
111 | {} | |
112 | ||
113 | first_owner(first_owner const&) | |
114 | : first(false) | |
115 | {} | |
116 | ||
117 | void clone() | |
118 | { | |
119 | } | |
120 | ||
121 | // return true to indicate deletion of resources | |
122 | bool release() | |
123 | { | |
124 | return first; | |
125 | } | |
126 | ||
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: | |
134 | 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 | /////////////////////////////////////////////////////////////////////////////// | |
92f5a8d4 | 148 | class BOOST_SYMBOL_VISIBLE illegal_backtracking : public std::exception |
7c673cae FG |
149 | { |
150 | public: | |
151 | ||
92f5a8d4 | 152 | illegal_backtracking() BOOST_NOEXCEPT_OR_NOTHROW {} |
20effc67 | 153 | ~illegal_backtracking() BOOST_NOEXCEPT_OR_NOTHROW BOOST_OVERRIDE {} |
7c673cae | 154 | |
20effc67 TL |
155 | const char* |
156 | what() const BOOST_NOEXCEPT_OR_NOTHROW BOOST_OVERRIDE | |
7c673cae FG |
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 | |
20effc67 | 166 | // iterator dereferences that are out of the range of the queue. |
7c673cae FG |
167 | /////////////////////////////////////////////////////////////////////////////// |
168 | class buf_id_check | |
169 | { | |
170 | protected: | |
171 | buf_id_check() | |
172 | : shared_buf_id(new unsigned long(0)) | |
173 | , buf_id(0) | |
174 | {} | |
175 | ||
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. | |
182 | void destroy() | |
183 | { | |
184 | delete shared_buf_id; | |
185 | shared_buf_id = 0; | |
186 | } | |
187 | ||
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. | |
195 | 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 | |
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: | |
223 | no_check() {} | |
224 | no_check(no_check const&) {} | |
225 | void destroy() {} | |
226 | void swap(no_check&) {} | |
227 | void check_if_valid() const {} | |
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: | |
254 | inner() | |
255 | : queuedElements(new queue_type) | |
256 | , queuePosition(0) | |
257 | {} | |
258 | ||
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. | |
265 | void destroy() | |
266 | { | |
267 | BOOST_SPIRIT_ASSERT(NULL != queuedElements); | |
268 | delete queuedElements; | |
269 | queuedElements = 0; | |
270 | } | |
271 | ||
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> | |
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> | |
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 | |
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> | |
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== | |
352 | bool equal_to(inner const& x) const | |
353 | { | |
354 | return queuePosition == x.queuePosition; | |
355 | } | |
356 | ||
357 | // called by operator< | |
358 | 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: | |
393 | inner() | |
394 | : queuedElements(new queue_type) | |
395 | , queuePosition(queuedElements->begin()) | |
396 | {} | |
397 | ||
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. | |
404 | void destroy() | |
405 | { | |
406 | BOOST_SPIRIT_ASSERT(NULL != queuedElements); | |
407 | delete queuedElements; | |
408 | queuedElements = 0; | |
409 | } | |
410 | ||
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> | |
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> | |
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 | |
452 | void clear_queue() | |
453 | {} | |
454 | ||
455 | // called to determine whether the iterator is an eof iterator | |
456 | template <typename MultiPassT> | |
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== | |
464 | bool equal_to(inner const& x) const | |
465 | { | |
466 | return queuePosition == x.queuePosition; | |
467 | } | |
468 | ||
469 | // called by operator< | |
470 | 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 | |
92f5a8d4 | 493 | typename std::iterator_traits<InputT>::value_type |
7c673cae FG |
494 | result_type; |
495 | ||
496 | public: | |
497 | typedef result_type value_type; | |
498 | ||
499 | private: | |
500 | struct Data { | |
501 | 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 | |
92f5a8d4 | 518 | typename std::iterator_traits<InputT>::difference_type |
7c673cae FG |
519 | difference_type; |
520 | typedef | |
92f5a8d4 | 521 | typename std::iterator_traits<InputT>::pointer |
7c673cae FG |
522 | pointer; |
523 | typedef | |
92f5a8d4 | 524 | typename std::iterator_traits<InputT>::reference |
7c673cae FG |
525 | reference; |
526 | ||
527 | protected: | |
528 | inner() | |
529 | : data(0) | |
530 | {} | |
531 | ||
532 | inner(InputT x) | |
533 | : data(new Data(x)) | |
534 | {} | |
535 | ||
536 | inner(inner const& x) | |
537 | : data(x.data) | |
538 | {} | |
539 | ||
540 | void destroy() | |
541 | { | |
542 | delete data; | |
543 | data = 0; | |
544 | } | |
545 | ||
546 | bool same_input(inner const& x) const | |
547 | { | |
548 | return data == x.data; | |
549 | } | |
550 | ||
551 | typedef | |
92f5a8d4 | 552 | typename std::iterator_traits<InputT>::value_type |
7c673cae FG |
553 | value_t; |
554 | void swap(inner& x) | |
555 | { | |
556 | impl::mp_swap(data, x.data); | |
557 | } | |
558 | ||
559 | 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: | |
568 | reference get_input() const | |
569 | { | |
570 | BOOST_SPIRIT_ASSERT(NULL != data); | |
571 | ensure_initialized(); | |
572 | return data->curtok; | |
573 | } | |
574 | ||
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 | ||
582 | 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: | |
612 | inner() | |
613 | : curtok(new int(0)) | |
614 | {} | |
615 | ||
616 | inner(InputT x) | |
617 | : curtok(new int(x)) | |
618 | {} | |
619 | ||
620 | inner(inner const& x) | |
621 | : curtok(x.curtok) | |
622 | {} | |
623 | ||
624 | void destroy() | |
625 | { | |
626 | delete curtok; | |
627 | curtok = 0; | |
628 | } | |
629 | ||
630 | bool same_input(inner const& x) const | |
631 | { | |
632 | return curtok == x.curtok; | |
633 | } | |
634 | ||
635 | void swap(inner& x) | |
636 | { | |
637 | impl::mp_swap(curtok, x.curtok); | |
638 | } | |
639 | ||
640 | public: | |
641 | reference get_input() const | |
642 | { | |
643 | return *curtok; | |
644 | } | |
645 | ||
646 | void advance_input() | |
647 | { | |
648 | extern int yylex(); | |
649 | *curtok = yylex(); | |
650 | } | |
651 | ||
652 | 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: | |
687 | inner() | |
688 | : ftor(0) | |
689 | , curtok(0) | |
690 | {} | |
691 | ||
692 | inner(FunctorT const& x) | |
693 | : ftor(new FunctorT(x)) | |
694 | , curtok(new result_type((*ftor)())) | |
695 | {} | |
696 | ||
697 | inner(inner const& x) | |
698 | : ftor(x.ftor) | |
699 | , curtok(x.curtok) | |
700 | {} | |
701 | ||
702 | void destroy() | |
703 | { | |
704 | delete ftor; | |
705 | ftor = 0; | |
706 | delete curtok; | |
707 | curtok = 0; | |
708 | } | |
709 | ||
710 | bool same_input(inner const& x) const | |
711 | { | |
712 | return ftor == x.ftor; | |
713 | } | |
714 | ||
715 | void swap(inner& x) | |
716 | { | |
717 | impl::mp_swap(curtok, x.curtok); | |
718 | impl::mp_swap(ftor, x.ftor); | |
719 | } | |
720 | ||
721 | public: | |
722 | reference get_input() const | |
723 | { | |
724 | return *curtok; | |
725 | } | |
726 | ||
727 | void advance_input() | |
728 | { | |
729 | if (curtok) { | |
730 | *curtok = (*ftor)(); | |
731 | } | |
732 | } | |
733 | ||
734 | bool input_at_eof() const | |
735 | { | |
736 | return !curtok || *curtok == ftor->eof; | |
737 | } | |
738 | ||
739 | 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 | ||
11fdf7f2 | 761 | // Meta-function to generate a std::iterator<>-like base class for multi_pass. |
7c673cae FG |
762 | template <typename InputPolicyT, typename InputT> |
763 | struct iterator_base_creator | |
764 | { | |
765 | typedef typename InputPolicyT::BOOST_NESTED_TEMPLATE inner<InputT> input_t; | |
766 | ||
11fdf7f2 TL |
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 | }; | |
7c673cae FG |
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>:: | |
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>:: | |
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>:: | |
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>:: | |
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>:: | |
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>:: | |
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>:: | |
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>:: | |
994 | 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>:: | |
1012 | 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>:: | |
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>:: | |
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>:: | |
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>:: | |
1088 | 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>:: | |
1104 | 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>:: | |
1138 | 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 | |
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 | |
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 | |
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 | |
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> | |
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: | |
1247 | look_ahead() | |
1248 | : base_t() {} | |
1249 | ||
1250 | explicit look_ahead(InputT x) | |
1251 | : base_t(x) {} | |
1252 | ||
1253 | look_ahead(look_ahead const& x) | |
1254 | : base_t(x) {} | |
1255 | ||
1256 | #if BOOST_WORKAROUND(__GLIBCPP__, == 20020514) | |
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 | > | |
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> | |
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 |