mirror of
https://github.com/boostorg/flyweight.git
synced 2026-01-19 04:12:09 +00:00
Sync from upstream.
This commit is contained in:
@@ -39,6 +39,7 @@ Tests
|
||||
<li><a href="#example6">Example 6: serialization</a></li>
|
||||
<li><a href="#example7">Example 7: performance comparison</a></li>
|
||||
<li><a href="#example8">Example 8: custom factory</a></li>
|
||||
<li><a href="#example9">Example 9: parallel tokenization</a></li>
|
||||
</ul>
|
||||
|
||||
<h2><a name="example1">Example 1: basic usage</a></h2>
|
||||
@@ -257,6 +258,42 @@ The example shows how to write and use a custom factory class. This
|
||||
by Boost.Flyweight, so helping the user visualize factory usage patterns.
|
||||
</p>
|
||||
|
||||
<h2><a name="example9">Example 9: parallel tokenization</a></h2>
|
||||
|
||||
<p>
|
||||
See <a href="../example/parallel.cpp">source code</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The program loads a text file and tokenizes its contents into words (sequences of
|
||||
alphabetic characters) using several threads in parallel to perform the task.
|
||||
Words are stored as plain <code>std::string</code>s or using different
|
||||
<code>boost::flyweight</code> configurations.
|
||||
These are the results for
|
||||
<a href="http://mattmahoney.net/dc/enwik9.zip">http://mattmahoney.net/dc/enwik9.zip</a>
|
||||
(a chunk of the Wikipedia 1,000 million bytes in size) with Visual Studio 2022 on
|
||||
a Windows machine with an Intel Core i5-8265U CPU and 8 GB of RAM:
|
||||
</p>
|
||||
|
||||
<blockquote><pre>
|
||||
std::string, 1 thread(s): 141176630 words, 11.4551 s
|
||||
std::string, 8 thread(s): 141176630 words, 2.75682 s
|
||||
regular flyweight, 1 thread(s): 141176630 words, 19.2284 s
|
||||
regular flyweight, 8 thread(s): 141176630 words, 36.0344 s
|
||||
concurrent flyweight, 1 thread(s): 141176630 words, 20.9516 s
|
||||
concurrent flyweight, 8 thread(s): 141176630 words, 7.84129 s
|
||||
</pre></blockquote>
|
||||
|
||||
<p>
|
||||
<code>boost::flyweight<std::string></code> performs worse
|
||||
in the parallelized scenario due to its class-wide locking upon flyweight
|
||||
creation.
|
||||
On the other hand, using
|
||||
<a href="tutorial/configuration.html#concurrent_factory"><code>concurrent_factory</code></a>
|
||||
with <code>no_locking</code> and <code>no_tracking</code> achieves
|
||||
a higher bandwidth under parallelization.
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="prev_link"><a href="performance.html"><img src="prev.gif" alt="performance" border="0"><br>
|
||||
@@ -272,9 +309,9 @@ Tests
|
||||
|
||||
<br>
|
||||
|
||||
<p>Revised October 14th 2014</p>
|
||||
<p>Revised September 21th 2024</p>
|
||||
|
||||
<p>© Copyright 2006-2014 Joaquín M López Muñoz.
|
||||
<p>© Copyright 2006-2024 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">
|
||||
|
||||
@@ -49,6 +49,16 @@ Holders
|
||||
<li><a href="#hashed_factory">Class template <code>hashed_factory</code></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#concurrent_factory_fwd_synopsis">Header
|
||||
<code>"boost/flyweight/concurrent_factory_fwd.hpp"</code> synopsis</a>
|
||||
</li>
|
||||
<li><a href="#concurrent_factory_synopsis">Header
|
||||
<code>"boost/flyweight/concurrent_factory.hpp"</code> synopsis</a>
|
||||
<ul>
|
||||
<li><a href="#concurrent_factory_class">Class template <code>concurrent_factory_class</code></a></li>
|
||||
<li><a href="#concurrent_factory">Class template <code>concurrent_factory</code></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#set_factory_fwd_synopsis">Header
|
||||
<code>"boost/flyweight/set_factory_fwd.hpp"</code> synopsis</a>
|
||||
</li>
|
||||
@@ -338,6 +348,142 @@ Placeholder Expressions</code></a> resolving to the actual types used by
|
||||
<code>hashed_factory_class</code>.
|
||||
</p>
|
||||
|
||||
<h2><a name="concurrent_factory_fwd_synopsis">Header
|
||||
<a href="../../../../boost/flyweight/concurrent_factory_fwd.hpp"><code>"boost/flyweight/concurrent_factory_fwd.hpp"</code></a> synopsis</a></h2>
|
||||
|
||||
<blockquote><pre>
|
||||
<span class=keyword>namespace</span> <span class=identifier>boost</span><span class=special>{</span>
|
||||
|
||||
<span class=keyword>namespace</span> <span class=identifier>flyweights</span><span class=special>{</span>
|
||||
|
||||
<span class=keyword>template</span><span class=special><</span>
|
||||
<span class=keyword>typename</span> <span class=identifier>Entry</span><span class=special>,</span><span class=keyword>typename</span> <span class=identifier>Key</span><span class=special>,</span>
|
||||
<span class=keyword>typename</span> <span class=identifier>Hash</span><span class=special>=</span><b>implementation defined</b><span class=special>,</span>
|
||||
<span class=keyword>typename</span> <span class=identifier>Pred</span><span class=special>=</span><b>implementation defined</b><span class=special>,</span>
|
||||
<span class=keyword>typename</span> <span class=identifier>Allocator</span><span class=special>=</span><b>implementation defined</b>
|
||||
<span class=special>></span>
|
||||
<span class=keyword>class</span> <span class=identifier>concurrent_factory_class</span><span class=special>;</span>
|
||||
|
||||
<span class=keyword>template</span><span class=special><</span>
|
||||
<span class=keyword>typename</span> <span class=identifier>Hash</span><span class=special>=</span><b>implementation defined</b><span class=special>,</span>
|
||||
<span class=keyword>typename</span> <span class=identifier>Pred</span><span class=special>=</span><b>implementation defined</b><span class=special>,</span>
|
||||
<span class=keyword>typename</span> <span class=identifier>Allocator</span><span class=special>=</span><b>implementation defined</b>
|
||||
<span class=special>></span>
|
||||
<span class=keyword>struct</span> <span class=identifier>concurrent_factory</span><span class=special>;</span>
|
||||
|
||||
<span class=special>}</span> <span class=comment>// namespace boost::flyweights</span>
|
||||
|
||||
<span class=special>}</span> <span class=comment>// namespace boost</span>
|
||||
</pre></blockquote>
|
||||
|
||||
<p>
|
||||
<code>concurrent_factory_fwd.hpp</code> forward declares the class templates
|
||||
<a href="#concurrent_factory_class"><code>concurrent_factory_class</code></a>
|
||||
and <a href="#concurrent_factory"><code>concurrent_factory</code></a>.
|
||||
</p>
|
||||
|
||||
<h2><a name="concurrent_factory_synopsis">Header
|
||||
<a href="../../../../boost/flyweight/concurrent_factory.hpp"><code>"boost/flyweight/concurrent_factory.hpp"</code></a> synopsis</a></h2>
|
||||
|
||||
<h3><a name="concurrent_factory_class">Class template <code>concurrent_factory_class</code></a></h3>
|
||||
|
||||
<p>
|
||||
<code>concurrent_factory_class</code> is a <a href="#factory"><code>Factory</code></a>
|
||||
implemented with a concurrent hash container. This factory does not require external
|
||||
locking, even in a multithreaded scenarios. It does not require any tracking mechanism
|
||||
either: values no longer referenced by any flyweight are not erased deterministically,
|
||||
but rather they are removed periodically by an internal garbage collector running
|
||||
in a dedicated thread.
|
||||
</p>
|
||||
|
||||
<blockquote><pre>
|
||||
<span class=keyword>template</span><span class=special><</span>
|
||||
<span class=keyword>typename</span> <span class=identifier>Entry</span><span class=special>,</span><span class=keyword>typename</span> <span class=identifier>Key</span><span class=special>,</span>
|
||||
<span class=keyword>typename</span> <span class=identifier>Hash</span><span class=special>,</span><span class=keyword>typename</span> <span class=identifier>Pred</span><span class=special>,</span><span class=keyword>typename</span> <span class=identifier>Allocator</span>
|
||||
<span class=special>></span>
|
||||
<span class=keyword>class</span> <span class=identifier>concurrent_factory_class</span>
|
||||
<span class=special>{</span>
|
||||
<span class=keyword>public</span><span class=special>:</span>
|
||||
<span class=keyword>typedef</span> <b>implementation defined</b> <span class=identifier>handle_type</span><span class=special>;</span>
|
||||
|
||||
<span class=identifier>handle_type</span> <span class=identifier>insert</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>Entry</span><span class=special>&</span> <span class=identifier>x</span><span class=special>);</span>
|
||||
<span class=keyword>void</span> <span class=identifier>erase</span><span class=special>(</span><span class=identifier>handle_type</span> <span class=identifier>h</span><span class=special>);</span>
|
||||
<span class=keyword>const</span> <span class=identifier>Entry</span><span class=special>&</span> <span class=identifier>entry</span><span class=special>(</span><span class=identifier>handle_type</span> <span class=identifier>h</span><span class=special>);</span>
|
||||
<span class=special>};</span>
|
||||
</pre></blockquote>
|
||||
|
||||
<p>
|
||||
<code>Hash</code> is a
|
||||
<a href="https://boost.org/sgi/stl/DefaultConstructible.html"><code>Default
|
||||
Constructible</code></a>
|
||||
<a href="https://boost.org/sgi/stl/UnaryFunction.html"><code>Unary Function</code></a>
|
||||
taking a single argument of type <code>Key</code> and returning a
|
||||
value of type <code>std::size_t</code> in the range
|
||||
<code>[0, std::numeric_limits<std::size_t>::max())</code>.
|
||||
<code>Pred</code> is a
|
||||
<a href="https://boost.org/sgi/stl/DefaultConstructible.html"><code>Default
|
||||
Constructible</code></a>
|
||||
<a href="https://boost.org/sgi/stl/BinaryPredicate.html">
|
||||
<code>Binary Predicate</code></a> inducing an equivalence relation
|
||||
on elements of <code>Key</code>. It is required that
|
||||
a <code>Hash</code> object return the same value for objects
|
||||
equivalent under <code>Pred</code>.
|
||||
The equivalence relation on <code>Key</code> associated to the factory is
|
||||
that induced by <code>Pred</code>.
|
||||
The default arguments for <code>Hash</code> and <code>Pred</code> are
|
||||
<a href="../../../functional/hash/index.html"><code>boost::hash<Key></code></a>
|
||||
and <code>std::equal_to<Key></code>, respectively.
|
||||
<code>Allocator</code> must be an allocator of <code>Entry</code> objects
|
||||
satisfying the associated C++ requirements at <b>[lib.allocator.requirements]</b>.
|
||||
The default argument is <code>std::allocator<Entry></code>. The internal
|
||||
concurrent container upon which <code>concurrent_factory_class</code> is based is
|
||||
constructed with default initialized objects of type <code>Hash</code>,
|
||||
<code>Pred</code> and <code>Allocator</code>.
|
||||
</p>
|
||||
|
||||
<h3><a name="concurrent_factory">Class template <code>concurrent_factory</code></a></h3>
|
||||
|
||||
<p>
|
||||
<a href="#factory"><code>Factory Specifier</code></a> for <a href="#concurrent_factory_class"><code>concurrent_factory_class</code></a>.
|
||||
</p>
|
||||
|
||||
<blockquote><pre>
|
||||
<span class=keyword>template</span><span class=special><</span><span class=keyword>typename</span> <span class=identifier>Hash</span><span class=special>,</span><span class=keyword>typename</span> <span class=identifier>Pred</span><span class=special>,</span><span class=keyword>typename</span> <span class=identifier>Allocator</span><span class=special>></span>
|
||||
<span class=keyword>struct</span> <span class=identifier>concurrent_factory</span><span class=special>;</span>
|
||||
</pre></blockquote>
|
||||
|
||||
<p>
|
||||
<code>concurrent_factory<Hash,Pred,Allocator></code> is an
|
||||
<a href="../../../mpl/doc/refmanual/metafunction-class.html"><code>MPL Metafunction
|
||||
Class</code></a> such that the type
|
||||
</p>
|
||||
|
||||
<blockquote><pre>
|
||||
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>mpl</span><span class=special>::</span><span class=identifier>apply</span><span class=special><</span>
|
||||
<span class=identifier>concurrent_factory</span><span class=special><</span><span class=identifier>Hash</span><span class=special>,</span><span class=identifier>Pred</span><span class=special>,</span><span class=identifier>Allocator</span><span class=special>>,</span>
|
||||
<span class=identifier>Entry</span><span class=special>,</span><span class=identifier>Key</span>
|
||||
<span class=special>>::</span><span class=identifier>type</span>
|
||||
</pre></blockquote>
|
||||
|
||||
<p>
|
||||
is the same as
|
||||
</p>
|
||||
|
||||
<blockquote><pre>
|
||||
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>mpl</span><span class=special>::</span><span class=identifier>apply</span><span class=special><</span>
|
||||
<span class=identifier>concurrent_factory_class</span><span class=special><</span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>mpl</span><span class=special>::</span><span class=identifier>_1</span><span class=special>,</span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>mpl</span><span class=special>::</span><span class=identifier>_2</span><span class=special>,</span><span class=identifier>Hash</span><span class=special>,</span><span class=identifier>Pred</span><span class=special>,</span><span class=identifier>Allocator</span><span class=special>>,</span>
|
||||
<span class=identifier>Entry</span><span class=special>,</span><span class=identifier>Key</span>
|
||||
<span class=special>>::</span><span class=identifier>type</span>
|
||||
</pre></blockquote>
|
||||
|
||||
<p>
|
||||
This implies that <code>Hash</code>, <code>Pred</code> and <code>Allocator</code>
|
||||
can be
|
||||
<a href="../../../mpl/doc/refmanual/placeholder-expression.html"><code>MPL
|
||||
Placeholder Expressions</code></a> resolving to the actual types used by
|
||||
<code>concurrent_factory_class</code>.
|
||||
</p>
|
||||
|
||||
<h2><a name="set_factory_fwd_synopsis">Header
|
||||
<a href="../../../../boost/flyweight/set_factory_fwd.hpp"><code>"boost/flyweight/set_factory_fwd.hpp"</code></a> synopsis</a></h2>
|
||||
|
||||
@@ -570,9 +716,9 @@ Holders
|
||||
|
||||
<br>
|
||||
|
||||
<p>Revised April 24th 2019</p>
|
||||
<p>Revised September 20th 2024</p>
|
||||
|
||||
<p>© Copyright 2006-2019 Joaquín M López Muñoz.
|
||||
<p>© Copyright 2006-2024 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">
|
||||
|
||||
@@ -72,6 +72,8 @@ Boost.Flyweight comprises the following public headers:
|
||||
<li><a href="factories.html#factory_tag_synopsis"><code>"boost/flyweight/factory_tag.hpp"</code></a></li>
|
||||
<li><a href="factories.html#hashed_factory_fwd_synopsis"><code>"boost/flyweight/hashed_factory_fwd.hpp"</code></a></li>
|
||||
<li><a href="factories.html#hashed_factory_synopsis"><code>"boost/flyweight/hashed_factory.hpp"</code></a></li>
|
||||
<li><a href="factories.html#concurrent_factory_fwd_synopsis"><code>"boost/flyweight/concurrent_factory_fwd.hpp"</code></a></li>
|
||||
<li><a href="factories.html#concurrent_factory_synopsis"><code>"boost/flyweight/concurrent_factory.hpp"</code></a></li>
|
||||
<li><a href="factories.html#set_factory_fwd_synopsis"><code>"boost/flyweight/set_factory_fwd.hpp"</code></a></li>
|
||||
<li><a href="factories.html#set_factory_synopsis"><code>"boost/flyweight/set_factory.hpp"</code></a></li>
|
||||
<li><a href="factories.html#assoc_container_factory_fwd_synopsis"><code>"boost/flyweight/assoc_container_factory_fwd.hpp"</code></a></li>
|
||||
@@ -154,9 +156,9 @@ Index
|
||||
|
||||
<br>
|
||||
|
||||
<p>Revised September 1st 2014</p>
|
||||
<p>Revised September 17th 2024</p>
|
||||
|
||||
<p>© Copyright 2006-2014 Joaquín M López Muñoz.
|
||||
<p>© Copyright 2006-2024 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">
|
||||
|
||||
@@ -55,6 +55,10 @@ Acknowledgements
|
||||
|
||||
<p>
|
||||
<ul>
|
||||
<li>Added <a href="tutorial/configuration.html#concurrent_factory"><code>concurrent_factory</code></a>,
|
||||
a factory based on a concurrent container from
|
||||
<a href="../../serialization/index.html">Boost.Unordered</a>
|
||||
that provides excellent performance in multithreaded scenarios.</li>
|
||||
<li>Marked as <code>noexcept</code> those <code>boost::flyweight</code>
|
||||
operations previously documented as not throwing
|
||||
(<a href="https://github.com/boostorg/flyweight/issues/15">issue #15</a>).</li>
|
||||
@@ -253,7 +257,7 @@ Acknowledgements
|
||||
|
||||
<br>
|
||||
|
||||
<p>Revised September 14th 2024</p>
|
||||
<p>Revised September 17th 2024</p>
|
||||
|
||||
<p>© Copyright 2006-2024 Joaquín M López Muñoz.
|
||||
Distributed under the Boost Software
|
||||
|
||||
@@ -52,38 +52,43 @@ of Boost.Flyweight.
|
||||
<td>Exercises the default components of <code>flyweight</code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../test/test_concurrent_factory.cpp"><code>test_concurrent_factory.cpp</code></a></td>
|
||||
<td>Exercises <a href="tutorial/configuration.html#concurrent_factory"><code>concurrent_factory</code></a>
|
||||
factory specifier.</td>
|
||||
</tr>
|
||||
<tr class="odd_tr">
|
||||
<td><a href="../test/test_custom_factory.cpp"><code>test_custom_factory.cpp</code></a></td>
|
||||
<td>Creates a user-defined factory class and specifier.</td>
|
||||
</tr>
|
||||
<tr class="odd_tr">
|
||||
<tr>
|
||||
<td><a href="../test/test_init.cpp"><code>test_init.cpp</code></a></td>
|
||||
<td>Boost.Flyweight <a href="tutorial/technical.html#static_init">static
|
||||
data initialization</a> facilities.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<tr class="odd_tr">
|
||||
<td><a href="../test/test_intermod_holder.cpp"><code>test_intermod_holder.cpp</code></a><br>
|
||||
<a href="../test/intermod_holder_dll.cpp"><code>intermod_holder_dll.cpp</code></a></td>
|
||||
<td>Exercises <a href="tutorial/configuration.html#intermodule_holder"><code>intermodule_holder</code></a>.</td>
|
||||
</tr>
|
||||
<tr class="odd_tr">
|
||||
<tr>
|
||||
<td><a href="../test/test_multictor.cpp"><code>test_multictor.cpp</code></a></td>
|
||||
<td>Tests <code>flyweight</code> <a href="reference/flyweight.html#constructors">multiple
|
||||
argument and initializer-list constructors</a>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<tr class="odd_tr">
|
||||
<td><a href="../test/test_no_locking.cpp"><code>test_no_locking.cpp</code></a></td>
|
||||
<td><a href="tutorial/configuration.html#no_locking"><code>no_locking</code></a> policy.</td>
|
||||
</tr>
|
||||
<tr class="odd_tr">
|
||||
<tr>
|
||||
<td><a href="../test/test_no_tracking.cpp"><code>test_no_tracking.cpp</code></a></td>
|
||||
<td><a href="tutorial/configuration.html#no_tracking"><code>no_tracking</code></a> policy.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<tr class="odd_tr">
|
||||
<td><a href="../test/test_serialization.cpp"><code>test_serialization.cpp</code></a></td>
|
||||
<td>Exercises <code>flyweight</code> <a href="tutorial/basics.html#serialization">serialization
|
||||
capabilities</a>.</td>
|
||||
</tr>
|
||||
<tr class="odd_tr">
|
||||
<tr>
|
||||
<td><a href="../test/test_set_factory.cpp"><code>test_set_factory.cpp</code></a></td>
|
||||
<td><a href="tutorial/configuration.html#set_factory"><code>set_factory</code></a>
|
||||
factory specifier.</td>
|
||||
@@ -106,9 +111,9 @@ Future work
|
||||
<br>
|
||||
|
||||
|
||||
<p>Revised September 1st 2014</p>
|
||||
<p>Revised September 17th 2024</p>
|
||||
|
||||
<p>© Copyright 2006-2014 Joaquín M López Muñoz.
|
||||
<p>© Copyright 2006-2024 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">
|
||||
|
||||
@@ -41,6 +41,7 @@ Extending Boost.Flyweight
|
||||
<ul>
|
||||
<li><a href="#factory_types">Types involved in the configuration of factories</a></li>
|
||||
<li><a href="#hashed_factory"><code>hashed_factory</code></a></li>
|
||||
<li><a href="#concurrent_factory"><code>concurrent_factory</code></a></li>
|
||||
<li><a href="#set_factory"><code>set_factory</code></a></li>
|
||||
<li><a href="#assoc_container_factory"><code>assoc_container_factory</code></a></li>
|
||||
</ul>
|
||||
@@ -228,7 +229,7 @@ type <code>boost::mpl::_1</code> can be used.
|
||||
|
||||
<p>
|
||||
This specifier, which Boost.Flyweight takes by default, controls the usage of a
|
||||
factory internally based in a hash container. Values are determined to be
|
||||
factory internally based on a hash container. Values are determined to be
|
||||
equivalent by means of the
|
||||
<a href="https://boost.org/sgi/stl/BinaryPredicate.html"><code>Binary
|
||||
Predicate</code></a> <code>Pred</code>, and indexed into the factory container
|
||||
@@ -281,6 +282,65 @@ a special hash predicate <code>special_hash</code> and a custom allocator
|
||||
<span class=special>></span>
|
||||
</pre></blockquote>
|
||||
|
||||
<h3><a name="concurrent_factory"><code>concurrent_factory</code></a></h3>
|
||||
|
||||
<blockquote>
|
||||
<b>Header:</b> <a href="../reference/factories.html#concurrent_factory_synopsis"><code>"boost/flyweight/concurrent_factory.hpp"</code></a><br>
|
||||
<b>Syntax:</b> <code>concurrent_factory<[Hash[,Pred[,Allocator]]]></code>
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
This specifier provides a factory based on a concurrent container from
|
||||
<a href="../../../unordered/index.html">Boost.Unordered</a>.
|
||||
The factory is particularly suitable for flyweight creation in multithreaded
|
||||
scenarios as it does not require external synchronization or tracking; so,
|
||||
it should be generally used in conjunction with
|
||||
<a href="#no_locking"><code>no_locking</code></a> and
|
||||
<a href="#no_tracking"><code>no_tracking</code></a>:
|
||||
</p>
|
||||
|
||||
<blockquote><pre>
|
||||
<span class=keyword>typedef</span> <span class=identifier>flyweight</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>concurrent_factory</span><span class=special><>,</span>
|
||||
<span class=identifier>no_locking</span><span class=special>,</span>
|
||||
<span class=identifier>no_tracking</span>
|
||||
<span class=special>></span> <span class=identifier>concurrent_string_flyweight</span><span class=special>;</span>
|
||||
</pre></blockquote>
|
||||
|
||||
<p>
|
||||
Unused values (those no longer referred to by any flyweight), are periodically
|
||||
erased from the factory by a built-in garbage collector.
|
||||
</p>
|
||||
|
||||
|
||||
<p>
|
||||
The default types for <code>concurrent_factory</code> parameters are such that the expression
|
||||
</p>
|
||||
|
||||
<blockquote><pre>
|
||||
<span class=identifier>flyweight</span><span class=special><</span><span class=identifier>T</span><span class=special>,</span><span class=identifier>concurrent_factory</span><span class=special><></span> <span class=special>></span>
|
||||
</pre></blockquote>
|
||||
|
||||
<p>
|
||||
is equivalent to
|
||||
</p>
|
||||
|
||||
<blockquote><pre>
|
||||
<span class=identifier>flyweight</span><span class=special><</span>
|
||||
<span class=identifier>T</span><span class=special>,</span>
|
||||
<span class=identifier>concurrent_factory</span><span class=special><</span>
|
||||
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>hash</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>equal_to</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>allocator</span><span class=special><</span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>mpl</span><span class=special>::</span><span class=identifier>_1</span><span class=special>></span>
|
||||
<span class=special>></span>
|
||||
<span class=special>></span>
|
||||
</pre></blockquote>
|
||||
|
||||
<p>
|
||||
with the same meaning as in <a href="#hashed_factory"><code>hashed_factory</code></a>.
|
||||
</p>
|
||||
|
||||
<h3><a name="set_factory"><code>set_factory</code></a></h3>
|
||||
|
||||
<blockquote>
|
||||
@@ -351,7 +411,7 @@ requirements:
|
||||
<a href="https://boost.org/sgi/stl/UniqueAssociativeContainer.html"><code>Unique
|
||||
Associative Container</code></a> where equivalence of <code>Entry</code>s
|
||||
is determined by the <code>key_type</code> values the entries are convertible
|
||||
to .
|
||||
to.
|
||||
</li>
|
||||
<li>The container must be <i>stable</i>, i.e. its iterators must remain valid
|
||||
after insert and erase operations. Note that this condition is not met by
|
||||
@@ -634,9 +694,9 @@ Extending Boost.Flyweight
|
||||
|
||||
<br>
|
||||
|
||||
<p>Revised April 24th 2019</p>
|
||||
<p>Revised September 18th 2024</p>
|
||||
|
||||
<p>© Copyright 2006-2019 Joaquín M López Muñoz.
|
||||
<p>© Copyright 2006-2024 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">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Boost.Flyweight examples Jamfile
|
||||
#
|
||||
# Copyright 2006-2014 Joaquín M López Muñoz.
|
||||
# Copyright 2006-2024 Joaquín M López Muñoz.
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -41,6 +41,11 @@ exe key_value
|
||||
/boost/array//boost_array
|
||||
;
|
||||
|
||||
exe parallel
|
||||
: parallel.cpp
|
||||
: <include>$(BOOST_ROOT)
|
||||
;
|
||||
|
||||
exe perf
|
||||
: perf.cpp
|
||||
/boost/tokenizer//boost_tokenizer
|
||||
|
||||
163
example/parallel.cpp
Normal file
163
example/parallel.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
/* Boost.Flyweight example of parallel tokenization.
|
||||
*
|
||||
* Copyright 2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See http://www.boost.org/libs/flyweight for library home page.
|
||||
*/
|
||||
|
||||
#include <boost/flyweight.hpp>
|
||||
#include <boost/flyweight/concurrent_factory.hpp>
|
||||
#include <boost/flyweight/no_locking.hpp>
|
||||
#include <boost/flyweight/no_tracking.hpp>
|
||||
#include <chrono>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
/* Handcrafted tokenizer for sequences of alphabetic characters */
|
||||
|
||||
inline bool match(char ch)
|
||||
{
|
||||
return (ch>='a' && ch<='z') || (ch>='A' && ch<='Z');
|
||||
}
|
||||
|
||||
template<typename ForwardIterator,typename F>
|
||||
void tokenize(ForwardIterator first,ForwardIterator last,F f)
|
||||
{
|
||||
goto start;
|
||||
for(;;)
|
||||
{
|
||||
for(;;){
|
||||
++first;
|
||||
|
||||
start:
|
||||
if(first==last)return;
|
||||
if(match(*first))break;
|
||||
}
|
||||
|
||||
auto begin_word=first;
|
||||
for(;;){
|
||||
if(++first==last||!match(*first)){
|
||||
f(begin_word,first);
|
||||
if(first==last)return;
|
||||
else break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Tokenize a string into words in parallel and store the results into a
|
||||
* std::vector<String>, String being std::string or a flyweight type.
|
||||
*/
|
||||
|
||||
template<typename String>
|
||||
void parse(const std::string& in,const char* type_name,std::size_t num_threads)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
using string_iterator=std::string::const_iterator;
|
||||
|
||||
auto t1=steady_clock::now();
|
||||
|
||||
/* Divide input in num_threads chunks, taking care that boundaries are not
|
||||
* placed in the middle of a token.
|
||||
*/
|
||||
|
||||
std::vector<string_iterator> boundaries(num_threads+1);
|
||||
|
||||
boundaries[0]=in.begin();
|
||||
for(std::size_t i=0;i<num_threads;++i){
|
||||
auto& it=boundaries[i+1];
|
||||
it=boundaries[i]+(in.end()-boundaries[i])/(num_threads-i);
|
||||
while(it!=in.end()&&match(*it))++it;
|
||||
}
|
||||
|
||||
/* do a first pass to precalculate # of words produced by each thread */
|
||||
|
||||
std::vector<std::thread> threads(num_threads);
|
||||
std::vector<std::size_t> partial_num_words(num_threads);
|
||||
|
||||
for(std::size_t i=0;i<num_threads;++i){
|
||||
threads[i]=std::thread([&,i]{
|
||||
std::size_t s=0;
|
||||
tokenize(
|
||||
boundaries[i],boundaries[i+1],
|
||||
[&](string_iterator,string_iterator){++s;});
|
||||
partial_num_words[i]=s;
|
||||
});
|
||||
}
|
||||
|
||||
std::size_t num_words=0;
|
||||
std::vector<std::size_t> thread_output_starts(num_threads);
|
||||
|
||||
for(std::size_t i=0;i<num_threads;++i){
|
||||
threads[i].join();
|
||||
thread_output_starts[i]=num_words;
|
||||
num_words+=partial_num_words[i];
|
||||
}
|
||||
|
||||
/* do a second pass, this time populating the result vector */
|
||||
|
||||
std::vector<String> words(num_words,String());
|
||||
|
||||
for(std::size_t i=0;i<num_threads;++i){
|
||||
threads[i]=std::thread([&,i]{
|
||||
auto out=words.begin()+thread_output_starts[i];
|
||||
tokenize(
|
||||
boundaries[i],boundaries[i+1],
|
||||
[&](string_iterator first,string_iterator last){
|
||||
*out++=String(first,last);
|
||||
});
|
||||
});
|
||||
}
|
||||
for(std::size_t i=0;i<num_threads;++i){threads[i].join();}
|
||||
|
||||
auto t2=steady_clock::now();
|
||||
|
||||
std::cout
|
||||
<<std::setw(20)<<type_name<<", "<<num_threads<<" thread(s): "
|
||||
<<num_words<<" words, "
|
||||
<<std::setw(9)<<duration_cast<duration<double>>(t2-t1).count()<< " s\n";
|
||||
}
|
||||
|
||||
/* accept a file and parse it with std::string and various flyweight types */
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
using namespace boost::flyweights;
|
||||
using regular_flyweight=flyweight<std::string>;
|
||||
using concurrent_flyweight=flyweight<
|
||||
std::string,
|
||||
concurrent_factory<>,
|
||||
no_locking,
|
||||
no_tracking
|
||||
>;
|
||||
|
||||
if(argc<2){
|
||||
std::cout<<"specify a file\n";
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
std::ifstream is(argv[1]);
|
||||
if(!is)
|
||||
{
|
||||
std::cout<<"can't open "<<argv[1]<<"\n";
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
std::string in(
|
||||
std::istreambuf_iterator<char>(is),std::istreambuf_iterator<char>{});
|
||||
|
||||
parse<std::string>(in,"std::string",1);
|
||||
parse<std::string>(in,"std::string",8);
|
||||
parse<regular_flyweight>(in,"regular flyweight",1);
|
||||
parse<regular_flyweight>(in,"regular flyweight",8);
|
||||
parse<concurrent_flyweight>(in,"concurrent flyweight",1);
|
||||
parse<concurrent_flyweight>(in,"concurrent flyweight",8);
|
||||
}
|
||||
248
include/boost/flyweight/concurrent_factory.hpp
Normal file
248
include/boost/flyweight/concurrent_factory.hpp
Normal file
@@ -0,0 +1,248 @@
|
||||
/* Copyright 2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See http://www.boost.org/libs/flyweight for library home page.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_FLYWEIGHT_CONCURRENT_FACTORY_HPP
|
||||
#define BOOST_FLYWEIGHT_CONCURRENT_FACTORY_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
||||
#include <atomic>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/core/allocator_access.hpp>
|
||||
#include <boost/core/invoke_swap.hpp>
|
||||
#include <boost/flyweight/concurrent_factory_fwd.hpp>
|
||||
#include <boost/flyweight/factory_tag.hpp>
|
||||
#include <boost/flyweight/detail/is_placeholder_expr.hpp>
|
||||
#include <boost/unordered/concurrent_node_set.hpp>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
/* flyweight factory based on boost::concurent_node_set */
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace flyweights{
|
||||
|
||||
namespace concurrent_factory_detail{
|
||||
|
||||
template<typename Entry>
|
||||
struct refcounted_entry:Entry
|
||||
{
|
||||
explicit refcounted_entry(Entry&& x):Entry{std::move(x)}{}
|
||||
refcounted_entry(refcounted_entry&& x):
|
||||
Entry{std::move(static_cast<Entry&>(x))}{}
|
||||
|
||||
long count()const{return ref;}
|
||||
void add_ref()const{++ref;}
|
||||
void release()const{--ref;}
|
||||
|
||||
private:
|
||||
mutable std::atomic_long ref{0};
|
||||
};
|
||||
|
||||
template<typename RefcountedEntry>
|
||||
class refcounted_handle
|
||||
{
|
||||
public:
|
||||
refcounted_handle(const refcounted_handle& x):p{x.p}{p->add_ref();}
|
||||
~refcounted_handle(){p->release();}
|
||||
|
||||
refcounted_handle& operator=(refcounted_handle x)
|
||||
{
|
||||
boost::core::invoke_swap(p,x.p);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const RefcountedEntry& get()const{return *p;}
|
||||
|
||||
private:
|
||||
template<typename,typename,typename,typename,typename>
|
||||
friend class concurrent_factory_class_impl;
|
||||
|
||||
refcounted_handle(const RefcountedEntry* p_):p{p_}
|
||||
{
|
||||
/* Doesn't add ref, refcount already incremented by
|
||||
* concurrent_factory_class_impl before calling this ctor.
|
||||
*/
|
||||
BOOST_ASSERT(p!=nullptr);
|
||||
BOOST_ASSERT(p->count()>0);
|
||||
}
|
||||
|
||||
const RefcountedEntry* p;
|
||||
};
|
||||
|
||||
template<
|
||||
typename Entry,typename Key,
|
||||
typename Hash,typename Pred,typename Allocator
|
||||
>
|
||||
class concurrent_factory_class_impl:public factory_marker
|
||||
{
|
||||
using entry_type=refcounted_entry<Entry>;
|
||||
using unrebound_allocator_type=typename std::conditional<
|
||||
mpl::is_na<Allocator>::value,
|
||||
std::allocator<entry_type>,
|
||||
Allocator
|
||||
>::type;
|
||||
using container_type=boost::concurrent_node_set<
|
||||
entry_type,
|
||||
typename std::conditional<
|
||||
mpl::is_na<Hash>::value,
|
||||
boost::hash<Key>,
|
||||
Hash
|
||||
>::type,
|
||||
typename std::conditional<
|
||||
mpl::is_na<Pred>::value,
|
||||
std::equal_to<Key>,
|
||||
Pred
|
||||
>::type,
|
||||
boost::allocator_rebind_t<unrebound_allocator_type,entry_type>
|
||||
>;
|
||||
|
||||
public:
|
||||
using handle_type=refcounted_handle<entry_type>;
|
||||
|
||||
concurrent_factory_class_impl():gc{[this]{
|
||||
/* Garbage collector. Traverses the container every gc_time and lockedly
|
||||
* erases entries without any external reference.
|
||||
*/
|
||||
|
||||
constexpr auto gc_time=std::chrono::seconds(1);
|
||||
|
||||
for(;;){
|
||||
{
|
||||
std::unique_lock<std::mutex> lk{m};
|
||||
if(cv.wait_for(lk,gc_time,[&]{return stop;}))return;
|
||||
}
|
||||
cont.erase_if([&](const entry_type& x){return !x.count();});
|
||||
}
|
||||
}}
|
||||
{}
|
||||
|
||||
~concurrent_factory_class_impl()
|
||||
{
|
||||
/* shut the garbage collector down */
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lk{m};
|
||||
stop=true;
|
||||
}
|
||||
cv.notify_one();
|
||||
gc.join();
|
||||
}
|
||||
|
||||
/* Instead of insert, concurrent_factory provides the undocumented extension
|
||||
* insert_and_visit, accessible through ADL (see global insert_and_visit
|
||||
* below). This ensures that visitation happens in a locked environment
|
||||
* even if no external locking is specified.
|
||||
*/
|
||||
|
||||
template<typename F>
|
||||
handle_type insert_and_visit(Entry&& x,F f)
|
||||
{
|
||||
const entry_type* p=nullptr;
|
||||
auto g=[&p,&f](const entry_type& x){
|
||||
f(static_cast<const Entry&>(x));
|
||||
x.add_ref();
|
||||
p=std::addressof(x);
|
||||
};
|
||||
|
||||
cont.insert_and_visit(entry_type{std::move(x)},g,g);
|
||||
return {p};
|
||||
}
|
||||
|
||||
void erase(handle_type)
|
||||
{
|
||||
/* unused entries taken care of by garbage collector */
|
||||
}
|
||||
|
||||
static const Entry& entry(handle_type h){return h.get();}
|
||||
|
||||
private:
|
||||
container_type cont;
|
||||
std::mutex m;
|
||||
std::condition_variable cv;
|
||||
bool stop=false;
|
||||
std::thread gc;
|
||||
};
|
||||
|
||||
struct concurrent_factory_class_empty_base:factory_marker{};
|
||||
|
||||
template<
|
||||
typename Entry,typename Key,
|
||||
typename Hash,typename Pred,typename Allocator
|
||||
>
|
||||
struct check_concurrent_factory_class_params{};
|
||||
|
||||
} /* namespace concurrent_factory_detail */
|
||||
|
||||
template<
|
||||
typename Entry,typename Key,
|
||||
typename Hash,typename Pred,typename Allocator
|
||||
>
|
||||
class concurrent_factory_class:
|
||||
/* boost::mpl::apply may instantiate concurrent_factory_class<...> even when
|
||||
* the type is a lambda expression, so we need to guard against the
|
||||
* implementation defining nonsensical typedefs based on placeholder params.
|
||||
*/
|
||||
|
||||
public std::conditional<
|
||||
boost::flyweights::detail::is_placeholder_expression<
|
||||
concurrent_factory_detail::check_concurrent_factory_class_params<
|
||||
Entry,Key,Hash,Pred,Allocator
|
||||
>
|
||||
>::value,
|
||||
concurrent_factory_detail::concurrent_factory_class_empty_base,
|
||||
concurrent_factory_detail::concurrent_factory_class_impl<
|
||||
Entry,Key,Hash,Pred,Allocator
|
||||
>
|
||||
>::type
|
||||
{};
|
||||
|
||||
template<
|
||||
typename Entry,typename Key,
|
||||
typename Hash,typename Pred,typename Allocator,
|
||||
typename F
|
||||
>
|
||||
typename concurrent_factory_class<Entry,Key,Hash,Pred,Allocator>::handle_type
|
||||
insert_and_visit(
|
||||
concurrent_factory_class<Entry,Key,Hash,Pred,Allocator>& fac,Entry&& x,F f)
|
||||
{
|
||||
return fac.insert_and_visit(std::move(x),f);
|
||||
}
|
||||
|
||||
/* concurrent_factory_class specifier */
|
||||
|
||||
template<
|
||||
typename Hash,typename Pred,typename Allocator
|
||||
BOOST_FLYWEIGHT_NOT_A_PLACEHOLDER_EXPRESSION_DEF
|
||||
>
|
||||
struct concurrent_factory:factory_marker
|
||||
{
|
||||
template<typename Entry,typename Key>
|
||||
struct apply:
|
||||
mpl::apply2<
|
||||
concurrent_factory_class<
|
||||
boost::mpl::_1,boost::mpl::_2,Hash,Pred,Allocator
|
||||
>,
|
||||
Entry,Key
|
||||
>
|
||||
{};
|
||||
};
|
||||
|
||||
} /* namespace flyweights */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
40
include/boost/flyweight/concurrent_factory_fwd.hpp
Normal file
40
include/boost/flyweight/concurrent_factory_fwd.hpp
Normal file
@@ -0,0 +1,40 @@
|
||||
/* Copyright 2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See http://www.boost.org/libs/flyweight for library home page.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_FLYWEIGHT_CONCURRENT_FACTORY_FWD_HPP
|
||||
#define BOOST_FLYWEIGHT_CONCURRENT_FACTORY_FWD_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
||||
#include <boost/flyweight/detail/not_placeholder_expr.hpp>
|
||||
#include <boost/mpl/aux_/na.hpp>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace flyweights{
|
||||
|
||||
template<
|
||||
typename Entry,typename Key,
|
||||
typename Hash=mpl::na,typename Pred=mpl::na,typename Allocator=mpl::na
|
||||
>
|
||||
class concurrent_factory_class;
|
||||
|
||||
template<
|
||||
typename Hash=mpl::na,typename Pred=mpl::na,typename Allocator=mpl::na
|
||||
BOOST_FLYWEIGHT_NOT_A_PLACEHOLDER_EXPRESSION
|
||||
>
|
||||
struct concurrent_factory;
|
||||
|
||||
} /* namespace flyweights */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -14,7 +14,7 @@
|
||||
#endif
|
||||
|
||||
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/config/workaround.hpp>
|
||||
#include <boost/flyweight/detail/perfect_fwd.hpp>
|
||||
#include <boost/flyweight/detail/value_tag.hpp>
|
||||
|
||||
@@ -67,11 +67,11 @@ struct default_value_policy:value_marker
|
||||
value_type x;
|
||||
};
|
||||
|
||||
static void construct_value(const rep_type&){}
|
||||
static void copy_value(const rep_type&){}
|
||||
static void key_construct_value(const rep_type&){}
|
||||
static void copy_construct_value(const rep_type&,const value_type&){}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
static void move_value(const rep_type&){}
|
||||
static void move_construct_value(const rep_type&,value_type&&){}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -15,10 +15,11 @@
|
||||
|
||||
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
||||
#include <boost/core/no_exceptions_support.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/config/workaround.hpp>
|
||||
#include <boost/flyweight/detail/perfect_fwd.hpp>
|
||||
#include <boost/mpl/apply.hpp>
|
||||
#include <boost/type_traits/declval.hpp>
|
||||
#include <utility>
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1400))
|
||||
#pragma warning(push)
|
||||
@@ -73,6 +74,49 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/* ADL-based customization point for factories providing the undocumented
|
||||
* insert_and_visit facility rather than regular insert. Default behavior is
|
||||
* to erase the entry if visitation throws.
|
||||
*/
|
||||
|
||||
template<typename Factory,typename Entry,typename F>
|
||||
typename Factory::handle_type
|
||||
insert_and_visit(Factory& fac,const Entry& x,F f)
|
||||
{
|
||||
typedef typename Factory::handle_type handle_type;
|
||||
|
||||
handle_type h(fac.insert(x));
|
||||
BOOST_TRY{
|
||||
f(fac.entry(h));
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
fac().erase(h);
|
||||
BOOST_RETHROW;
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
return h;
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template<typename Factory,typename Entry,typename F>
|
||||
typename Factory::handle_type
|
||||
insert_and_visit(Factory& fac,Entry&& x,F f)
|
||||
{
|
||||
typedef typename Factory::handle_type handle_type;
|
||||
|
||||
handle_type h(fac.insert(std::forward<Entry>(x)));
|
||||
BOOST_TRY{
|
||||
f(fac.entry(h));
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
fac.erase(h);
|
||||
BOOST_RETHROW;
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
return h;
|
||||
}
|
||||
#endif
|
||||
|
||||
template<
|
||||
typename ValuePolicy,typename Tag,typename TrackingPolicy,
|
||||
typename FactorySpecifier,typename LockingPolicy,typename HolderSpecifier
|
||||
@@ -177,27 +221,56 @@ private:
|
||||
holder_arg
|
||||
>::type holder_type;
|
||||
|
||||
/* [key|copy|move]_construct_value: poor-man's pre-C++11 lambdas */
|
||||
|
||||
struct key_construct_value
|
||||
{
|
||||
void operator()(const entry_type& e)const
|
||||
{
|
||||
ValuePolicy::key_construct_value(static_cast<const rep_type&>(e));
|
||||
}
|
||||
};
|
||||
|
||||
struct copy_construct_value
|
||||
{
|
||||
copy_construct_value(const value_type& x_):x(x_){}
|
||||
|
||||
void operator()(const entry_type& e)const
|
||||
{
|
||||
ValuePolicy::copy_construct_value(static_cast<const rep_type&>(e),x);
|
||||
}
|
||||
|
||||
const value_type& x;
|
||||
};
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
struct move_construct_value
|
||||
{
|
||||
move_construct_value(value_type&& x_):x(x_){}
|
||||
|
||||
void operator()(const entry_type& e)const
|
||||
{
|
||||
ValuePolicy::move_construct_value(
|
||||
static_cast<const rep_type&>(e),std::move(x));
|
||||
}
|
||||
|
||||
value_type& x;
|
||||
};
|
||||
#endif
|
||||
|
||||
static handle_type insert_rep(const rep_type& x)
|
||||
{
|
||||
init();
|
||||
entry_type e(x);
|
||||
lock_type lock(mutex());(void)lock;
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
base_handle_type h(factory().insert(std::move(e)));
|
||||
#else
|
||||
base_handle_type h(factory().insert(e));
|
||||
#endif
|
||||
|
||||
BOOST_TRY{
|
||||
ValuePolicy::construct_value(
|
||||
static_cast<const rep_type&>(entry(h)));
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
factory().erase(h);
|
||||
BOOST_RETHROW;
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
return static_cast<handle_type>(h);
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
return static_cast<handle_type>(
|
||||
insert_and_visit(factory(),std::move(e),key_construct_value()));
|
||||
#else
|
||||
return static_cast<handle_type>(
|
||||
insert_and_visit(factory(),e,key_construct_value()));
|
||||
#endif
|
||||
}
|
||||
|
||||
static handle_type insert_value(const value_type& x)
|
||||
@@ -207,21 +280,12 @@ private:
|
||||
lock_type lock(mutex());(void)lock;
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
base_handle_type h(factory().insert(std::move(e)));
|
||||
return static_cast<handle_type>(
|
||||
insert_and_visit(factory(),std::move(e),copy_construct_value(x)));
|
||||
#else
|
||||
base_handle_type h(factory().insert(e));
|
||||
return static_cast<handle_type>(
|
||||
insert_and_visit(factory(),e,copy_construct_value(x)));
|
||||
#endif
|
||||
|
||||
BOOST_TRY{
|
||||
ValuePolicy::copy_value(
|
||||
static_cast<const rep_type&>(entry(h)));
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
factory().erase(h);
|
||||
BOOST_RETHROW;
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
return static_cast<handle_type>(h);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
@@ -230,18 +294,9 @@ private:
|
||||
init();
|
||||
entry_type e(std::move(x));
|
||||
lock_type lock(mutex());(void)lock;
|
||||
base_handle_type h(factory().insert(std::move(e)));
|
||||
|
||||
BOOST_TRY{
|
||||
ValuePolicy::construct_value(
|
||||
static_cast<const rep_type&>(entry(h)));
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
factory().erase(h);
|
||||
BOOST_RETHROW;
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
return static_cast<handle_type>(h);
|
||||
return static_cast<handle_type>(
|
||||
insert_and_visit(factory(),std::move(e),key_construct_value()));
|
||||
}
|
||||
|
||||
static handle_type insert_value(value_type&& x)
|
||||
@@ -249,17 +304,10 @@ private:
|
||||
init();
|
||||
entry_type e(rep_type(std::move(x)));
|
||||
lock_type lock(mutex());(void)lock;
|
||||
base_handle_type h(factory().insert(std::move(e)));
|
||||
BOOST_TRY{
|
||||
ValuePolicy::move_value(
|
||||
static_cast<const rep_type&>(entry(h)));
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
factory().erase(h);
|
||||
BOOST_RETHROW;
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
return static_cast<handle_type>(h);
|
||||
|
||||
return static_cast<handle_type>(
|
||||
insert_and_visit(
|
||||
factory(),std::move(e),move_construct_value(std::move(x))));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2006-2018 Joaquin M Lopez Munoz.
|
||||
/* Copyright 2006-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -27,7 +27,7 @@
|
||||
*/
|
||||
|
||||
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/config/workaround.hpp>
|
||||
|
||||
#if BOOST_WORKAROUND(__GNUC__, <4)||\
|
||||
BOOST_WORKAROUND(__GNUC__,==4)&&(__GNUC_MINOR__<2)||\
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2006-2023 Joaquin M Lopez Munoz.
|
||||
/* Copyright 2006-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -60,7 +60,7 @@ private:
|
||||
|
||||
} /* namespace boost */
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
/* code shamelessly ripped from <boost/detail/lwm_pthreads.hpp> */
|
||||
/* code shamelessly ripped from <boost/smart_ptr/detail/lwm_pthreads.hpp> */
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
|
||||
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
||||
#include <algorithm>
|
||||
#include <boost/config/workaround.hpp>
|
||||
#include <boost/core/addressof.hpp>
|
||||
#include <boost/core/invoke_swap.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/flyweight/detail/default_value_policy.hpp>
|
||||
#include <boost/flyweight/detail/flyweight_core.hpp>
|
||||
#include <boost/flyweight/detail/perfect_fwd.hpp>
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
#endif
|
||||
|
||||
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
||||
#include <boost/config/workaround.hpp>
|
||||
#include <boost/detail/templated_streams.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/parameter/parameters.hpp>
|
||||
#include <boost/preprocessor/punctuation/comma.hpp>
|
||||
#include <iosfwd>
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
#endif
|
||||
|
||||
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config/workaround.hpp>
|
||||
#include <boost/flyweight/detail/perfect_fwd.hpp>
|
||||
#include <boost/flyweight/detail/value_tag.hpp>
|
||||
#include <boost/flyweight/key_value_fwd.hpp>
|
||||
@@ -47,7 +48,7 @@ namespace flyweights{
|
||||
namespace detail{
|
||||
|
||||
template<typename Key,typename Value,typename KeyFromValue>
|
||||
struct optimized_key_value:value_marker
|
||||
struct variant_key_value:value_marker
|
||||
{
|
||||
typedef Key key_type;
|
||||
typedef Value value_type;
|
||||
@@ -58,9 +59,9 @@ struct optimized_key_value:value_marker
|
||||
/* template ctors */
|
||||
|
||||
#define BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY(args) \
|
||||
:value_ptr(0) \
|
||||
:value_cted(false) \
|
||||
{ \
|
||||
new(spc_ptr())key_type(BOOST_FLYWEIGHT_FORWARD(args)); \
|
||||
new(key_ptr())key_type(BOOST_FLYWEIGHT_FORWARD(args)); \
|
||||
}
|
||||
|
||||
BOOST_FLYWEIGHT_PERFECT_FWD(
|
||||
@@ -69,55 +70,61 @@ struct optimized_key_value:value_marker
|
||||
|
||||
#undef BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY
|
||||
|
||||
rep_type(const rep_type& x):value_ptr(x.value_ptr)
|
||||
rep_type(const rep_type& x):value_cted(false)
|
||||
{
|
||||
if(!x.value_ptr)new(key_ptr())key_type(*x.key_ptr());
|
||||
if(!x.value_cted)new(key_ptr())key_type(*x.key_ptr());
|
||||
else new(key_ptr())key_type(key_from_value(*x.value_ptr()));
|
||||
}
|
||||
|
||||
rep_type(const value_type& x):value_ptr(&x){}
|
||||
rep_type(const value_type& x):value_cted(false)
|
||||
{
|
||||
new(key_ptr())key_type(key_from_value(x));
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
rep_type(rep_type&& x):value_ptr(x.value_ptr)
|
||||
rep_type(rep_type&& x):value_cted(false)
|
||||
{
|
||||
if(!x.value_ptr)new(key_ptr())key_type(std::move(*x.key_ptr()));
|
||||
if(!x.value_cted)new(key_ptr())key_type(std::move(*x.key_ptr()));
|
||||
else new(key_ptr())key_type(key_from_value(*x.value_ptr()));
|
||||
}
|
||||
|
||||
rep_type(value_type&& x):value_ptr(&x){}
|
||||
rep_type(value_type&& x):value_cted(false)
|
||||
{
|
||||
new(key_ptr())key_type(key_from_value(x));
|
||||
}
|
||||
#endif
|
||||
|
||||
~rep_type()
|
||||
{
|
||||
if(!value_ptr) key_ptr()->~key_type();
|
||||
else if(value_cted())value_ptr->~value_type();
|
||||
if(value_cted)value_ptr()->~value_type();
|
||||
else key_ptr()->~key_type();
|
||||
}
|
||||
|
||||
operator const key_type&()const
|
||||
BOOST_NOEXCEPT_IF(noexcept(
|
||||
boost::declval<KeyFromValue>()(boost::declval<const value_type&>())))
|
||||
{
|
||||
if(value_ptr)return key_from_value(*value_ptr);
|
||||
else return *key_ptr();
|
||||
if(value_cted)return key_from_value(*value_ptr());
|
||||
else return *key_ptr();
|
||||
}
|
||||
|
||||
operator const value_type&()const
|
||||
{
|
||||
/* This is always called after construct_value() or copy_value(),
|
||||
* so we access spc directly rather than through value_ptr to
|
||||
* save us an indirection.
|
||||
*/
|
||||
|
||||
return *static_cast<value_type*>(spc_ptr());
|
||||
BOOST_ASSERT(value_cted);
|
||||
return *value_ptr();
|
||||
}
|
||||
|
||||
private:
|
||||
friend struct optimized_key_value;
|
||||
|
||||
void* spc_ptr()const{return static_cast<void*>(&spc);}
|
||||
bool value_cted()const{return value_ptr==spc_ptr();}
|
||||
friend struct variant_key_value;
|
||||
|
||||
key_type* key_ptr()const
|
||||
{
|
||||
return static_cast<key_type*>(static_cast<void*>(&spc));
|
||||
return static_cast<key_type*>(static_cast<void*>(&key_spc));
|
||||
}
|
||||
|
||||
value_type* value_ptr()const
|
||||
{
|
||||
return static_cast<value_type*>(static_cast<void*>(&value_spc));
|
||||
}
|
||||
|
||||
static const key_type& key_from_value(const value_type& x)
|
||||
@@ -126,68 +133,66 @@ struct optimized_key_value:value_marker
|
||||
return k(x);
|
||||
}
|
||||
|
||||
void construct_value()const
|
||||
void key_construct_value()const
|
||||
{
|
||||
if(!value_cted()){
|
||||
/* value_ptr must be ==0, oherwise copy_value would have been called */
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
key_type k(std::move(*key_ptr()));
|
||||
#else
|
||||
key_type k(*key_ptr());
|
||||
#endif
|
||||
|
||||
if(!value_cted){
|
||||
new(value_ptr())value_type(*key_ptr());
|
||||
key_ptr()->~key_type();
|
||||
value_ptr= /* guarantees key won't be re-dted at ~rep_type if the */
|
||||
static_cast<value_type*>(spc_ptr())+1; /* next statement throws */
|
||||
value_ptr=new(spc_ptr())value_type(k);
|
||||
value_cted=true;
|
||||
}
|
||||
}
|
||||
|
||||
void copy_value()const
|
||||
void copy_construct_value(const value_type& x)const
|
||||
{
|
||||
if(!value_cted())value_ptr=new(spc_ptr())value_type(*value_ptr);
|
||||
if(!value_cted){
|
||||
new(value_ptr())value_type(x);
|
||||
key_ptr()->~key_type();
|
||||
value_cted=true;
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
void move_value()const
|
||||
void move_construct_value(value_type&& x)const
|
||||
{
|
||||
if(!value_cted())value_ptr=
|
||||
new(spc_ptr())value_type(std::move(const_cast<value_type&>(*value_ptr)));
|
||||
if(!value_cted){
|
||||
new(value_ptr())value_type(std::move(x));
|
||||
key_ptr()->~key_type();
|
||||
value_cted=true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
mutable typename boost::aligned_storage<
|
||||
(sizeof(key_type)>sizeof(value_type))?
|
||||
sizeof(key_type):sizeof(value_type),
|
||||
(boost::alignment_of<key_type>::value >
|
||||
boost::alignment_of<value_type>::value)?
|
||||
boost::alignment_of<key_type>::value:
|
||||
boost::alignment_of<value_type>::value
|
||||
>::type spc;
|
||||
mutable const value_type* value_ptr;
|
||||
sizeof(key_type),
|
||||
boost::alignment_of<key_type>::value
|
||||
>::type key_spc;
|
||||
mutable typename boost::aligned_storage<
|
||||
sizeof(value_type),
|
||||
boost::alignment_of<value_type>::value
|
||||
>::type value_spc;
|
||||
mutable bool value_cted;
|
||||
};
|
||||
|
||||
static void construct_value(const rep_type& r)
|
||||
static void key_construct_value(const rep_type& r)
|
||||
{
|
||||
r.construct_value();
|
||||
r.key_construct_value();
|
||||
}
|
||||
|
||||
static void copy_value(const rep_type& r)
|
||||
static void copy_construct_value(const rep_type& r,const value_type& x)
|
||||
{
|
||||
r.copy_value();
|
||||
r.copy_construct_value(x);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
static void move_value(const rep_type& r)
|
||||
static void move_construct_value(const rep_type& r,value_type&& x)
|
||||
{
|
||||
r.move_value();
|
||||
r.move_construct_value(std::move(x));
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template<typename Key,typename Value>
|
||||
struct regular_key_value:value_marker
|
||||
struct product_key_value:value_marker
|
||||
{
|
||||
typedef Key key_type;
|
||||
typedef Value value_type;
|
||||
@@ -205,11 +210,11 @@ struct regular_key_value:value_marker
|
||||
* variadic temmplate ctor below fails to value-initialize key.
|
||||
*/
|
||||
|
||||
rep_type():key(),value_ptr(0){}
|
||||
rep_type():key(),value_cted(false){}
|
||||
#endif
|
||||
|
||||
#define BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY(args) \
|
||||
:key(BOOST_FLYWEIGHT_FORWARD(args)),value_ptr(0){}
|
||||
:key(BOOST_FLYWEIGHT_FORWARD(args)),value_cted(false){}
|
||||
|
||||
BOOST_FLYWEIGHT_PERFECT_FWD(
|
||||
explicit rep_type,
|
||||
@@ -217,34 +222,34 @@ struct regular_key_value:value_marker
|
||||
|
||||
#undef BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY
|
||||
|
||||
rep_type(const rep_type& x):key(x.key),value_ptr(0){}
|
||||
rep_type(const rep_type& x):key(x.key),value_cted(false){}
|
||||
rep_type(const value_type&):key(no_key_from_value_failure()){}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
rep_type(rep_type&& x):key(std::move(x.key)),value_ptr(0){}
|
||||
rep_type(rep_type&& x):key(std::move(x.key)),value_cted(false){}
|
||||
rep_type(value_type&&):key(no_key_from_value_failure()){}
|
||||
#endif
|
||||
|
||||
~rep_type()
|
||||
{
|
||||
if(value_ptr)value_ptr->~value_type();
|
||||
if(value_cted)value_ptr()->~value_type();
|
||||
}
|
||||
|
||||
operator const key_type&()const BOOST_NOEXCEPT{return key;}
|
||||
|
||||
operator const value_type&()const
|
||||
{
|
||||
/* This is always called after construct_value(),so we access spc
|
||||
* directly rather than through value_ptr to save us an indirection.
|
||||
*/
|
||||
|
||||
return *static_cast<value_type*>(spc_ptr());
|
||||
BOOST_ASSERT(value_cted);
|
||||
return *value_ptr();
|
||||
}
|
||||
|
||||
private:
|
||||
friend struct regular_key_value;
|
||||
friend struct product_key_value;
|
||||
|
||||
void* spc_ptr()const{return static_cast<void*>(&spc);}
|
||||
value_type* value_ptr()const
|
||||
{
|
||||
return static_cast<value_type*>(static_cast<void*>(&value_spc));
|
||||
}
|
||||
|
||||
struct no_key_from_value_failure
|
||||
{
|
||||
@@ -256,33 +261,36 @@ struct regular_key_value:value_marker
|
||||
operator const key_type&()const;
|
||||
};
|
||||
|
||||
void construct_value()const
|
||||
void key_construct_value()const
|
||||
{
|
||||
if(!value_ptr)value_ptr=new(spc_ptr())value_type(key);
|
||||
if(!value_cted){
|
||||
new(value_ptr())value_type(key);
|
||||
value_cted=true;
|
||||
}
|
||||
}
|
||||
|
||||
key_type key;
|
||||
mutable typename boost::aligned_storage<
|
||||
sizeof(value_type),
|
||||
boost::alignment_of<value_type>::value
|
||||
>::type spc;
|
||||
mutable const value_type* value_ptr;
|
||||
>::type value_spc;
|
||||
mutable bool value_cted;
|
||||
};
|
||||
|
||||
static void construct_value(const rep_type& r)
|
||||
static void key_construct_value(const rep_type& r)
|
||||
{
|
||||
r.construct_value();
|
||||
r.key_construct_value();
|
||||
}
|
||||
|
||||
/* copy_value() and move_value() can't really ever be called, provided to avoid
|
||||
* compile errors (it is the no_key_from_value_failure compile error we want to
|
||||
* appear in these cases).
|
||||
/* [copy|move]_construct_value() can't really ever be called, provided to
|
||||
* avoid compile errors (it is the no_key_from_value_failure compile error
|
||||
* we want to appear in these cases).
|
||||
*/
|
||||
|
||||
static void copy_value(const rep_type&){}
|
||||
static void copy_construct_value(const rep_type&,const value_type&){}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
static void move_value(const rep_type&){}
|
||||
static void move_construct_value(const rep_type&,value_type&&){}
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -292,8 +300,8 @@ template<typename Key,typename Value,typename KeyFromValue>
|
||||
struct key_value:
|
||||
mpl::if_<
|
||||
is_same<KeyFromValue,no_key_from_value>,
|
||||
detail::regular_key_value<Key,Value>,
|
||||
detail::optimized_key_value<Key,Value,KeyFromValue>
|
||||
detail::product_key_value<Key,Value>,
|
||||
detail::variant_key_value<Key,Value,KeyFromValue>
|
||||
>::type
|
||||
{};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2006-2022 Joaquin M Lopez Munoz.
|
||||
/* Copyright 2006-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -15,11 +15,11 @@
|
||||
|
||||
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
||||
#include <algorithm>
|
||||
#include <boost/config/workaround.hpp>
|
||||
#include <boost/core/invoke_swap.hpp>
|
||||
#include <boost/detail/atomic_count.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/flyweight/refcounted_fwd.hpp>
|
||||
#include <boost/flyweight/tracking_tag.hpp>
|
||||
#include <boost/smart_ptr/detail/atomic_count.hpp>
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
#include <utility>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Boost.Flyweight tests Jamfile
|
||||
#
|
||||
# Copyright 2006-2014 Joaquín M López Muñoz.
|
||||
# Copyright 2006-2024 Joaquín M López Muñoz.
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -14,22 +14,23 @@ project
|
||||
;
|
||||
|
||||
test-suite "flyweight" :
|
||||
[ run test_assoc_cont_factory.cpp test_assoc_cont_fact_main.cpp ]
|
||||
[ run test_basic.cpp test_basic_main.cpp ]
|
||||
[ run test_custom_factory.cpp test_custom_factory_main.cpp ]
|
||||
[ run test_init.cpp test_init_main.cpp ]
|
||||
[ run test_assoc_cont_factory.cpp test_assoc_cont_fact_main.cpp ]
|
||||
[ run test_basic.cpp test_basic_main.cpp ]
|
||||
[ run test_concurrent_factory.cpp test_concurrent_factory_main.cpp ]
|
||||
[ run test_custom_factory.cpp test_custom_factory_main.cpp ]
|
||||
[ run test_init.cpp test_init_main.cpp ]
|
||||
[ run test_intermod_holder.cpp test_intermod_holder_main.cpp
|
||||
intermod_holder_dll
|
||||
: # command line
|
||||
: # input files
|
||||
: # requirements
|
||||
<threading>multi ]
|
||||
[ run test_multictor.cpp test_multictor_main.cpp ]
|
||||
[ run test_no_locking.cpp test_no_locking_main.cpp ]
|
||||
[ run test_no_tracking.cpp test_no_tracking_main.cpp ]
|
||||
<threading>multi ]
|
||||
[ run test_multictor.cpp test_multictor_main.cpp ]
|
||||
[ run test_no_locking.cpp test_no_locking_main.cpp ]
|
||||
[ run test_no_tracking.cpp test_no_tracking_main.cpp ]
|
||||
[ run test_serialization.cpp test_serialization_main.cpp
|
||||
/boost/serialization//boost_serialization/<link>static ]
|
||||
[ run test_set_factory.cpp test_set_factory_main.cpp ]
|
||||
/boost/serialization//boost_serialization/<link>static ]
|
||||
[ run test_set_factory.cpp test_set_factory_main.cpp ]
|
||||
;
|
||||
|
||||
lib intermod_holder_dll : intermod_holder_dll.cpp :
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Classes for Boost.Flyweight key-value tests.
|
||||
*
|
||||
* Copyright 2006-2014 Joaquin M Lopez Munoz.
|
||||
* Copyright 2006-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -90,11 +90,17 @@ struct throwing_value_exception{};
|
||||
|
||||
struct throwing_value
|
||||
{
|
||||
throwing_value():n(0){}
|
||||
throwing_value(const throwing_value&){throw throwing_value_exception();}
|
||||
throwing_value(bool does_throw_=true):n(0),does_throw(does_throw_){}
|
||||
|
||||
throwing_value(const throwing_value& x):n(x.n),does_throw(x.does_throw)
|
||||
{
|
||||
if(does_throw)throw throwing_value_exception();
|
||||
}
|
||||
|
||||
throwing_value(int){throw throwing_value_exception();}
|
||||
|
||||
int n;
|
||||
int n;
|
||||
bool does_throw;
|
||||
};
|
||||
|
||||
struct from_throwing_value_to_int
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Boost.Flyweight test suite.
|
||||
*
|
||||
* Copyright 2006-2014 Joaquin M Lopez Munoz.
|
||||
* Copyright 2006-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -9,9 +9,10 @@
|
||||
*/
|
||||
|
||||
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include "test_assoc_cont_factory.hpp"
|
||||
#include "test_basic.hpp"
|
||||
#include "test_concurrent_factory.hpp"
|
||||
#include "test_custom_factory.hpp"
|
||||
#include "test_intermod_holder.hpp"
|
||||
#include "test_init.hpp"
|
||||
@@ -25,6 +26,7 @@ int main()
|
||||
{
|
||||
test_assoc_container_factory();
|
||||
test_basic();
|
||||
test_concurrent_factory();
|
||||
test_custom_factory();
|
||||
test_init();
|
||||
test_intermodule_holder();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Boost.Flyweight test of assoc_container_factory.
|
||||
*
|
||||
* Copyright 2006-2008 Joaquin M Lopez Munoz.
|
||||
* Copyright 2006-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -8,7 +8,7 @@
|
||||
* See http://www.boost.org/libs/flyweight for library home page.
|
||||
*/
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include "test_assoc_cont_factory.hpp"
|
||||
|
||||
int main()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Boost.Flyweight basic test.
|
||||
*
|
||||
* Copyright 2006-2008 Joaquin M Lopez Munoz.
|
||||
* Copyright 2006-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -8,7 +8,7 @@
|
||||
* See http://www.boost.org/libs/flyweight for library home page.
|
||||
*/
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include "test_basic.hpp"
|
||||
|
||||
int main()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Boost.Flyweight basic test template.
|
||||
*
|
||||
* Copyright 2006-2023 Joaquin M Lopez Munoz.
|
||||
* Copyright 2006-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -16,7 +16,7 @@
|
||||
#endif
|
||||
|
||||
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/flyweight/key_value.hpp>
|
||||
#include <boost/mpl/apply.hpp>
|
||||
#include <boost/utility/value_init.hpp>
|
||||
@@ -298,6 +298,9 @@ void test_basic_template(BOOST_EXPLICIT_TEMPLATE_TYPE(FlyweightSpecifier))
|
||||
throwing_flyweight fw=throwing_flyweight(throwing_value());
|
||||
(void)fw;
|
||||
}catch(const throwing_value_exception&){}
|
||||
throwing_flyweight fw=throwing_flyweight(
|
||||
throwing_value(false /* doesn't throw */));
|
||||
(void)fw.get();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
91
test/test_concurrent_factory.cpp
Normal file
91
test/test_concurrent_factory.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
/* Boost.Flyweight test of concurrent_factory.
|
||||
*
|
||||
* Copyright 2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See http://www.boost.org/libs/flyweight for library home page.
|
||||
*/
|
||||
|
||||
#include "test_concurrent_factory.hpp"
|
||||
|
||||
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
||||
#include <boost/config/workaround.hpp>
|
||||
#include <boost/flyweight/flyweight.hpp>
|
||||
#include <boost/flyweight/concurrent_factory.hpp>
|
||||
#include <boost/flyweight/no_locking.hpp>
|
||||
#include <boost/flyweight/no_tracking.hpp>
|
||||
#include <boost/flyweight/refcounted.hpp>
|
||||
#include <boost/flyweight/simple_locking.hpp>
|
||||
#include <boost/flyweight/static_holder.hpp>
|
||||
#include <functional>
|
||||
#include "test_basic_template.hpp"
|
||||
|
||||
using namespace boost::flyweights;
|
||||
|
||||
struct concurrent_factory_flyweight_specifier1
|
||||
{
|
||||
template<typename T>
|
||||
struct apply
|
||||
{
|
||||
typedef flyweight<T,concurrent_factory<> > type;
|
||||
};
|
||||
};
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC,<1930)
|
||||
/* Boost.MPL spuriously and failingly instantiates std::hash<boost::mpl::_n>
|
||||
* in msvc 14.0 under some circumstances.
|
||||
*/
|
||||
|
||||
#define STD_HASH boost::hash
|
||||
#else
|
||||
#define STD_HASH std::hash
|
||||
#endif
|
||||
|
||||
struct concurrent_factory_flyweight_specifier2
|
||||
{
|
||||
template<typename T>
|
||||
struct apply
|
||||
{
|
||||
typedef flyweight<
|
||||
T,
|
||||
static_holder_class<boost::mpl::_1>,
|
||||
no_locking,
|
||||
no_tracking,
|
||||
concurrent_factory_class<
|
||||
boost::mpl::_1,boost::mpl::_2,
|
||||
STD_HASH<boost::mpl::_2>,
|
||||
std::equal_to<boost::mpl::_2>,
|
||||
std::allocator<boost::mpl::_1>
|
||||
>
|
||||
> type;
|
||||
};
|
||||
};
|
||||
|
||||
struct concurrent_factory_flyweight_specifier3
|
||||
{
|
||||
template<typename T>
|
||||
struct apply
|
||||
{
|
||||
typedef flyweight<
|
||||
T,
|
||||
concurrent_factory<
|
||||
STD_HASH<boost::mpl::_2>,
|
||||
std::equal_to<boost::mpl::_2>,
|
||||
std::allocator<boost::mpl::_1>
|
||||
>,
|
||||
static_holder_class<boost::mpl::_1>,
|
||||
no_locking,
|
||||
no_tracking,
|
||||
tag<char>
|
||||
> type;
|
||||
};
|
||||
};
|
||||
|
||||
void test_concurrent_factory()
|
||||
{
|
||||
test_basic_template<concurrent_factory_flyweight_specifier1>();
|
||||
test_basic_template<concurrent_factory_flyweight_specifier2>();
|
||||
test_basic_template<concurrent_factory_flyweight_specifier3>();
|
||||
}
|
||||
11
test/test_concurrent_factory.hpp
Normal file
11
test/test_concurrent_factory.hpp
Normal file
@@ -0,0 +1,11 @@
|
||||
/* Boost.Flyweight test of concurrent_factory.
|
||||
*
|
||||
* Copyright 2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See http://www.boost.org/libs/flyweight for library home page.
|
||||
*/
|
||||
|
||||
void test_concurrent_factory();
|
||||
18
test/test_concurrent_factory_main.cpp
Normal file
18
test/test_concurrent_factory_main.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/* Boost.Flyweight test of concurrent_factory.
|
||||
*
|
||||
* Copyright 2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See http://www.boost.org/libs/flyweight for library home page.
|
||||
*/
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include "test_concurrent_factory.hpp"
|
||||
|
||||
int main()
|
||||
{
|
||||
test_concurrent_factory();
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Boost.Flyweight test of a custom factory.
|
||||
*
|
||||
* Copyright 2006-2008 Joaquin M Lopez Munoz.
|
||||
* Copyright 2006-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -8,7 +8,7 @@
|
||||
* See http://www.boost.org/libs/flyweight for library home page.
|
||||
*/
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include "test_custom_factory.hpp"
|
||||
|
||||
int main()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Boost.Flyweight test of static data initialization facilities.
|
||||
*
|
||||
* Copyright 2006-2019 Joaquin M Lopez Munoz.
|
||||
* Copyright 2006-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "test_init.hpp"
|
||||
|
||||
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/flyweight.hpp>
|
||||
|
||||
using namespace boost::flyweights;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Boost.Flyweight test of static data initialization facilities.
|
||||
*
|
||||
* Copyright 2006-2008 Joaquin M Lopez Munoz.
|
||||
* Copyright 2006-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -8,7 +8,7 @@
|
||||
* See http://www.boost.org/libs/flyweight for library home page.
|
||||
*/
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include "test_init.hpp"
|
||||
|
||||
int main()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Boost.Flyweight test of intermodule_holder.
|
||||
*
|
||||
* Copyright 2006-2008 Joaquin M Lopez Munoz.
|
||||
* Copyright 2006-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -8,7 +8,7 @@
|
||||
* See http://www.boost.org/libs/flyweight for library home page.
|
||||
*/
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include "test_intermod_holder.hpp"
|
||||
|
||||
int main()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Boost.Flyweight test of flyweight forwarding and initializer_list ctors.
|
||||
*
|
||||
* Copyright 2006-2015 Joaquin M Lopez Munoz.
|
||||
* Copyright 2006-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -11,8 +11,8 @@
|
||||
#include "test_multictor.hpp"
|
||||
|
||||
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/config/workaround.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/flyweight.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Boost.Flyweight test of flyweight forwarding ctors.
|
||||
*
|
||||
* Copyright 2006-2008 Joaquin M Lopez Munoz.
|
||||
* Copyright 2006-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -8,7 +8,7 @@
|
||||
* See http://www.boost.org/libs/flyweight for library home page.
|
||||
*/
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include "test_multictor.hpp"
|
||||
|
||||
int main()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Boost.Flyweight test of no_locking.
|
||||
*
|
||||
* Copyright 2006-2008 Joaquin M Lopez Munoz.
|
||||
* Copyright 2006-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -8,7 +8,7 @@
|
||||
* See http://www.boost.org/libs/flyweight for library home page.
|
||||
*/
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include "test_no_locking.hpp"
|
||||
|
||||
int main()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Boost.Flyweight test of no_tracking.
|
||||
*
|
||||
* Copyright 2006-2008 Joaquin M Lopez Munoz.
|
||||
* Copyright 2006-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -8,7 +8,7 @@
|
||||
* See http://www.boost.org/libs/flyweight for library home page.
|
||||
*/
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include "test_no_tracking.hpp"
|
||||
|
||||
int main()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Boost.Flyweight test of serialization capabilities.
|
||||
*
|
||||
* Copyright 2006-2014 Joaquin M Lopez Munoz.
|
||||
* Copyright 2006-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -8,7 +8,7 @@
|
||||
* See http://www.boost.org/libs/flyweight for library home page.
|
||||
*/
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include "test_serialization.hpp"
|
||||
|
||||
int main()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Boost.Flyweight test template for serialization capabilities.
|
||||
*
|
||||
* Copyright 2006-2014 Joaquin M Lopez Munoz.
|
||||
* Copyright 2006-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
||||
#include <boost/archive/text_oarchive.hpp>
|
||||
#include <boost/archive/text_iarchive.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/flyweight/key_value.hpp>
|
||||
#include <boost/flyweight/serialize.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Boost.Flyweight test of set_factory.
|
||||
*
|
||||
* Copyright 2006-2008 Joaquin M Lopez Munoz.
|
||||
* Copyright 2006-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -8,7 +8,7 @@
|
||||
* See http://www.boost.org/libs/flyweight for library home page.
|
||||
*/
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include "test_set_factory.hpp"
|
||||
|
||||
int main()
|
||||
|
||||
Reference in New Issue
Block a user