| [/============================================================================== |
| Copyright (C) 2001-2010 Hartmut Kaiser |
| Copyright (C) 2001-2010 Joel de Guzman |
| Copyright (C) 2001-2002 Daniel C. Nuffer |
| |
| Distributed under the Boost Software License, Version 1.0. (See accompanying |
| file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| ===============================================================================/] |
| |
| [section:multi_pass The multi pass iterator] |
| |
| Backtracking in __qi__ requires the use of the following types of iterator: |
| forward, bidirectional, or random access. Because of backtracking, input |
| iterators cannot be used. Therefore, the standard library classes |
| `std::istreambuf_iterator` and `std::istream_iterator`, that fall under the |
| category of input iterators, cannot be used. Another input iterator that is of |
| interest is one that wraps a lexer, such as LEX. |
| |
| [note In general, __qi__ generates recursive descent parser which require |
| backtracking parsers by design. For this reason we need to provide at |
| least forward iterators to any of __qi__'s API functions. This is not an |
| absolute requirement though. In the future, we shall see more |
| deterministic parsers that require no more than 1 character (token) of |
| lookahead. Such parsers allow us to use input iterators such as the |
| `std::istream_iterator` as is. ] |
| |
| Backtracking can be implemented only if we are allowed to save an iterator |
| position, i.e. making a copy of the current iterator. Unfortunately, with an |
| input iterator, there is no way to do so, and thus input iterators will not |
| work with backtracking in __qi__. One solution to this problem is to simply |
| load all the data to be parsed into a container, such as a vector or deque, |
| and then pass the begin and end of the container to __qi__. This method can be |
| too memory intensive for certain applications, which is why the `multi_pass` |
| iterator was created. |
| |
| [heading Using the multi_pass] |
| |
| The `multi_pass` iterator will convert any input iterator into a forward |
| iterator suitable for use with __qi__. `multi_pass` will buffer data when |
| needed and will discard the buffer when its contents is not needed anymore. |
| This happens either if only one copy of the iterator exists or if no |
| backtracking can occur. |
| |
| A grammar must be designed with care if the `multi_pass` iterator is used. |
| Any rule that may need to backtrack, such as one that contains an alternative, |
| will cause data to be buffered. The rules that are optimal to use are |
| repetition constructs (as kleene and plus). |
| |
| Sequences of the form `a >> b` will buffer data as well. This is different from |
| the behavior of __classic__ but for a good reason. Sequences need to reset the |
| current iterator to its initial state if one of the components of a sequence |
| fails to match. To compensate for this behavior we added functionality to |
| the `expect` parsers (i.e. constructs like `a > b`). Expectation points introduce |
| deterministic points into the grammar ensuring no backtracking can occur if |
| they match. For this reason we clear the buffers of any multi_pass iterator |
| on each expectation point, ensuring minimal buffer content even for large |
| grammars. |
| |
| [important If you use an error handler in conjunction with the `expect` parser |
| while utilizing a `multi_pass` iterator and you intend to use |
| the error handler to force a `retry` or a `fail` (see the |
| description of error handlers - __fixme__: insert link), then |
| you need to instantiate the error handler using `retry` or `fail`, |
| for instance: |
| `` |
| rule r<iterator_type> r; |
| on_error<retry>(r, std::cout << phoenix::val("Error!")); |
| `` |
| If you fail to do so the resulting code will trigger an assert |
| statement at runtime.] |
| |
| Any rule that repeats, such as kleene_star (`*a`) or positive such as (`+a`), |
| will only buffer the data for the current repetition. |
| |
| In typical grammars, ambiguity and therefore lookahead is often localized. In |
| fact, many well designed languages are fully deterministic and require no |
| lookahead at all. Peeking at the first character from the input will |
| immediately determine the alternative branch to take. Yet, even with highly |
| ambiguous grammars, alternatives are often of the form `*(a | b | c | d)`. |
| The input iterator moves on and is never stuck at the beginning. Let's look at |
| a Pascal snippet for example: |
| |
| program = |
| programHeading >> block >> '.' |
| ; |
| |
| block = |
| *( labelDeclarationPart |
| | constantDefinitionPart |
| | typeDefinitionPart |
| | variableDeclarationPart |
| | procedureAndFunctionDeclarationPart |
| ) |
| >> statementPart |
| ; |
| |
| Notice the alternatives inside the Kleene star in the rule block . The rule |
| gobbles the input in a linear manner and throws away the past history with each |
| iteration. As this is fully deterministic LL(1) grammar, each failed |
| alternative only has to peek 1 character (token). The alternative that consumes |
| more than 1 character (token) is definitely a winner. After which, the Kleene |
| star moves on to the next. |
| |
| Now, after the lecture on the features to be careful with when using |
| `multi_pass`, you may think that `multi_pass` is way too restrictive to use. |
| That's not the case. If your grammar is deterministic, you can make use of |
| the `flush_multi_pass` pseudo parser in your grammar to ensure that data is not |
| buffered when unnecessary (`flush_multi_pass` is available from the __qi__ |
| parser __repo__). |
| |
| Here we present a minimal example showing a minimal use case. The `multi_pass` |
| iterator is highly configurable, but the default policies have been chosen so |
| that its easily usable with input iterators such as `std::istreambuf_iterator`. |
| For the complete source code of this example please refer to |
| [@../../example/support/multi_pass.cpp multi_pass.cpp]. |
| |
| [import ../../example/support/multi_pass.cpp] |
| [tutorial_multi_pass] |
| |
| [heading Using the flush_multi_pass parser] |
| |
| The __spirit__ __repo__ contains the `flush_multi_pass` parser component. |
| This is usable in conjunction with the `multi_pass` iterator to minimize the |
| buffering. It allows to insert explicit synchronization points into your |
| grammar where it is safe to clear any stored input as it is ensured that no |
| backtracking can occur at this point anymore. |
| |
| When the `flush_multi_pass` parser is used with `multi_pass`, it will call |
| `multi_pass::clear_queue()`. This will cause any buffered data to be erased. |
| This also will invalidate all other copies of multi_pass and they should not |
| be used. If they are, an `boost::illegal_backtracking` exception will be |
| thrown. |
| |
| [heading The multi_pass Policies] |
| |
| The `multi_pass` iterator is a templated class configurable using policies. |
| The description of `multi_pass` above is how it was originally implemented |
| (before it used policies), and is the default configuration now. But, |
| `multi_pass` is capable of much more. Because of the open-ended nature of |
| policies, you can write your own policy to make `multi_pass` behave in a way |
| that we never before imagined. |
| |
| The multi_pass class has two template parameters: |
| |
| [variablelist The multi_pass template parameters |
| [[Input] [The type multi_pass uses to acquire it's input. This is |
| typically an input iterator, or functor.]] |
| [[Policies] [The combined policies to use to create an instance of a |
| multi_pass iterator. This combined policy type is described |
| below]] |
| ] |
| |
| It is possible to implement all of the required functionality of the combined |
| policy in a single class. But it has shown to be more convenient to split this |
| into four different groups of functions, i.e. four separate, but well |
| coordinated policies. For this reason the `multi_pass` library |
| implements a template `iterator_policies::default_policy` allowing to combine |
| several different policies, each implementing one of the functionality groups: |
| |
| [table Policies needed for default_policy template |
| [[Template Parameter] [Description]] |
| [[`OwnershipPolicy`] [This policy determines how `multi_pass` deals with |
| it's shared components.]] |
| [[`CheckingPolicy`] [This policy determines how checking for invalid |
| iterators is done.]] |
| [[`InputPolicy`] [A class that defines how `multi_pass` acquires its |
| input. The `InputPolicy` is parameterized by the |
| `Input` template parameter to the `multi_pass`.]] |
| [[`StoragePolicy`] [The buffering scheme used by `multi_pass` is |
| determined and managed by the StoragePolicy.]] |
| ] |
| |
| The `multi_pass` library contains several predefined policy implementations |
| for each of the policy types as described above. First we will describe those |
| predefined types. Afterwards we will give some guidelines how you can write |
| your own policy implementations. |
| |
| [heading Predefined policies] |
| |
| All predefined `multi_pass` policies are defined in the namespace |
| `boost::spirit::iterator_policies`. |
| |
| [table Predefined policy classes |
| [[Class name] [Description]] |
| [[*InputPolicy* classes]] |
| [[`input_iterator`] [This policy directs `multi_pass` to read from an |
| input iterator of type `Input`.]] |
| [[`buffering_input_iterator`] [This policy directs `multi_pass` to read from an |
| input iterator of type `Input`. Additionally it buffers |
| the last character received from the underlying iterator. |
| This allows to wrap iterators not buffering the last |
| character on their own (as `std::istreambuf_iterator`).]] |
| [[`istream`] [This policy directs `multi_pass` to read from an |
| input stream of type `Input` (usually a |
| `std::basic_istream`).]] |
| [[`lex_input`] [This policy obtains it's input by calling yylex(), |
| which would typically be provided by a scanner |
| generated by __flex__. If you use this policy your code |
| must link against a __flex__ generated scanner.]] |
| [[`functor_input`] [This input policy obtains it's data by calling a |
| functor of type `Input`. The functor must meet |
| certain requirements. It must have a typedef called |
| `result_type` which should be the type returned |
| from `operator()`. Also, since an input policy needs |
| a way to determine when the end of input has been |
| reached, the functor must contain a static variable |
| named `eof` which is comparable to a variable of |
| `result_type`.]] |
| [[`split_functor_input`][This is essentially the same as the `functor_input` |
| policy except that the (user supplied) function |
| object exposes separate `unique` and `shared` sub |
| classes, allowing to integrate the functors /unique/ |
| data members with the `multi_pass` data items held |
| by each instance and its /shared/ data members will |
| be integrated with the `multi_pass` members shared |
| by all copies.]] |
| |
| [[*OwnershipPolicy* classes]] |
| [[`ref_counted`] [This class uses a reference counting scheme. |
| The `multi_pass` will delete it's shared components |
| when the count reaches zero.]] |
| [[`first_owner`] [When this policy is used, the first `multi_pass` |
| created will be the one that deletes the shared data. |
| Each copy will not take ownership of the shared data. |
| This works well for __spirit__, since no dynamic |
| allocation of iterators is done. All copies are made |
| on the stack, so the original iterator has the |
| longest lifespan.]] |
| |
| [[*CheckingPolicy* classes]] |
| [[`no_check`] [This policy does no checking at all.]] |
| [[`buf_id_check`] [This policy keeps around a buffer id, or a buffer |
| age. Every time `clear_queue()` is called on a |
| `multi_pass` iterator, it is possible that all other |
| iterators become invalid. When `clear_queue()` is |
| called, `buf_id_check` increments the buffer id. |
| When an iterator is dereferenced, this policy checks |
| that the buffer id of the iterator matches the shared |
| buffer id. This policy is most effective when used |
| together with the `split_std_deque` StoragePolicy. |
| It should not be used with the `fixed_size_queue` |
| StoragePolicy, because it will not detect iterator |
| dereferences that are out of range.]] |
| [[full_check] [This policy has not been implemented yet. When it |
| is, it will keep track of all iterators and make |
| sure that they are all valid. This will be mostly |
| useful for debugging purposes as it will incur |
| significant overhead.]] |
| |
| [[*StoragePolicy* classes]] |
| [[`split_std_deque`] [Despite its name this policy keeps all buffered data |
| in a `std::vector`. All data is stored as long as |
| there is more than one iterator. Once the iterator |
| count goes down to one, and the queue is no longer |
| needed, it is cleared, freeing up memory. The queue |
| can also be forcibly cleared by calling |
| `multi_pass::clear_queue()`.]] |
| [[`fixed_size_queue<N>`][This policy keeps a circular buffer that is size |
| `N+1` and stores `N` elements. `fixed_size_queue` |
| is a template with a `std::size_t` parameter that |
| specified the queue size. It is your responsibility |
| to ensure that `N` is big enough for your parser. |
| Whenever the foremost iterator is incremented, the |
| last character of the buffer is automatically |
| erased. Currently there is no way to tell if an |
| iterator is trailing too far behind and has become |
| invalid. No dynamic allocation is done by this |
| policy during normal iterator operation, only on |
| initial construction. The memory usage of this |
| `StoragePolicy` is set at `N+1` bytes, unlike |
| `split_std_deque`, which is unbounded.]] |
| ] |
| |
| [heading Combinations: How to specify your own custom multi_pass] |
| |
| The beauty of policy based designs is that you can mix and match policies to |
| create your own custom iterator by selecting the policies you want. Here's an |
| example of how to specify a custom `multi_pass` that wraps an |
| `std::istream_iterator<char>`, and is slightly more efficient than the default |
| `multi_pass` (as generated by the `make_default_multi_pass()` API function) |
| because it uses the `iterator_policies::first_owner` OwnershipPolicy and the |
| `iterator_policies::no_check` CheckingPolicy: |
| |
| typedef multi_pass< |
| std::istream_iterator<char> |
| , iterator_policies::default_policy< |
| iterator_policies::first_owner |
| , iterator_policies::no_check |
| , iterator_policies::buffering_input_iterator |
| , iterator_policies::split_std_deque |
| > |
| > first_owner_multi_pass_type; |
| |
| The default template parameters for `iterator_policies::default_policy` are: |
| |
| * `iterator_policies::ref_counted` OwnershipPolicy |
| * `iterator_policies::no_check` CheckingPolicy, if `BOOST_SPIRIT_DEBUG` is |
| defined: `iterator_policies::buf_id_check` CheckingPolicy |
| * `iterator_policies::buffering_input_iterator` InputPolicy, and |
| * `iterator_policies::split_std_deque` StoragePolicy. |
| |
| So if you use `multi_pass<std::istream_iterator<char> >` you will get those |
| pre-defined behaviors while wrapping an `std::istream_iterator<char>`. |
| |
| [heading Dealing with constant look ahead] |
| |
| There is one other pre-defined class called `look_ahead`. The class |
| `look_ahead` is another predefine `multi_pass` iterator type. It has two |
| template parameters: `Input`, the type of the input iterator to wrap, and a |
| `std::size_t N`, which specifies the size of the buffer to the |
| `fixed_size_queue` policy. While the default multi_pass configuration is |
| designed for safety, `look_ahead` is designed for speed. `look_ahead` is derived |
| from a multi_pass with the following policies: `input_iterator` InputPolicy, |
| `first_owner` OwnershipPolicy, `no_check` CheckingPolicy, and |
| `fixed_size_queue<N>` StoragePolicy. |
| |
| This iterator is defined by including the files: |
| |
| // forwards to <boost/spirit/home/support/look_ahead.hpp> |
| #include <boost/spirit/include/support_look_ahead.hpp> |
| |
| Also, see __include_structure__. |
| |
| [heading Reading from standard input streams] |
| |
| Yet another predefined iterator for wrapping standard input streams (usually a |
| `std::basic_istream<>`) is called `basic_istream_iterator<Char, Traits>`. This |
| class is usable as a drop in replacement for `std::istream_iterator<Char, Traits>`. |
| Its only difference is that it is a forward iterator (instead of the |
| `std::istream_iterator`, which is an input iterator). `basic_istream_iterator` |
| is derived from a multi_pass with the following policies: `istream` InputPolicy, |
| `ref_counted` OwnershipPolicy, `no_check` CheckingPolicy, and |
| `split_std_deque` StoragePolicy. |
| |
| There exists an additional predefined typedef: |
| |
| typedef basic_istream_iterator<char, std::char_traits<char> > istream_iterator; |
| |
| This iterator is defined by including the files: |
| |
| // forwards to <boost/spirit/home/support/istream_iterator.hpp> |
| #include <boost/spirit/include/support_istream_iterator.hpp> |
| |
| Also, see __include_structure__. |
| |
| [heading How to write a functor for use with the `functor_input` InputPolicy] |
| |
| If you want to use the `functor_input` InputPolicy, you can write your own |
| function object that will supply the input to `multi_pass`. The function object |
| must satisfy several requirements. It must have a typedef `result_type` which |
| specifies the return type of its `operator()`. This is standard practice in the |
| STL. Also, it must supply a static variable called eof which is compared against |
| to know whether the input has reached the end. Last but not least the function |
| object must be default constructible. Here is an example: |
| |
| // define the function object |
| class iterate_a2m |
| { |
| public: |
| typedef char result_type; |
| |
| iterate_a2m() : c('A') {} |
| iterate_a2m(char c) : c_(c) {} |
| |
| result_type operator()() const |
| { |
| if (c_ == 'M') |
| return eof; |
| return c_++; |
| } |
| |
| static result_type eof; |
| |
| private: |
| char c_; |
| }; |
| |
| iterate_a2m::result_type iterate_a2m::eof = iterate_a2m::result_type('\0'); |
| |
| // create two iterators using the define function object, one of which is |
| // an end iterator |
| typedef multi_pass<iterate_a2m |
| , iterator_policies::functor_input |
| , iterator_policies::first_owner |
| , iterator_policies::no_check |
| , iterator_policies::split_std_deque> |
| functor_multi_pass_type; |
| |
| functor_multi_pass_type first = functor_multi_pass_t(iterate_a2m()); |
| functor_multi_pass_type last; |
| |
| // use the iterators: this will print "ABCDEFGHIJKL" |
| while (first != last) { |
| std::cout << *first; |
| ++first; |
| } |
| |
| [heading How to write policies for use with multi_pass] |
| |
| All policies to be used with the `default_policy` template need to have two |
| embedded classes: `unique` and `shared`. The `unique` class needs to implement |
| all required functions for a particular policy type. In addition it may hold |
| all member data items being /unique/ for a particular instance of a `multi_pass` |
| (hence the name). The `shared` class does not expose any member functions |
| (except sometimes a constructor), but it may hold all member data items to be |
| /shared/ between all copies of a particular `multi_pass`. |
| |
| [heading InputPolicy] |
| |
| An `InputPolicy` must have the following interface: |
| |
| struct input_policy |
| { |
| // Input is the same type used as the first template parameter |
| // while instantiating the multi_pass |
| template <typename Input> |
| struct unique |
| { |
| // these typedef's will be exposed as the multi_pass iterator |
| // properties |
| typedef __unspecified_type__ value_type; |
| typedef __unspecified_type__ difference_type; |
| typedef __unspecified_type__ distance_type; |
| typedef __unspecified_type__ pointer; |
| typedef __unspecified_type__ reference; |
| |
| unique() {} |
| explicit unique(Input) {} |
| |
| // destroy is called whenever the last copy of a multi_pass is |
| // destructed (ownership_policy::release() returned true) |
| // |
| // mp: is a reference to the whole multi_pass instance |
| template <typename MultiPass> |
| static void destroy(MultiPass& mp); |
| |
| // swap is called by multi_pass::swap() |
| void swap(unique&); |
| |
| // get_input is called whenever the next input character/token |
| // should be fetched. |
| // |
| // mp: is a reference to the whole multi_pass instance |
| // |
| // This method is expected to return a reference to the next |
| // character/token |
| template <typename MultiPass> |
| static typename MultiPass::reference get_input(MultiPass& mp); |
| |
| // advance_input is called whenever the underlying input stream |
| // should be advanced so that the next call to get_input will be |
| // able to return the next input character/token |
| // |
| // mp: is a reference to the whole multi_pass instance |
| template <typename MultiPass> |
| static void advance_input(MultiPass& mp); |
| |
| // input_at_eof is called to test whether this instance is a |
| // end of input iterator. |
| // |
| // mp: is a reference to the whole multi_pass instance |
| // |
| // This method is expected to return true if the end of input is |
| // reached. It is often used in the implementation of the function |
| // storage_policy::is_eof. |
| template <typename MultiPass> |
| static bool input_at_eof(MultiPass const& mp); |
| |
| // input_is_valid is called to verify if the parameter t represents |
| // a valid input character/token |
| // |
| // mp: is a reference to the whole multi_pass instance |
| // t: is the character/token to test for validity |
| // |
| // This method is expected to return true if the parameter t |
| // represents a valid character/token. |
| template <typename MultiPass> |
| static bool input_is_valid(MultiPass const& mp, value_type const& t); |
| }; |
| |
| // Input is the same type used as the first template parameter passed |
| // while instantiating the multi_pass |
| template <typename Input> |
| struct shared |
| { |
| explicit shared(Input) {} |
| }; |
| }; |
| |
| It is possible to derive the struct `unique` from the type |
| `boost::spirit::detail::default_input_policy`. This type implements a minimal |
| sufficient interface for some of the required functions, simplifying the task |
| of writing a new input policy. |
| |
| This class may implement a function `destroy()` being called during destruction |
| of the last copy of a `multi_pass`. This function should be used to free any of |
| the shared data items the policy might have allocated during construction of |
| its `shared` part. Because of the way `multi_pass` is implemented any allocated |
| data members in `shared` should _not_ be deep copied in a copy constructor of |
| `shared`. |
| |
| [heading OwnershipPolicy] |
| |
| The `OwnershipPolicy` must have the following interface: |
| |
| struct ownership_policy |
| { |
| struct unique |
| { |
| // destroy is called whenever the last copy of a multi_pass is |
| // destructed (ownership_policy::release() returned true) |
| // |
| // mp: is a reference to the whole multi_pass instance |
| template <typename MultiPass> |
| static void destroy(MultiPass& mp); |
| |
| // swap is called by multi_pass::swap() |
| void swap(unique&); |
| |
| // clone is called whenever a multi_pass is copied |
| // |
| // mp: is a reference to the whole multi_pass instance |
| template <typename MultiPass> |
| static void clone(MultiPass& mp); |
| |
| // release is called whenever a multi_pass is destroyed |
| // |
| // mp: is a reference to the whole multi_pass instance |
| // |
| // The method is expected to return true if the destructed |
| // instance is the last copy of a particular multi_pass. |
| template <typename MultiPass> |
| static bool release(MultiPass& mp); |
| |
| // is_unique is called to test whether this instance is the only |
| // existing copy of a particular multi_pass |
| // |
| // mp: is a reference to the whole multi_pass instance |
| // |
| // The method is expected to return true if this instance is unique |
| // (no other copies of this multi_pass exist). |
| template <typename MultiPass> |
| static bool is_unique(MultiPass const& mp); |
| }; |
| |
| struct shared {}; |
| }; |
| |
| It is possible to derive the struct `unique` from the type |
| `boost::spirit::detail::default_ownership_policy`. This type implements a |
| minimal sufficient interface for some of the required functions, simplifying |
| the task of writing a new ownership policy. |
| |
| This class may implement a function `destroy()` being called during destruction |
| of the last copy of a `multi_pass`. This function should be used to free any of |
| the shared data items the policy might have allocated during construction of |
| its `shared` part. Because of the way `multi_pass` is implemented any allocated |
| data members in `shared` should _not_ be deep copied in a copy constructor of |
| `shared`. |
| |
| [heading CheckingPolicy] |
| |
| The `CheckingPolicy` must have the following interface: |
| |
| struct checking_policy |
| { |
| struct unique |
| { |
| // swap is called by multi_pass::swap() |
| void swap(unique&); |
| |
| // destroy is called whenever the last copy of a multi_pass is |
| // destructed (ownership_policy::release() returned true) |
| // |
| // mp: is a reference to the whole multi_pass instance |
| template <typename MultiPass> |
| static void destroy(MultiPass& mp); |
| |
| // docheck is called before the multi_pass is dereferenced or |
| // incremented. |
| // |
| // mp: is a reference to the whole multi_pass instance |
| // |
| // This method is expected to make sure the multi_pass instance is |
| // still valid. If it is invalid an exception should be thrown. |
| template <typename MultiPass> |
| static void docheck(MultiPass const& mp); |
| |
| // clear_queue is called whenever the function |
| // multi_pass::clear_queue is called on this instance |
| // |
| // mp: is a reference to the whole multi_pass instance |
| template <typename MultiPass> |
| static void clear_queue(MultiPass& mp); |
| }; |
| |
| struct shared {}; |
| }; |
| |
| It is possible to derive the struct `unique` from the type |
| `boost::spirit::detail::default_checking_policy`. This type implements a |
| minimal sufficient interface for some of the required functions, simplifying |
| the task of writing a new checking policy. |
| |
| This class may implement a function `destroy()` being called during destruction |
| of the last copy of a `multi_pass`. This function should be used to free any of |
| the shared data items the policy might have allocated during construction of |
| its `shared` part. Because of the way `multi_pass` is implemented any allocated |
| data members in `shared` should _not_ be deep copied in a copy constructor of |
| `shared`. |
| |
| [heading StoragePolicy] |
| |
| A `StoragePolicy` must have the following interface: |
| |
| struct storage_policy |
| { |
| // Value is the same type as typename MultiPass::value_type |
| template <typename Value> |
| struct unique |
| { |
| // destroy is called whenever the last copy of a multi_pass is |
| // destructed (ownership_policy::release() returned true) |
| // |
| // mp: is a reference to the whole multi_pass instance |
| template <typename MultiPass> |
| static void destroy(MultiPass& mp); |
| |
| // swap is called by multi_pass::swap() |
| void swap(unique&); |
| |
| // dereference is called whenever multi_pass::operator*() is invoked |
| // |
| // mp: is a reference to the whole multi_pass instance |
| // |
| // This function is expected to return a reference to the current |
| // character/token. |
| template <typename MultiPass> |
| static typename MultiPass::reference dereference(MultiPass const& mp); |
| |
| // increment is called whenever multi_pass::operator++ is invoked |
| // |
| // mp: is a reference to the whole multi_pass instance |
| template <typename MultiPass> |
| static void increment(MultiPass& mp); |
| |
| // |
| // mp: is a reference to the whole multi_pass instance |
| template <typename MultiPass> |
| static void clear_queue(MultiPass& mp); |
| |
| // is_eof is called to test whether this instance is a end of input |
| // iterator. |
| // |
| // mp: is a reference to the whole multi_pass instance |
| // |
| // This method is expected to return true if the end of input is |
| // reached. |
| template <typename MultiPass> |
| static bool is_eof(MultiPass const& mp); |
| |
| // less_than is called whenever multi_pass::operator==() is invoked |
| // |
| // mp: is a reference to the whole multi_pass instance |
| // rhs: is the multi_pass reference this instance is compared |
| // to |
| // |
| // This function is expected to return true if the current instance |
| // is equal to the right hand side multi_pass instance |
| template <typename MultiPass> |
| static bool equal_to(MultiPass const& mp, MultiPass const& rhs); |
| |
| // less_than is called whenever multi_pass::operator<() is invoked |
| // |
| // mp: is a reference to the whole multi_pass instance |
| // rhs: is the multi_pass reference this instance is compared |
| // to |
| // |
| // This function is expected to return true if the current instance |
| // is less than the right hand side multi_pass instance |
| template <typename MultiPass> |
| static bool less_than(MultiPass const& mp, MultiPass const& rhs); |
| }; |
| |
| // Value is the same type as typename MultiPass::value_type |
| template <typename Value> |
| struct shared {}; |
| }; |
| |
| It is possible to derive the struct `unique` from the type |
| `boost::spirit::detail::default_storage_policy`. This type implements a |
| minimal sufficient interface for some of the required functions, simplifying |
| the task of writing a new storage policy. |
| |
| This class may implement a function `destroy()` being called during destruction |
| of the last copy of a `multi_pass`. This function should be used to free any of |
| the shared data items the policy might have allocated during construction of |
| its `shared` part. Because of the way `multi_pass` is implemented any allocated |
| data members in `shared` should _not_ be deep copied in a copy constructor of |
| `shared`. |
| |
| Generally, a `StoragePolicy` is the trickiest policy to implement. You should |
| study and understand the existing `StoragePolicy` classes before you try and |
| write your own. |
| |
| |
| [endsect] |
| |
| |
| |