234 lines
12 KiB
HTML
234 lines
12 KiB
HTML
<!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>
|