key_value.html 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0.1 Transitional//EN">
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
  5. <title>Boost.Flyweight Documentation - Tutorial - Key-value flyweights</title>
  6. <link rel="stylesheet" href="../style.css" type="text/css">
  7. <link rel="start" href="../index.html">
  8. <link rel="prev" href="basics.html">
  9. <link rel="up" href="index.html">
  10. <link rel="next" href="configuration.html">
  11. </head>
  12. <body>
  13. <h1><img src="../../../../boost.png" alt="Boost logo" align=
  14. "middle" width="277" height="86">Boost.Flyweight Tutorial: Key-value flyweights</h1>
  15. <div class="prev_link"><a href="basics.html"><img src="../prev.gif" alt="basics" border="0"><br>
  16. Basics
  17. </a></div>
  18. <div class="up_link"><a href="index.html"><img src="../up.gif" alt="Boost.Flyweight tutorial" border="0"><br>
  19. Boost.Flyweight tutorial
  20. </a></div>
  21. <div class="next_link"><a href="configuration.html"><img src="../next.gif" alt="configuring Boost.Flyweight" border="0"><br>
  22. Configuring Boost.Flyweight
  23. </a></div><br clear="all" style="clear: all;">
  24. <hr>
  25. <h2>Contents</h2>
  26. <ul>
  27. <li><a href="#key_value">Key-value flyweights</a>
  28. <ul>
  29. <li><a href="#key_extractor">Key extractors</a></li>
  30. <li><a href="#requirements">Type requirements</a></li>
  31. </ul>
  32. </li>
  33. </ul>
  34. <h2><a name="key_value">Key-value flyweights</a></h2>
  35. <p>
  36. Continuing with our online game example, suppose we have a huge class for
  37. handling rendering textures:
  38. </p>
  39. <blockquote><pre>
  40. <span class=keyword>class</span> <span class=identifier>texture</span>
  41. <span class=special>{</span>
  42. <span class=keyword>public</span><span class=special>:</span>
  43. <span class=identifier>texture</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>&amp;</span> <span class=identifier>filename</span><span class=special>){/*</span> <span class=identifier>loads</span> <span class=identifier>texture</span> <span class=identifier>file</span> <span class=special>*/}</span>
  44. <span class=keyword>const</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>&amp;</span> <span class=identifier>get_filename</span><span class=special>()</span><span class=keyword>const</span><span class=special>;</span>
  45. <span class=comment>// rest of the interface</span>
  46. <span class=special>};</span>
  47. </pre></blockquote>
  48. <p>
  49. and we decide to use <code>flyweight&lt;texture&gt;</code> to ease the
  50. manipulation of these objects. Now consider this seemingly innocent
  51. expression:
  52. </p>
  53. <blockquote><pre>
  54. <span class=identifier>flyweight</span><span class=special>&lt;</span><span class=identifier>texture</span><span class=special>&gt;</span> <span class=identifier>fw</span><span class=special>(</span><span class=string>&quot;grass.texture&quot;</span><span class=special>);</span>
  55. </pre></blockquote>
  56. <p>
  57. Note that in order to construct <code>fw</code> we are implicitly
  58. constructing a full grass texture object. The expression is mostly
  59. equivalent to
  60. </p>
  61. <blockquote><pre>
  62. <span class=identifier>flyweight</span><span class=special>&lt;</span><span class=identifier>texture</span><span class=special>&gt;</span> <span class=identifier>fw</span><span class=special>(</span><span class=identifier>texture</span><span class=special>(</span><span class=string>&quot;grass.texture&quot;</span><span class=special>));</span>
  63. </pre></blockquote>
  64. <p>
  65. This is unnaceptably costly: we are constructing a massive temporary
  66. object just to throw it away in most cases, since Boost.Flyweight most
  67. likely already has an internal equivalent object to which <code>fw</code>
  68. will be bound --value sharing is the key feature behind the flyweight
  69. pattern after all. In this particular example, texture filenames act
  70. as a <i>key</i> to the actual texture objects: two texture objects
  71. constructed from the same filename are equivalent. So, we would like
  72. for filenames to be used for texture lookup and somehow be sure that
  73. the costly texture construction is only performed when no equivalent
  74. value has been found.
  75. </p>
  76. <p>
  77. <code>flyweight&lt;T&gt;</code> makes this distinction between key and value
  78. blurry because it uses <code>T</code> both as the key type and
  79. its associated value type. When this is inefficient, as in our texture
  80. example, we can explicity specify both types using the
  81. <a href="../reference/key_value.html#key_value_construct"><code>key_value</code></a>
  82. construct:
  83. </p>
  84. <blockquote><pre>
  85. <span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>flyweight</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
  86. <span class=preprocessor>#include</span> <span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>flyweight</span><span class=special>/</span><span class=identifier>key_value</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;</span>
  87. <span class=special>...</span>
  88. <span class=identifier>flyweight</span><span class=special>&lt;</span><span class=identifier>key_value</span><span class=special>&lt;</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,</span><span class=identifier>texture</span><span class=special>&gt;</span> <span class=special>&gt;</span> <span class=identifier>fw</span><span class=special>(</span><span class=string>&quot;grass.texture&quot;</span><span class=special>);</span>
  89. </pre></blockquote>
  90. <p>
  91. So called <i>key-value flyweights</i> have then the form
  92. <code>flyweight&lt;key_value&lt;K,T&gt; &gt;</code>: the key type <code>K</code> is
  93. used to do the internal lookup for the associated values of type <code>T</code>. Key-value
  94. flyweights guarantee that <code>T</code> values are not constructed except when
  95. no other equivalent value exists; such construction is done from the associated
  96. <code>K</code> value.
  97. </p>
  98. <h3><a name="key_extractor">Key extractors</a></h3>
  99. <p>
  100. Besides the key-based semantics on construction time, key-value flyweights
  101. behave much the same as regular flyweights, although some differences persist.
  102. Consider the following code, which poses no problems with regular
  103. flyweights:
  104. </p>
  105. <blockquote><pre>
  106. <span class=keyword>const</span> <span class=identifier>texture</span><span class=special>&amp;</span> <span class=identifier>get_texture</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>object</span><span class=special>&amp;);</span>
  107. <span class=special>...</span>
  108. <span class=identifier>flyweight</span><span class=special>&lt;</span><span class=identifier>key_value</span><span class=special>&lt;</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,</span><span class=identifier>texture</span><span class=special>&gt;</span> <span class=special>&gt;</span> <span class=identifier>fw</span><span class=special>;</span>
  109. <span class=special>...</span>
  110. <span class=identifier>fw</span><span class=special>=</span><span class=identifier>get_texture</span><span class=special>(</span><span class=identifier>obj</span><span class=special>);</span>
  111. </pre></blockquote>
  112. <p>
  113. The assignment cannot possibly work, because a key of type <code>std::string</code>
  114. is needed to do the internal lookup whereas we are passing a full texture object.
  115. Indeed, the code produces a compilation error similar to this:
  116. </p>
  117. <blockquote><pre>
  118. error: 'boost::mpl::assertion_failed' : cannot convert parameter 1 from
  119. 'boost::mpl::failed ************(__thiscall boost::flyweights::detail::
  120. regular_key_value&lt;Key,Value&gt;::rep_type::no_key_from_value_failure::
  121. <b>NO_KEY_FROM_VALUE_CONVERSION_PROVIDED</b>::* ***********)(std::string,texture)'
  122. to 'boost::mpl::assert&lt;false&gt;::type'...
  123. </pre></blockquote>
  124. <p>
  125. It turns out that we can make the assignment work if only we provide a means
  126. to retrieve the key from the value. This is not always possible, but in
  127. our particular example the texture class does store the filename used for
  128. construction, as indicated by the <code>texture::get_filename</code>
  129. member function. We take advantage of this by specifying a
  130. suitable <a href="../reference/key_value.html#key_extractor"><i>key
  131. extractor</i></a> as part of the flyweight type definition:
  132. </p>
  133. <blockquote><pre>
  134. <span class=keyword>struct</span> <span class=identifier>texture_filename_extractor</span>
  135. <span class=special>{</span>
  136. <span class=keyword>const</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>&amp;</span> <span class=keyword>operator</span><span class=special>()(</span><span class=keyword>const</span> <span class=identifier>texture</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>)</span><span class=keyword>const</span>
  137. <span class=special>{</span>
  138. <span class=keyword>return</span> <span class=identifier>x</span><span class=special>.</span><span class=identifier>get_filename</span><span class=special>();</span>
  139. <span class=special>}</span>
  140. <span class=special>};</span>
  141. <span class=identifier>flyweight</span><span class=special>&lt;</span><span class=identifier>key_value</span><span class=special>&lt;</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>,</span><span class=identifier>texture</span><span class=special>,</span><span class=identifier>texture_filename_extractor</span><span class=special>&gt;</span> <span class=special>&gt;</span> <span class=identifier>fw</span><span class=special>;</span>
  142. <span class=special>...</span>
  143. <span class=identifier>fw</span><span class=special>=</span><span class=identifier>get_texture</span><span class=special>(</span><span class=identifier>obj</span><span class=special>);</span> <span class=comment>// OK now</span>
  144. </pre></blockquote>
  145. <p>
  146. The specification of a key extractor in the
  147. definition of a key-value flyweight results in internal space optimizations,
  148. as the keys need not be stored along the values but are retrieved from
  149. them instead. So, it is always a good idea to provide a key extractor when
  150. possible even if your program does not contain assignment statements like
  151. the one above.
  152. </p>
  153. <p>
  154. Examples <a href="../examples.html#example2">2</a> and
  155. <a href="../examples.html#example5">5</a>
  156. of the examples section make use of key-value flyweights.
  157. </p>
  158. <h3><a name="requirements">Type requirements</a></h3>
  159. <p>
  160. Many of the requirements imposed on <code>T</code> for
  161. <a href="basics.html#requirements">regular flyweights</a> move to the key
  162. type in the case of a key-value <code>flyweight&lt;key_value&lt;K,T&gt; &gt;</code>.
  163. Now it is <code>K</code> that must be
  164. <a href="https://boost.org/sgi/stl/Assignable.html"><code>Assignable</code></a>,
  165. <a href="https://boost.org/sgi/stl/EqualityComparable.html"><code>Equality
  166. Comparable</code></a> and interoperate with
  167. <a href="../../../functional/hash/index.html">Boost.Hash</a>, where equality and
  168. hash compatibility are requirements imposed by the default internal factory of
  169. Boost.Flyweight and can change if this factory is further configured or replaced
  170. by the user. The only requisite retained on <code>T</code> is that it must be
  171. constructible from <code>K</code>; only in the case that a flyweight is directly
  172. assigned a <code>T</code> object is also <code>T</code> required to be
  173. <a href="https://boost.org/sgi/stl/Assignable.html"><code>Assignable</code></a>.
  174. To serialize objects of type <code>flyweight&lt;key_value&lt;K,T&gt; &gt;</code>
  175. only <code>K</code> needs to be serializable.
  176. </p>
  177. <hr>
  178. <div class="prev_link"><a href="basics.html"><img src="../prev.gif" alt="basics" border="0"><br>
  179. Basics
  180. </a></div>
  181. <div class="up_link"><a href="index.html"><img src="../up.gif" alt="Boost.Flyweight tutorial" border="0"><br>
  182. Boost.Flyweight tutorial
  183. </a></div>
  184. <div class="next_link"><a href="configuration.html"><img src="../next.gif" alt="configuring Boost.Flyweight" border="0"><br>
  185. Configuring Boost.Flyweight
  186. </a></div><br clear="all" style="clear: all;">
  187. <br>
  188. <p>Revised April 24th 2019</p>
  189. <p>&copy; Copyright 2006-2019 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
  190. Distributed under the Boost Software
  191. License, Version 1.0. (See accompanying file <a href="../../../../LICENSE_1_0.txt">
  192. LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
  193. http://www.boost.org/LICENSE_1_0.txt</a>)
  194. </p>
  195. </body>
  196. </html>