implementation.html 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. <html>
  2. <head>
  3. <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
  4. <title>Annex: Implementation</title>
  5. <link rel="stylesheet" href="../../../../../doc/src/boostbook.css" type="text/css">
  6. <meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
  7. <link rel="home" href="../index.html" title="Chapter&#160;1.&#160;Boost.LocalFunction 1.0.0">
  8. <link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Boost.LocalFunction 1.0.0">
  9. <link rel="prev" href="no_variadic_macros.html" title="Annex: No Variadic Macros">
  10. <link rel="next" href="../reference.html" title="Reference">
  11. </head>
  12. <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
  13. <table cellpadding="2" width="100%"><tr>
  14. <td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../boost.png"></td>
  15. <td align="center"><a href="../../../../../index.html">Home</a></td>
  16. <td align="center"><a href="../../../../../libs/libraries.htm">Libraries</a></td>
  17. <td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
  18. <td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
  19. <td align="center"><a href="../../../../../more/index.htm">More</a></td>
  20. </tr></table>
  21. <hr>
  22. <div class="spirit-nav">
  23. <a accesskey="p" href="no_variadic_macros.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="../reference.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
  24. </div>
  25. <div class="section">
  26. <div class="titlepage"><div><div><h2 class="title" style="clear: both">
  27. <a name="boost_localfunction.implementation"></a><a class="link" href="implementation.html" title="Annex: Implementation">Annex: Implementation</a>
  28. </h2></div></div></div>
  29. <p>
  30. This section gives an overview of the key programming techniques used to implement
  31. this library.
  32. </p>
  33. <div class="note"><table border="0" summary="Note">
  34. <tr>
  35. <td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../doc/src/images/note.png"></td>
  36. <th align="left">Note</th>
  37. </tr>
  38. <tr><td align="left" valign="top"><p>
  39. The code listed here can be used by curious readers and library maintainers
  40. as a reference in trying to understand the library source code. There is
  41. absolutely no guarantee that the library implementation uses the exact code
  42. listed here.
  43. </p></td></tr>
  44. </table></div>
  45. <h4>
  46. <a name="boost_localfunction.implementation.h0"></a>
  47. <span class="phrase"><a name="boost_localfunction.implementation.local_classes_as_template_parameters"></a></span><a class="link" href="implementation.html#boost_localfunction.implementation.local_classes_as_template_parameters">Local
  48. Classes as Template Parameters</a>
  49. </h4>
  50. <p>
  51. This library uses a local class to implement the local function object. However,
  52. in <a href="http://www.open-std.org/JTC1/SC22/WG21/docs/standards" target="_top">C++03</a>
  53. local classes (and therefore the local function objects they implement) cannot
  54. be passed as template parameters (e.g., to the <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">for_each</span></code>
  55. algorithm), this is instead possible in <a href="http://www.open-std.org/JTC1/SC22/WG21/" target="_top">C++11</a>,
  56. MSVC, and some other compilers (see <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm" target="_top">[N2657]</a>
  57. and <a href="http://www.boost.org/libs/chrono" target="_top">Boost.Config</a>'s <code class="computeroutput"><span class="identifier">BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS</span></code>).
  58. To work around this limitation, this library investigated the following two
  59. "tricks" (both tricks can be extended to support function default
  60. parameters):
  61. </p>
  62. <div class="orderedlist"><ol class="orderedlist" type="1">
  63. <li class="listitem">
  64. The <span class="emphasis"><em>casting functor trick</em></span> uses a non-local functor
  65. that calls a static member function of the local class via a function pointer.
  66. The static member function then calls the correct local function body after
  67. type casting the object from a <code class="computeroutput"><span class="keyword">void</span><span class="special">*</span></code> pointer (local classes can always be used
  68. for type casting via <code class="computeroutput"><span class="keyword">static_cast</span></code>
  69. or similar).
  70. </li>
  71. <li class="listitem">
  72. The <span class="emphasis"><em>virtual functor trick</em></span> derives the local functor
  73. class from a non-local base class. The correct overridden implementation
  74. of the virtual <code class="computeroutput"><span class="keyword">operator</span><span class="special">()</span></code>
  75. is then called via dynamic binding.
  76. </li>
  77. </ol></div>
  78. <p>
  79. For example (see also <a href="../../../example/impl_tparam_tricks.cpp" target="_top"><code class="literal">impl_tparam_tricks.cpp</code></a>):
  80. </p>
  81. <p>
  82. </p>
  83. <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">detail</span><span class="special">/</span><span class="identifier">lightweight_test</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
  84. <span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">vector</span><span class="special">&gt;</span>
  85. <span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">algorithm</span><span class="special">&gt;</span>
  86. <span class="comment">// Casting functor trick.</span>
  87. <span class="keyword">struct</span> <span class="identifier">casting_func</span> <span class="special">{</span>
  88. <span class="keyword">explicit</span> <span class="identifier">casting_func</span><span class="special">(</span><span class="keyword">void</span><span class="special">*</span> <span class="identifier">obj</span><span class="special">,</span> <span class="keyword">void</span> <span class="special">(*</span><span class="identifier">call</span><span class="special">)(</span><span class="keyword">void</span><span class="special">*,</span> <span class="keyword">const</span> <span class="keyword">int</span><span class="special">&amp;))</span>
  89. <span class="special">:</span> <span class="identifier">obj_</span><span class="special">(</span><span class="identifier">obj</span><span class="special">),</span> <span class="identifier">call_</span><span class="special">(</span><span class="identifier">call</span><span class="special">)</span> <span class="special">{}</span>
  90. <span class="comment">// Unfortunately, function pointer call is not inlined.</span>
  91. <span class="keyword">inline</span> <span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()(</span><span class="keyword">const</span> <span class="keyword">int</span><span class="special">&amp;</span> <span class="identifier">num</span><span class="special">)</span> <span class="special">{</span> <span class="identifier">call_</span><span class="special">(</span><span class="identifier">obj_</span><span class="special">,</span> <span class="identifier">num</span><span class="special">);</span> <span class="special">}</span>
  92. <span class="keyword">private</span><span class="special">:</span>
  93. <span class="keyword">void</span><span class="special">*</span> <span class="identifier">obj_</span><span class="special">;</span>
  94. <span class="keyword">void</span> <span class="special">(*</span><span class="identifier">call_</span><span class="special">)(</span><span class="keyword">void</span><span class="special">*,</span> <span class="keyword">const</span> <span class="keyword">int</span><span class="special">&amp;);</span>
  95. <span class="special">};</span>
  96. <span class="comment">// Virtual functor trick.</span>
  97. <span class="keyword">struct</span> <span class="identifier">virtual_func</span> <span class="special">{</span>
  98. <span class="keyword">struct</span> <span class="identifier">interface</span> <span class="special">{</span>
  99. <span class="comment">// Unfortunately, virtual function call is not inlined.</span>
  100. <span class="keyword">inline</span> <span class="keyword">virtual</span> <span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()(</span><span class="keyword">const</span> <span class="keyword">int</span><span class="special">&amp;)</span> <span class="special">{}</span>
  101. <span class="special">};</span>
  102. <span class="keyword">explicit</span> <span class="identifier">virtual_func</span><span class="special">(</span><span class="identifier">interface</span><span class="special">&amp;</span> <span class="identifier">func</span><span class="special">):</span> <span class="identifier">func_</span><span class="special">(&amp;</span><span class="identifier">func</span><span class="special">)</span> <span class="special">{}</span>
  103. <span class="keyword">inline</span> <span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()(</span><span class="keyword">const</span> <span class="keyword">int</span><span class="special">&amp;</span> <span class="identifier">num</span><span class="special">)</span> <span class="special">{</span> <span class="special">(*</span><span class="identifier">func_</span><span class="special">)(</span><span class="identifier">num</span><span class="special">);</span> <span class="special">}</span>
  104. <span class="keyword">private</span><span class="special">:</span>
  105. <span class="identifier">interface</span><span class="special">*</span> <span class="identifier">func_</span><span class="special">;</span>
  106. <span class="special">};</span>
  107. <span class="keyword">int</span> <span class="identifier">main</span><span class="special">(</span><span class="keyword">void</span><span class="special">)</span> <span class="special">{</span>
  108. <span class="keyword">int</span> <span class="identifier">sum</span> <span class="special">=</span> <span class="number">0</span><span class="special">,</span> <span class="identifier">factor</span> <span class="special">=</span> <span class="number">10</span><span class="special">;</span>
  109. <span class="comment">// Local class for local function.</span>
  110. <span class="keyword">struct</span> <span class="identifier">local_add</span> <span class="special">:</span> <span class="identifier">virtual_func</span><span class="special">::</span><span class="identifier">interface</span> <span class="special">{</span>
  111. <span class="keyword">explicit</span> <span class="identifier">local_add</span><span class="special">(</span><span class="keyword">int</span><span class="special">&amp;</span> <span class="identifier">_sum</span><span class="special">,</span> <span class="keyword">const</span> <span class="keyword">int</span><span class="special">&amp;</span> <span class="identifier">_factor</span><span class="special">)</span>
  112. <span class="special">:</span> <span class="identifier">sum_</span><span class="special">(</span><span class="identifier">_sum</span><span class="special">),</span> <span class="identifier">factor_</span><span class="special">(</span><span class="identifier">_factor</span><span class="special">)</span> <span class="special">{}</span>
  113. <span class="keyword">inline</span> <span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()(</span><span class="keyword">const</span> <span class="keyword">int</span><span class="special">&amp;</span> <span class="identifier">num</span><span class="special">)</span> <span class="special">{</span>
  114. <span class="identifier">body</span><span class="special">(</span><span class="identifier">sum_</span><span class="special">,</span> <span class="identifier">factor_</span><span class="special">,</span> <span class="identifier">num</span><span class="special">);</span>
  115. <span class="special">}</span>
  116. <span class="keyword">inline</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="identifier">call</span><span class="special">(</span><span class="keyword">void</span><span class="special">*</span> <span class="identifier">obj</span><span class="special">,</span> <span class="keyword">const</span> <span class="keyword">int</span><span class="special">&amp;</span> <span class="identifier">num</span><span class="special">)</span> <span class="special">{</span>
  117. <span class="identifier">local_add</span><span class="special">*</span> <span class="identifier">self</span> <span class="special">=</span> <span class="keyword">static_cast</span><span class="special">&lt;</span><span class="identifier">local_add</span><span class="special">*&gt;(</span><span class="identifier">obj</span><span class="special">);</span>
  118. <span class="identifier">self</span><span class="special">-&gt;</span><span class="identifier">body</span><span class="special">(</span><span class="identifier">self</span><span class="special">-&gt;</span><span class="identifier">sum_</span><span class="special">,</span> <span class="identifier">self</span><span class="special">-&gt;</span><span class="identifier">factor_</span><span class="special">,</span> <span class="identifier">num</span><span class="special">);</span>
  119. <span class="special">}</span>
  120. <span class="keyword">private</span><span class="special">:</span>
  121. <span class="keyword">int</span><span class="special">&amp;</span> <span class="identifier">sum_</span><span class="special">;</span>
  122. <span class="keyword">const</span> <span class="keyword">int</span><span class="special">&amp;</span> <span class="identifier">factor_</span><span class="special">;</span>
  123. <span class="keyword">inline</span> <span class="keyword">void</span> <span class="identifier">body</span><span class="special">(</span><span class="keyword">int</span><span class="special">&amp;</span> <span class="identifier">sum</span><span class="special">,</span> <span class="keyword">const</span> <span class="keyword">int</span><span class="special">&amp;</span> <span class="identifier">factor</span><span class="special">,</span> <span class="keyword">const</span> <span class="keyword">int</span><span class="special">&amp;</span> <span class="identifier">num</span><span class="special">)</span> <span class="special">{</span>
  124. <span class="identifier">sum</span> <span class="special">+=</span> <span class="identifier">factor</span> <span class="special">*</span> <span class="identifier">num</span><span class="special">;</span>
  125. <span class="special">}</span>
  126. <span class="special">}</span> <span class="identifier">add_local</span><span class="special">(</span><span class="identifier">sum</span><span class="special">,</span> <span class="identifier">factor</span><span class="special">);</span>
  127. <span class="identifier">casting_func</span> <span class="identifier">add_casting</span><span class="special">(&amp;</span><span class="identifier">add_local</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">local_add</span><span class="special">::</span><span class="identifier">call</span><span class="special">);</span>
  128. <span class="identifier">virtual_func</span> <span class="identifier">add_virtual</span><span class="special">(</span><span class="identifier">add_local</span><span class="special">);</span>
  129. <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span> <span class="identifier">v</span><span class="special">(</span><span class="number">10</span><span class="special">);</span>
  130. <span class="identifier">std</span><span class="special">::</span><span class="identifier">fill</span><span class="special">(</span><span class="identifier">v</span><span class="special">.</span><span class="identifier">begin</span><span class="special">(),</span> <span class="identifier">v</span><span class="special">.</span><span class="identifier">end</span><span class="special">(),</span> <span class="number">1</span><span class="special">);</span>
  131. <span class="comment">// std::for_each(v.begin(), v.end(), add_local); // Error but OK on C++11.</span>
  132. <span class="identifier">std</span><span class="special">::</span><span class="identifier">for_each</span><span class="special">(</span><span class="identifier">v</span><span class="special">.</span><span class="identifier">begin</span><span class="special">(),</span> <span class="identifier">v</span><span class="special">.</span><span class="identifier">end</span><span class="special">(),</span> <span class="identifier">add_casting</span><span class="special">);</span> <span class="comment">// OK.</span>
  133. <span class="identifier">std</span><span class="special">::</span><span class="identifier">for_each</span><span class="special">(</span><span class="identifier">v</span><span class="special">.</span><span class="identifier">begin</span><span class="special">(),</span> <span class="identifier">v</span><span class="special">.</span><span class="identifier">end</span><span class="special">(),</span> <span class="identifier">add_virtual</span><span class="special">);</span> <span class="comment">// OK.</span>
  134. <span class="identifier">BOOST_TEST</span><span class="special">(</span><span class="identifier">sum</span> <span class="special">==</span> <span class="number">200</span><span class="special">);</span>
  135. <span class="keyword">return</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">report_errors</span><span class="special">();</span>
  136. <span class="special">}</span>
  137. </pre>
  138. <p>
  139. </p>
  140. <p>
  141. The casting functor trick measured slightly better run-time performances than
  142. the virtual functor trick so the current implementation of this library uses
  143. the casting functor trick (probably because in addition to the indirect function
  144. call, the virtual functor trick also requires accessing the <a href="http://en.wikipedia.org/wiki/Virtual_method_table" target="_top">virtual
  145. function table</a>). However, neither one of the two tricks was observed
  146. to allow for compiler optimizations that inline the local function calls (because
  147. they rely on one indirect function call via either a function pointer or a
  148. virtual function respectively). Therefore, on compilers that accept local classes
  149. as template parameters (MSVC, <a href="http://www.open-std.org/JTC1/SC22/WG21/" target="_top">C++11</a>,
  150. etc, see <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm" target="_top">[N2657]</a>
  151. and <a href="http://www.boost.org/libs/chrono" target="_top">Boost.Config</a>'s <code class="computeroutput"><span class="identifier">BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS</span></code>),
  152. this library automatically generates code that passes the local class type
  153. directly as template parameter without using neither one of these two tricks
  154. in order to take full advantage of compiler optimizations that inline the local
  155. function calls.
  156. </p>
  157. <h4>
  158. <a name="boost_localfunction.implementation.h1"></a>
  159. <span class="phrase"><a name="boost_localfunction.implementation.parsing_macros"></a></span><a class="link" href="implementation.html#boost_localfunction.implementation.parsing_macros">Parsing
  160. Macros</a>
  161. </h4>
  162. <p>
  163. This library macros can parse the list of specified parameters and detect if
  164. any of the bound variable names matches the token <code class="computeroutput"><span class="identifier">this_</span></code>
  165. (to generate special code to bind the object in scope), or if the variable
  166. is bound by <code class="computeroutput"><span class="keyword">const</span></code> (to generate
  167. special code to bind by constant), etc. The parameter tokens are inspected
  168. using preprocessor meta-programming and specifically using the macros defined
  169. by the files in the <code class="literal">boost/local_function/detail/preprocessor/keyword/</code>
  170. directory. <a href="#ftn.boost_localfunction.implementation.f0" class="footnote" name="boost_localfunction.implementation.f0"><sup class="footnote">[31]</sup></a>
  171. </p>
  172. <p>
  173. For example, the following code defines a macro that allows the preprocessor
  174. to detect if a set of space-separated tokens ends with <code class="computeroutput"><span class="identifier">this_</span></code>
  175. or not (see also <a href="../../../example/impl_pp_keyword.cpp" target="_top"><code class="literal">impl_pp_keyword.cpp</code></a>):
  176. </p>
  177. <p>
  178. </p>
  179. <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">local_function</span><span class="special">/</span><span class="identifier">detail</span><span class="special">/</span><span class="identifier">preprocessor</span><span class="special">/</span><span class="identifier">keyword</span><span class="special">/</span><span class="identifier">thisunderscore</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
  180. <span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">local_function</span><span class="special">/</span><span class="identifier">detail</span><span class="special">/</span><span class="identifier">preprocessor</span><span class="special">/</span><span class="identifier">keyword</span><span class="special">/</span><span class="keyword">const</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
  181. <span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">local_function</span><span class="special">/</span><span class="identifier">detail</span><span class="special">/</span><span class="identifier">preprocessor</span><span class="special">/</span><span class="identifier">keyword</span><span class="special">/</span><span class="identifier">bind</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
  182. <span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">detail</span><span class="special">/</span><span class="identifier">lightweight_test</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
  183. <span class="comment">// Expand to 1 if space-separated tokens end with `this_`, 0 otherwise.</span>
  184. <span class="preprocessor">#define</span> <span class="identifier">IS_THIS_BACK</span><span class="special">(</span><span class="identifier">tokens</span><span class="special">)</span> <span class="special">\</span>
  185. <span class="identifier">BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_IS_THISUNDERSCORE_BACK</span><span class="special">(</span> <span class="special">\</span>
  186. <span class="identifier">BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_BIND_REMOVE_FRONT</span><span class="special">(</span> <span class="special">\</span>
  187. <span class="identifier">BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_CONST_REMOVE_FRONT</span><span class="special">(</span> <span class="special">\</span>
  188. <span class="identifier">tokens</span> <span class="special">\</span>
  189. <span class="special">)))</span>
  190. <span class="keyword">int</span> <span class="identifier">main</span><span class="special">(</span><span class="keyword">void</span><span class="special">)</span> <span class="special">{</span>
  191. <span class="identifier">BOOST_TEST</span><span class="special">(</span><span class="identifier">IS_THIS_BACK</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">bind</span> <span class="identifier">this_</span><span class="special">)</span> <span class="special">==</span> <span class="number">1</span><span class="special">);</span>
  192. <span class="identifier">BOOST_TEST</span><span class="special">(</span><span class="identifier">IS_THIS_BACK</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">bind</span><span class="special">&amp;</span> <span class="identifier">x</span><span class="special">)</span> <span class="special">==</span> <span class="number">0</span><span class="special">);</span>
  193. <span class="keyword">return</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">report_errors</span><span class="special">();</span>
  194. <span class="special">}</span>
  195. </pre>
  196. <p>
  197. </p>
  198. <div class="footnotes">
  199. <br><hr style="width:100; text-align:left;margin-left: 0">
  200. <div id="ftn.boost_localfunction.implementation.f0" class="footnote"><p><a href="#boost_localfunction.implementation.f0" class="para"><sup class="para">[31] </sup></a>
  201. This technique is at the core of even more complex preprocessor parsing macros
  202. like the ones that parse the <a href="http://sourceforge.net/projects/contractpp" target="_top">Contract++</a>
  203. syntax.
  204. </p></div>
  205. </div>
  206. </div>
  207. <table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
  208. <td align="left"></td>
  209. <td align="right"><div class="copyright-footer">Copyright &#169; 2009-2012 Lorenzo
  210. Caminiti<p>
  211. Distributed under the Boost Software License, Version 1.0 (see accompanying
  212. file LICENSE_1_0.txt or a copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
  213. </p>
  214. </div></td>
  215. </tr></table>
  216. <hr>
  217. <div class="spirit-nav">
  218. <a accesskey="p" href="no_variadic_macros.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="../reference.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
  219. </div>
  220. </body>
  221. </html>