123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723 |
- [/==============================================================================
- Copyright (C) 2001-2011 Hartmut Kaiser
- Copyright (C) 2001-2011 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:
- #include <iostream>
- #include <boost/spirit/home/qi.hpp>
- #include <boost/spirit/home/support.hpp>
- #include <boost/spirit/home/support/multi_pass.hpp>
- #include <boost/spirit/home/support/iterators/detail/functor_input_policy.hpp>
- // 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()()
- {
- 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('M');
- using namespace boost::spirit;
- // create two iterators using the define function object, one of which is
- // an end iterator
- typedef multi_pass<iterate_a2m
- , iterator_policies::first_owner
- , iterator_policies::no_check
- , iterator_policies::functor_input
- , iterator_policies::split_std_deque>
- functor_multi_pass_type;
- int main()
- {
- functor_multi_pass_type first = functor_multi_pass_type(iterate_a2m());
- functor_multi_pass_type last;
- // use the iterators: this will print "ABCDEFGHIJKL"
- while (first != last) {
- std::cout << *first;
- ++first;
- }
- std::cout << std::endl;
- return 0;
- }
- [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]
|