| <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><title>The multi_pass</title> |
| |
| <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
| <link rel="stylesheet" href="theme/style.css" type="text/css"></head> |
| <body> |
| <table width="100%" border="0" background="theme/bkd2.gif" cellspacing="2"> |
| <tbody><tr> |
| <td width="10"> |
| <br> |
| </td> |
| <td width="85%"> <font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>The |
| multi_pass</b></font> </td> |
| <td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" width="112" height="48" align="right" border="0"></a></td> |
| </tr> |
| </tbody></table> |
| <br> |
| <table border="0"> |
| <tbody><tr> |
| <td width="10"><br> |
| </td> |
| <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> |
| <td width="30"><a href="trees.html"><img src="theme/l_arr.gif" border="0"></a></td> |
| <td width="30"><a href="file_iterator.html"><img src="theme/r_arr.gif" border="0"></a></td> |
| </tr> |
| </tbody></table> |
| <p>Backtracking in Spirit 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 istreambuf_iterator |
| and 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.</p> |
| <table width="80%" border="0" align="center"> |
| <tbody><tr> |
| <td class="note_box"> <img src="theme/note.gif" width="16" height="16"> <b>Input |
| Iterators</b> <br> |
| <br> |
| In general, Spirit is a backtracking parser. 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 istream_iterator as is. </td> |
| </tr> |
| </tbody></table> |
| <p> Unfortunately, with an input iterator, there is no way to save an iterator |
| position, and thus input iterators will not work with backtracking in Spirit. |
| 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 Spirit. This method can be too memory intensive for certain applications, |
| which is why the multi_pass iterator was created.</p> |
| <p> The multi_pass iterator will convert any input iterator into a forward iterator |
| suitable for use with Spirit. multi_pass will buffer data when needed and will |
| discard the buffer when only one copy of the iterator exists.</p> |
| <p> 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 sequence and repetition. Sequences of the form <tt>a >> b</tt> |
| will not buffer data at all. Any rule that repeats, such as kleene_star (<tt>*a</tt>) |
| or positive such as (<tt>+a</tt>), will only buffer the data for the current |
| repetition.</p> |
| <p> 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 <tt>*(a | b | c | d)</tt>. The input iterator |
| moves on and is never stuck at the beginning. Let's look at a Pascal snippet |
| for example:</p> |
| <pre> <code><span class="identifier">program </span><span class="special">=<br> </span><span class="identifier"> programHeading </span><span class="special">>> </span><span class="identifier">block </span><span class="special">>> </span><span class="literal">'.'<br> </span><span class="special"> ;<br><br> </span><span class="identifier">block </span><span class="special">=<br> *( </span><span class="identifier">labelDeclarationPart<br> </span><span class="special">| </span><span class="identifier">constantDefinitionPart<br> </span><span class="special">| </span><span class="identifier">typeDefinitionPart<br> </span><span class="special"> | </span><span class="identifier">variableDeclarationPart<br> </span><span class="special">| </span><span class="identifier"> procedureAndFunctionDeclarationPart<br> </span><span class="special"> )<br> >> </span><span class="identifier">statementPart<br> </span><span class="special">;<br></span></code></pre> |
| <p> 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.</p> |
| <p>Be mindful if you use the free parse functions. |
| All of these make a copy of the iterator passed to them.<br> |
| </p> |
| <p>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 flush_multi_pass in your grammar to ensure that data is not buffered when unnecessary.<br> |
| </p> |
| |
| <p> Again, following up the example we started to use in the section on the scanner |
| . Here's an example using the multi_pass: This time around we are extracting |
| our input from the input stream using an istreambuf_iterator.</p> |
| <pre> <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">spirit</span><span class="special">/</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <code><span class="preprocessor"> #include </span><span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">spirit</span><span class="special">/</span><span class="identifier">iterator</span><span class="special">/</span><span class="identifier">multi_pass</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span><span class="comment"> |
| |
| </span><span class="keyword">using namespace</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">spirit</span><span class="special">; |
| </span><span class="keyword">using namespace</span> <span class="identifier">std</span><span class="special">;</span> |
| |
| <span class="identifier">ifstream in</span><span class="special">(</span><span class="string">"input_file.txt"</span><span class="special">); </span><span class="comment">// we get our input from this file<br><br> </span><span class="keyword">typedef char </span><span class="identifier">char_type</span><span class="special">;</span> |
| <span class="keyword">typedef </span><span class="identifier">multi_pass</span><span class="special"><</span><span class="identifier">istreambuf_iterator</span><span class="special"><</span><span class="identifier">char_type</span><span class="special">> > </span><span class="identifier">iterator_type</span><span class="special">;</span> |
| |
| <span class="keyword">typedef</span> <span class="identifier">skip_parser_iteration_policy</span><span class="special"><</span><span class="identifier">space_parser</span><span class="special">></span> <span class="identifier">iter_policy_type</span><span class="special">;</span> |
| <span class="keyword">typedef</span> <span class="identifier">scanner_policies</span><span class="special"><</span>iter_policy_type<span class="special">></span> <span class="identifier">scanner_policies_type</span><span class="special">;</span> |
| <span class="keyword">typedef</span> <span class="identifier">scanner</span><span class="special"><</span>iterator_type, scanner_policies_type<span class="special">></span> <span class="identifier">scanner_type</span><span class="special">;</span> |
| |
| <span class="keyword">typedef</span> rule<span class="special"><</span>scanner_type<span class="special">></span> <span class="identifier">rule_type</span><span class="special">;</span> |
| |
| <span class="identifier">iter_policy_type</span> <span class="identifier">iter_policy</span><span class="special">(</span><span class="identifier">space_p</span><span class="special">);</span> |
| <span class="identifier">scanner_policies_type</span> <span class="identifier">policies</span><span class="special">(</span><span class="identifier">iter_policy</span><span class="special">);</span> |
| iterator_type first( |
| make_multi_pass(std::istreambuf_iterator<char_type>(in))); |
| |
| scanner_type <span class="identifier">scan</span><span class="special">(</span> |
| first<span class="special">,</span> make_multi_pass(std::istreambuf_iterator<span class="special"><</span><span class="identifier">char_type</span><span class="special">>()),</span> |
| <span class="identifier">policies</span><span class="special">)</span>; |
| <span class="special"><br> </span><span class="identifier">rule_type n_list </span><span class="special">= </span><span class="identifier">real_p </span><span class="special">>> *(</span><span class="literal">',' </span><span class="special">>> </span><span class="identifier">real_p</span><span class="special">);<br> </span><span class="identifier">match</span><span class="special"><></span><span class="identifier"> m </span><span class="special">= </span><span class="identifier">n_list</span><span class="special">.</span><span class="identifier">parse</span><span class="special">(</span><span class="identifier">scan</span><span class="special">);<br></span></code></pre> |
| <a name="flush_multi_pass"></a> |
| <h2>flush_multi_pass</h2> |
| <p> There is a predefined pseudo-parser called flush_multi_pass. When this 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.</p> |
| <a name="multi_pass_policies"></a> |
| <h2>multi_pass Policies</h2> |
| <p> multi_pass is a templated policy driven class. 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.</p> |
| <p> The multi_pass class has five template parameters:</p> |
| <ul> |
| <li>InputT - The type multi_pass uses to acquire it's input. This is typically |
| an input iterator, or functor.</li> |
| <li>InputPolicy - A class that defines how multi_pass acquires it's input. The |
| InputPolicy is parameterized by InputT.</li> |
| <li>OwnershipPolicy - This policy determines how multi_pass deals with it's |
| shared components.</li> |
| <li>CheckingPolicy - This policy determines how checking for invalid iterators |
| is done.</li> |
| <li>StoragePolicy - The buffering scheme used by multi_pass is determined and |
| managed by the StoragePolicy.</li> |
| </ul> |
| <a name="predefined_policies"></a> |
| <h2>Predefined policies</h2> |
| <p> All predefined multi_pass policies are in the namespace boost::spirit::multi_pass_policies.</p> |
| <a name="predefined_inputpolicy_classes"></a> |
| <h3>Predefined InputPolicy classes</h3> |
| <a name="input_iterator"></a> |
| <h4>input_iterator</h4> |
| <p> This policy directs multi_pass to read from an input iterator of type InputT.</p> |
| <a name="lex_input"></a> |
| <h4>lex_input</h4> |
| <p> This policy obtains it's input by calling yylex(), which would typically be |
| provided by a scanner generated by LEX. If you use this policy your code must |
| link against a LEX generated scanner.</p> |
| <a name="functor_input"></a> |
| <h4>functor_input</h4> |
| <p> This input policy obtains it's data by calling a functor of type InputT. 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.</p> |
| <a name="predefined_ownershippolicy_classes"></a> |
| <h3>Predefined OwnershipPolicy classes</h3> |
| <a name="ref_counted"></a> |
| <h4>ref_counted</h4> |
| <p> This class uses a reference counting scheme. multi_pass will delete it's shared |
| components when the count reaches zero.</p> |
| <a name="first_owner"></a> |
| <h4>first_owner</h4> |
| <p> 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.</p> |
| <a name="predefined_checkingpolicy_classes"></a> |
| <h3>Predefined CheckingPolicy classes</h3> |
| <a name="no_check"></a> |
| <h4>no_check</h4> |
| <p> This policy does no checking at all.</p> |
| <a name="buf_id_check"></a> |
| <h4>buf_id_check</h4> |
| <p> buf_id_check 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 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.</p> |
| <a name="full_check"></a> |
| <h4>full_check</h4> |
| <p> 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.</p> |
| <a name="predefined_storagepolicy_classes"></a> |
| <h3>Predefined StoragePolicy classes</h3> |
| <a name="std_deque"></a> |
| <h4>std_deque</h4> |
| <p> This policy keeps all buffered data in a std::deque. 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().</p> |
| <a name="fixed_size_queue_lt_n_gt_"></a> |
| <h4>fixed_size_queue<N></h4> |
| <p> fixed_size_queue 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 std_deque, |
| which is unbounded.</p> |
| <a name="combinations__how_to_specify_your_own_custom_multi_pass"></a> |
| <h2>Combinations: How to specify your own custom multi_pass</h2> |
| <p> The beauty of policy based designs is that you can mix and match policies |
| to create your own custom class by selecting the policies you want. Here's an |
| example of how to specify a custom multi_pass that wraps an istream_iterator<char>, |
| and is slightly more efficient than the default because it uses the first_owner |
| OwnershipPolicy and the no_check CheckingPolicy:</p> |
| <pre> <code><span class="keyword">typedef </span><span class="identifier">multi_pass</span><span class="special"><<br> </span><span class="identifier">istream_iterator</span><span class="special"><</span><span class="keyword">char</span><span class="special">>,<br> </span><span class="identifier">multi_pass_policies</span><span class="special">::</span><span class="identifier">input_iterator</span><span class="special">,<br> </span><span class="identifier">multi_pass_policies</span><span class="special">::</span><span class="identifier">first_owner</span><span class="special">,<br> </span><span class="identifier">multi_pass_policies</span><span class="special">::</span><span class="identifier">no_check</span><span class="special">,<br> </span><span class="identifier">multi_pass_policies</span><span class="special">::</span><span class="identifier">std_deque<br> </span><span class="special">> </span><span class="identifier">first_owner_multi_pass_type</span><span class="special">;<br></span></code></pre> |
| <p> The default template parameters for multi_pass are: input_iterator InputPolicy, |
| ref_counted OwnershipPolicy, buf_id_check CheckingPolicy and std_deque StoragePolicy. |
| So if you use multi_pass<istream_iterator<char> > you will get those |
| pre-defined behaviors while wrapping an istream_iterator<char>.</p> |
| <p> There is one other pre-defined class called look_ahead. look_ahead has two |
| template parameters: InputT, 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 safey, 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.</p> |
| <a name="how_to_write_a_functor_for_use_with_the_functor_input_inputpolicy"></a> |
| <h3>How to write a functor for use with the functor_input InputPolicy</h3> |
| <p> If you want to use the functor_input InputPolicy, you can write your own functor |
| that will supply the input to multi_pass. The functor must satisfy two requirements. |
| It must have a typedef result_type which specifies the return type of 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. Here is an example:</p> |
| <pre> <code><span class="keyword">class </span><span class="identifier">my_functor<br> </span><span class="special">{<br> </span><span class="keyword">public</span><span class="special">:<br><br> </span><span class="keyword">typedef char </span><span class="identifier">result_type</span><span class="special">;<br><br> </span><span class="identifier">my_functor</span><span class="special">()<br> : </span><span class="identifier">c</span><span class="special">(</span><span class="literal">'A'</span><span class="special">) {}<br><br> </span><span class="keyword">char operator</span><span class="special">()() </span><span class="keyword">const<br> </span><span class="special">{<br> </span><span class="keyword">if </span><span class="special">(</span><span class="identifier">c </span><span class="special">== </span><span class="literal">'M'</span><span class="special">)<br> </span><span class="keyword">return </span><span class="identifier">eof</span><span class="special">;<br> </span><span class="keyword">else<br> return </span><span class="identifier">c</span><span class="special">++;<br> }<br><br> </span><span class="keyword">static </span><span class="identifier">result_type eof</span><span class="special">;<br><br> </span><span class="keyword">private</span><span class="special">:<br><br> </span><span class="keyword">char </span><span class="identifier">c</span><span class="special">;<br> };<br><br> </span><span class="identifier">my_functor</span><span class="special">::</span><span class="identifier">result_type my_functor</span><span class="special">::</span><span class="identifier">eof </span><span class="special">= </span><span class="literal">'\0'</span><span class="special">;<br><br> </span><span class="keyword">typedef </span><span class="identifier">multi_pass</span><span class="special"><<br> </span><span class="identifier">my_functor</span><span class="special">,<br> </span><span class="identifier">multi_pass_policies</span><span class="special">::</span><span class="identifier">functor_input</span><span class="special">,<br> </span><span class="identifier">multi_pass_policies</span><span class="special">::</span><span class="identifier">first_owner</span><span class="special">,<br> </span><span class="identifier">multi_pass_policies</span><span class="special">::</span><span class="identifier">no_check</span><span class="special">,<br> </span><span class="identifier">multi_pass_policies</span><span class="special">::</span><span class="identifier">std_deque<br> </span><span class="special">> </span><span class="identifier">functor_multi_pass_type</span><span class="special">;<br><br> </span><span class="identifier">functor_multi_pass_type first </span><span class="special">= </span><span class="identifier">functor_multi_pass_type</span><span class="special">(</span><span class="identifier">my_functor</span><span class="special">());<br> </span><span class="identifier">functor_multi_pass_type last</span><span class="special">;<br></span></code></pre> |
| <a name="how_to_write_policies_for_use_with_multi_pass"></a> |
| <h3>How to write policies for use with multi_pass</h3> |
| <a name="inputpolicy"></a> |
| <h4>InputPolicy</h4> |
| <p> An InputPolicy must have the following interface:</p> |
| <pre> <code><span class="keyword">class </span><span class="identifier">my_input_policy </span><span class="comment">// your policy name<br> </span><span class="special">{<br> </span><span class="keyword">public</span><span class="special">:<br><br> </span><span class="comment">// class inner will be instantiated with the type given<br> // as the InputT parameter to multi_pass.<br><br> </span><span class="keyword">template </span><span class="special"><</span><span class="keyword">typename </span><span class="identifier">InputT</span><span class="special">><br> </span><span class="keyword">class </span><span class="identifier">inner<br> </span><span class="special">{<br> </span><span class="keyword">public</span><span class="special">:<br><br> </span><span class="comment">// these typedefs determine the iterator_traits for multi_pass<br> </span><span class="keyword">typedef </span><span class="identifier">x </span><span class="identifier">value_type</span><span class="special">;<br> </span><span class="keyword">typedef </span><span class="identifier">x </span><span class="identifier">difference_type</span><span class="special">;<br> </span><span class="keyword">typedef </span><span class="identifier">x </span><span class="identifier">pointer</span><span class="special">;<br> </span><span class="keyword">typedef </span><span class="identifier">x </span><span class="identifier">reference</span><span class="special">;<br><br> </span><span class="keyword">protected</span><span class="special">:<br><br> </span><span class="identifier">inner</span><span class="special">();<br> </span><span class="identifier">inner</span><span class="special">(</span><span class="identifier">InputT </span><span class="identifier">x</span><span class="special">);<br> </span><span class="identifier">inner</span><span class="special">(</span><span class="identifier">inner </span><span class="keyword">const</span><span class="special">& </span><span class="identifier">x</span><span class="special">);<br> </span><span class="comment">// delete or clean up any state<br> </span><span class="keyword">void </span><span class="identifier">destroy</span><span class="special">();<br> </span><span class="comment">// return true if *this and x have the same input<br> </span><span class="keyword">bool </span><span class="identifier">same_input</span><span class="special">(</span><span class="identifier">inner </span><span class="keyword">const</span><span class="special">& </span><span class="identifier">x</span><span class="special">) </span><span class="keyword">const</span><span class="special">;<br> </span><span class="keyword">void </span><span class="identifier">swap</span><span class="special">(</span><span class="identifier">inner</span><span class="special">& </span><span class="identifier">x</span><span class="special">);<br><br> </span><span class="keyword">public</span><span class="special">:<br><br> </span><span class="comment">// get an instance from the input<br> </span><span class="identifier">result_type </span><span class="identifier">get_input</span><span class="special">() </span><span class="keyword">const</span><span class="special">;<br> </span><span class="comment">// advance the input<br> </span><span class="keyword">void </span><span class="identifier">advance_input</span><span class="special">();<br> </span><span class="comment">// return true if the input is at the end<br> </span><span class="keyword">bool </span><span class="identifier">input_at_eof</span><span class="special">() </span><span class="keyword">const</span><span class="special">;<br> </span><span class="special">};<br> </span><span class="special">};<br></span></code></pre> |
| <p> Because of the way that multi_pass shares a buffer and input among multiple |
| copies, class inner should keep a pointer to it's input. The copy constructor |
| should simply copy the pointer. destroy() should delete it. same_input should |
| compare the pointers. For more details see the various implementations of InputPolicy |
| classes.</p> |
| <a name="ownershippolicy"></a> |
| <h4>OwnershipPolicy</h4> |
| <p> The OwnershipPolicy must have the following interface:</p> |
| <pre> <code><span class="keyword">class </span><span class="identifier">my_ownership_policy<br> </span><span class="special">{<br> </span><span class="keyword">protected</span><span class="special">:<br><br> </span><span class="identifier">my_ownership_policy</span><span class="special">();<br> </span><span class="identifier">my_ownership_policy</span><span class="special">(</span><span class="identifier">my_ownership_policy </span><span class="keyword">const</span><span class="special">& </span><span class="identifier">x</span><span class="special">);<br> </span><span class="comment">// clone is called when a copy of the iterator is made<br> </span><span class="keyword">void </span><span class="identifier">clone</span><span class="special">();<br> </span><span class="comment">// called when a copy is deleted. Return true to indicate<br> // resources should be released<br> </span><span class="keyword">bool </span><span class="identifier">release</span><span class="special">();<br> </span><span class="keyword">void </span><span class="identifier">swap</span><span class="special">(</span><span class="identifier">my_ownership_policy</span><span class="special">& </span><span class="identifier">x</span><span class="special">);<br><br> </span><span class="keyword">public</span><span class="special">:<br> </span><span class="comment">// returns true if there is only one iterator in existence.<br> // std_dequeue StoragePolicy will free it's buffered data if this<br> // returns true.<br> </span><span class="keyword">bool </span><span class="identifier">unique</span><span class="special">() </span><span class="keyword">const</span><span class="special">;<br> </span><span class="special">};<br></span></code></pre> |
| <a name="checkingpolicy"></a> |
| <h4>CheckingPolicy</h4> |
| <p> The CheckingPolicy must have the following interface:</p> |
| <pre> <code><span class="keyword">class </span><span class="identifier">my_check<br> </span><span class="special">{<br> </span><span class="keyword">protected</span><span class="special">:<br><br> </span><span class="identifier">my_check</span><span class="special">();<br> </span><span class="identifier">my_check</span><span class="special">(</span><span class="identifier">my_check </span><span class="keyword">const</span><span class="special">& </span><span class="identifier">x</span><span class="special">);<br> </span><span class="keyword">void </span><span class="identifier">destroy</span><span class="special">();<br> </span><span class="keyword">void </span><span class="identifier">swap</span><span class="special">(</span><span class="identifier">my_check</span><span class="special">& </span><span class="identifier">x</span><span class="special">);<br> </span><span class="comment">// check should make sure that this iterator is valid<br> </span><span class="keyword">void </span><span class="identifier">check</span><span class="special">() </span><span class="keyword">const</span><span class="special">;<br> </span><span class="keyword">void </span><span class="identifier">clear_queue</span><span class="special">();<br> </span><span class="special">};<br></span></code></pre> |
| <a name="storagepolicy"></a> |
| <h4>StoragePolicy</h4> |
| <p> A StoragePolicy must have the following interface:</p> |
| <pre> <code><span class="keyword">class </span><span class="identifier">my_storage_policy<br> </span><span class="special">{<br> </span><span class="keyword">public</span><span class="special">:<br><br> </span><span class="comment">// class inner will be instantiated with the value_type from the InputPolicy<br><br> </span><span class="keyword">template </span><span class="special"><</span><span class="keyword">typename </span><span class="identifier">ValueT</span><span class="special">><br> </span><span class="keyword">class </span><span class="identifier">inner<br> </span><span class="special">{<br> </span><span class="keyword">protected</span><span class="special">:<br><br> </span><span class="identifier">inner</span><span class="special">();<br> </span><span class="identifier">inner</span><span class="special">(</span><span class="identifier">inner </span><span class="keyword">const</span><span class="special">& </span><span class="identifier">x</span><span class="special">);<br> </span><span class="comment">// will be called from the destructor of the last iterator.<br> </span><span class="keyword">void </span><span class="identifier">destroy</span><span class="special">();<br> </span><span class="keyword">void </span><span class="identifier">swap</span><span class="special">(</span><span class="identifier">inner</span><span class="special">& </span><span class="identifier">x</span><span class="special">);<br> </span><span class="comment">// This is called when the iterator is dereferenced. It's a template<br> // method so we can recover the type of the multi_pass iterator<br> // and access it.<br> </span><span class="keyword">template </span><span class="special"><</span><span class="keyword">typename </span><span class="identifier">MultiPassT</span><span class="special">><br> </span><span class="keyword">static </span><span class="identifier">ValueT </span><span class="identifier">dereference</span><span class="special">(</span><span class="identifier">MultiPassT </span><span class="keyword">const</span><span class="special">& </span><span class="identifier">mp</span><span class="special">);<br> </span><span class="comment">// This is called when the iterator is incremented. It's a template<br> // method so we can recover the type of the multi_pass iterator<br> // and access it.<br> </span><span class="keyword">template </span><span class="special"><</span><span class="keyword">typename </span><span class="identifier">MultiPassT</span><span class="special">><br> </span><span class="keyword">static </span><span class="keyword">void </span><span class="identifier">increment</span><span class="special">(</span><span class="identifier">MultiPassT</span><span class="special">& </span><span class="identifier">mp</span><span class="special">);<br> </span><span class="keyword">void </span><span class="identifier">clear_queue</span><span class="special">();<br> </span><span class="comment">// called to determine whether the iterator is an eof iterator<br> </span><span class="keyword">template </span><span class="special"><</span><span class="keyword">typename </span><span class="identifier">MultiPassT</span><span class="special">><br> </span><span class="keyword">static </span><span class="keyword">bool </span><span class="identifier">is_eof</span><span class="special">(</span><span class="identifier">MultiPassT </span><span class="keyword">const</span><span class="special">& </span><span class="identifier">mp</span><span class="special">);<br> </span><span class="comment">// called by operator==<br> </span><span class="keyword">bool </span><span class="identifier">equal_to</span><span class="special">(</span><span class="identifier">inner </span><span class="keyword">const</span><span class="special">& </span><span class="identifier">x</span><span class="special">) </span><span class="keyword">const</span><span class="special">;<br> </span><span class="comment">// called by operator<<br> </span><span class="keyword">bool </span><span class="identifier">less_than</span><span class="special">(</span><span class="identifier">inner </span><span class="keyword">const</span><span class="special">& </span><span class="identifier">x</span><span class="special">) </span><span class="keyword">const</span><span class="special">;<br> </span><span class="special">}; </span><span class="comment"> // class inner<br> </span><span class="special">};<br></span></code></pre> |
| <p> A StoragePolicy is the trickiest policy to write. You should study and understand |
| the existing StoragePolicy classes before you try and write your own.</p> |
| <table border="0"> |
| <tbody><tr> |
| <td width="10"><br> |
| </td> |
| <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> |
| <td width="30"><a href="trees.html"><img src="theme/l_arr.gif" border="0"></a></td> |
| <td width="30"><a href="file_iterator.html"><img src="theme/r_arr.gif" border="0"></a></td> |
| </tr> |
| </tbody></table> |
| <br> |
| <hr size="1"> |
| <p class="copyright">Copyright © 2001-2002 Daniel C. Nuffer<br> |
| <br> |
| <font size="2">Use, modification and distribution is subject to 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) </font> </p> |
| <p class="copyright"> </p> |
| <br> |
| </body></html> |