123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0.1 Transitional//EN">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>Boost.Flyweight Documentation - Tutorial - Key-value flyweights</title>
- <link rel="stylesheet" href="../style.css" type="text/css">
- <link rel="start" href="../index.html">
- <link rel="prev" href="basics.html">
- <link rel="up" href="index.html">
- <link rel="next" href="configuration.html">
- </head>
- <body>
- <h1><img src="../../../../boost.png" alt="Boost logo" align=
- "middle" width="277" height="86">Boost.Flyweight Tutorial: Key-value flyweights</h1>
- <div class="prev_link"><a href="basics.html"><img src="../prev.gif" alt="basics" border="0"><br>
- Basics
- </a></div>
- <div class="up_link"><a href="index.html"><img src="../up.gif" alt="Boost.Flyweight tutorial" border="0"><br>
- Boost.Flyweight tutorial
- </a></div>
- <div class="next_link"><a href="configuration.html"><img src="../next.gif" alt="configuring Boost.Flyweight" border="0"><br>
- Configuring Boost.Flyweight
- </a></div><br clear="all" style="clear: all;">
- <hr>
- <h2>Contents</h2>
- <ul>
- <li><a href="#key_value">Key-value flyweights</a>
- <ul>
- <li><a href="#key_extractor">Key extractors</a></li>
- <li><a href="#requirements">Type requirements</a></li>
- </ul>
- </li>
- </ul>
- <h2><a name="key_value">Key-value flyweights</a></h2>
- <p>
- Continuing with our online game example, suppose we have a huge class for
- handling rendering textures:
- </p>
- <blockquote><pre>
- <span class=keyword>class</span> <span class=identifier>texture</span>
- <span class=special>{</span>
- <span class=keyword>public</span><span class=special>:</span>
- <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>
- <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>
- <span class=comment>// rest of the interface</span>
- <span class=special>};</span>
- </pre></blockquote>
- <p>
- and we decide to use <code>flyweight<texture></code> to ease the
- manipulation of these objects. Now consider this seemingly innocent
- expression:
- </p>
- <blockquote><pre>
- <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>
- </pre></blockquote>
- <p>
- Note that in order to construct <code>fw</code> we are implicitly
- constructing a full grass texture object. The expression is mostly
- equivalent to
- </p>
- <blockquote><pre>
- <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>
- </pre></blockquote>
- <p>
- This is unnaceptably costly: we are constructing a massive temporary
- object just to throw it away in most cases, since Boost.Flyweight most
- likely already has an internal equivalent object to which <code>fw</code>
- will be bound --value sharing is the key feature behind the flyweight
- pattern after all. In this particular example, texture filenames act
- as a <i>key</i> to the actual texture objects: two texture objects
- constructed from the same filename are equivalent. So, we would like
- for filenames to be used for texture lookup and somehow be sure that
- the costly texture construction is only performed when no equivalent
- value has been found.
- </p>
- <p>
- <code>flyweight<T></code> makes this distinction between key and value
- blurry because it uses <code>T</code> both as the key type and
- its associated value type. When this is inefficient, as in our texture
- example, we can explicity specify both types using the
- <a href="../reference/key_value.html#key_value_construct"><code>key_value</code></a>
- construct:
- </p>
- <blockquote><pre>
- <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>
- <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>
- <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>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>
- </pre></blockquote>
- <p>
- So called <i>key-value flyweights</i> have then the form
- <code>flyweight<key_value<K,T> ></code>: the key type <code>K</code> is
- used to do the internal lookup for the associated values of type <code>T</code>. Key-value
- flyweights guarantee that <code>T</code> values are not constructed except when
- no other equivalent value exists; such construction is done from the associated
- <code>K</code> value.
- </p>
- <h3><a name="key_extractor">Key extractors</a></h3>
- <p>
- Besides the key-based semantics on construction time, key-value flyweights
- behave much the same as regular flyweights, although some differences persist.
- Consider the following code, which poses no problems with regular
- flyweights:
- </p>
- <blockquote><pre>
- <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>
- <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>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=special>...</span>
- <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>
- </pre></blockquote>
- <p>
- The assignment cannot possibly work, because a key of type <code>std::string</code>
- is needed to do the internal lookup whereas we are passing a full texture object.
- Indeed, the code produces a compilation error similar to this:
- </p>
- <blockquote><pre>
- error: 'boost::mpl::assertion_failed' : cannot convert parameter 1 from
- 'boost::mpl::failed ************(__thiscall boost::flyweights::detail::
- regular_key_value<Key,Value>::rep_type::no_key_from_value_failure::
- <b>NO_KEY_FROM_VALUE_CONVERSION_PROVIDED</b>::* ***********)(std::string,texture)'
- to 'boost::mpl::assert<false>::type'...
- </pre></blockquote>
- <p>
- It turns out that we can make the assignment work if only we provide a means
- to retrieve the key from the value. This is not always possible, but in
- our particular example the texture class does store the filename used for
- construction, as indicated by the <code>texture::get_filename</code>
- member function. We take advantage of this by specifying a
- suitable <a href="../reference/key_value.html#key_extractor"><i>key
- extractor</i></a> as part of the flyweight type definition:
- </p>
- <blockquote><pre>
- <span class=keyword>struct</span> <span class=identifier>texture_filename_extractor</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=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>
- <span class=special>{</span>
- <span class=keyword>return</span> <span class=identifier>x</span><span class=special>.</span><span class=identifier>get_filename</span><span class=special>();</span>
- <span class=special>}</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>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>
- <span class=special>...</span>
- <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>
- </pre></blockquote>
- <p>
- The specification of a key extractor in the
- definition of a key-value flyweight results in internal space optimizations,
- as the keys need not be stored along the values but are retrieved from
- them instead. So, it is always a good idea to provide a key extractor when
- possible even if your program does not contain assignment statements like
- the one above.
- </p>
- <p>
- Examples <a href="../examples.html#example2">2</a> and
- <a href="../examples.html#example5">5</a>
- of the examples section make use of key-value flyweights.
- </p>
- <h3><a name="requirements">Type requirements</a></h3>
- <p>
- Many of the requirements imposed on <code>T</code> for
- <a href="basics.html#requirements">regular flyweights</a> move to the key
- type in the case of a key-value <code>flyweight<key_value<K,T> ></code>.
- Now it is <code>K</code> that must be
- <a href="https://boost.org/sgi/stl/Assignable.html"><code>Assignable</code></a>,
- <a href="https://boost.org/sgi/stl/EqualityComparable.html"><code>Equality
- Comparable</code></a> and interoperate with
- <a href="../../../functional/hash/index.html">Boost.Hash</a>, where equality and
- hash compatibility are requirements imposed by the default internal factory of
- Boost.Flyweight and can change if this factory is further configured or replaced
- by the user. The only requisite retained on <code>T</code> is that it must be
- constructible from <code>K</code>; only in the case that a flyweight is directly
- assigned a <code>T</code> object is also <code>T</code> required to be
- <a href="https://boost.org/sgi/stl/Assignable.html"><code>Assignable</code></a>.
- To serialize objects of type <code>flyweight<key_value<K,T> ></code>
- only <code>K</code> needs to be serializable.
- </p>
- <hr>
- <div class="prev_link"><a href="basics.html"><img src="../prev.gif" alt="basics" border="0"><br>
- Basics
- </a></div>
- <div class="up_link"><a href="index.html"><img src="../up.gif" alt="Boost.Flyweight tutorial" border="0"><br>
- Boost.Flyweight tutorial
- </a></div>
- <div class="next_link"><a href="configuration.html"><img src="../next.gif" alt="configuring Boost.Flyweight" border="0"><br>
- Configuring Boost.Flyweight
- </a></div><br clear="all" style="clear: all;">
- <br>
- <p>Revised April 24th 2019</p>
- <p>© Copyright 2006-2019 Joaquín M López Muñoz.
- Distributed under the Boost Software
- License, Version 1.0. (See accompanying file <a href="../../../../LICENSE_1_0.txt">
- LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
- http://www.boost.org/LICENSE_1_0.txt</a>)
- </p>
- </body>
- </html>
|