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