Sync from upstream.

This commit is contained in:
Rene Rivera
2024-09-27 20:00:13 -05:00
38 changed files with 1112 additions and 214 deletions

View File

@@ -39,6 +39,7 @@ Tests
<li><a href="#example6">Example 6: serialization</a></li> <li><a href="#example6">Example 6: serialization</a></li>
<li><a href="#example7">Example 7: performance comparison</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="#example8">Example 8: custom factory</a></li>
<li><a href="#example9">Example 9: parallel tokenization</a></li>
</ul> </ul>
<h2><a name="example1">Example 1: basic usage</a></h2> <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. by Boost.Flyweight, so helping the user visualize factory usage patterns.
</p> </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&lt;std::string&gt;</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> <hr>
<div class="prev_link"><a href="performance.html"><img src="prev.gif" alt="performance" border="0"><br> <div class="prev_link"><a href="performance.html"><img src="prev.gif" alt="performance" border="0"><br>
@@ -272,9 +309,9 @@ Tests
<br> <br>
<p>Revised October 14th 2014</p> <p>Revised September 21th 2024</p>
<p>&copy; Copyright 2006-2014 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz. <p>&copy; Copyright 2006-2024 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt"> 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"> LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">

View File

@@ -49,6 +49,16 @@ Holders
<li><a href="#hashed_factory">Class template <code>hashed_factory</code></a></li> <li><a href="#hashed_factory">Class template <code>hashed_factory</code></a></li>
</ul> </ul>
</li> </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 <li><a href="#set_factory_fwd_synopsis">Header
<code>"boost/flyweight/set_factory_fwd.hpp"</code> synopsis</a> <code>"boost/flyweight/set_factory_fwd.hpp"</code> synopsis</a>
</li> </li>
@@ -338,6 +348,142 @@ Placeholder Expressions</code></a> resolving to the actual types used by
<code>hashed_factory_class</code>. <code>hashed_factory_class</code>.
</p> </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>&lt;</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>&gt;</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>&lt;</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>&gt;</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>&lt;</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>&gt;</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>&amp;</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>&amp;</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&lt;std::size_t&gt;::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&lt;Key&gt;</code></a>
and <code>std::equal_to&lt;Key&gt;</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&lt;Entry&gt;</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>&lt;</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>&gt;</span>
<span class=keyword>struct</span> <span class=identifier>concurrent_factory</span><span class=special>;</span>
</pre></blockquote>
<p>
<code>concurrent_factory&lt;Hash,Pred,Allocator&gt;</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>&lt;</span>
<span class=identifier>concurrent_factory</span><span class=special>&lt;</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>&gt;,</span>
<span class=identifier>Entry</span><span class=special>,</span><span class=identifier>Key</span>
<span class=special>&gt;::</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>&lt;</span>
<span class=identifier>concurrent_factory_class</span><span class=special>&lt;</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>&gt;,</span>
<span class=identifier>Entry</span><span class=special>,</span><span class=identifier>Key</span>
<span class=special>&gt;::</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 <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> <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> <br>
<p>Revised April 24th 2019</p> <p>Revised September 20th 2024</p>
<p>&copy; Copyright 2006-2019 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz. <p>&copy; Copyright 2006-2024 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../../LICENSE_1_0.txt"> 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"> LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">

View File

@@ -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#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_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#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_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#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> <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> <br>
<p>Revised September 1st 2014</p> <p>Revised September 17th 2024</p>
<p>&copy; Copyright 2006-2014 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz. <p>&copy; Copyright 2006-2024 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../../LICENSE_1_0.txt"> 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"> LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">

View File

@@ -55,6 +55,10 @@ Acknowledgements
<p> <p>
<ul> <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> <li>Marked as <code>noexcept</code> those <code>boost::flyweight</code>
operations previously documented as not throwing operations previously documented as not throwing
(<a href="https://github.com/boostorg/flyweight/issues/15">issue #15</a>).</li> (<a href="https://github.com/boostorg/flyweight/issues/15">issue #15</a>).</li>
@@ -253,7 +257,7 @@ Acknowledgements
<br> <br>
<p>Revised September 14th 2024</p> <p>Revised September 17th 2024</p>
<p>&copy; Copyright 2006-2024 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz. <p>&copy; Copyright 2006-2024 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software Distributed under the Boost Software

View File

@@ -52,38 +52,43 @@ of Boost.Flyweight.
<td>Exercises the default components of <code>flyweight</code>.</td> <td>Exercises the default components of <code>flyweight</code>.</td>
</tr> </tr>
<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><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> <td>Creates a user-defined factory class and specifier.</td>
</tr> </tr>
<tr class="odd_tr"> <tr>
<td><a href="../test/test_init.cpp"><code>test_init.cpp</code></a></td> <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 <td>Boost.Flyweight <a href="tutorial/technical.html#static_init">static
data initialization</a> facilities.</td> data initialization</a> facilities.</td>
</tr> </tr>
<tr> <tr class="odd_tr">
<td><a href="../test/test_intermod_holder.cpp"><code>test_intermod_holder.cpp</code></a><br> <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> <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> <td>Exercises <a href="tutorial/configuration.html#intermodule_holder"><code>intermodule_holder</code></a>.</td>
</tr> </tr>
<tr class="odd_tr"> <tr>
<td><a href="../test/test_multictor.cpp"><code>test_multictor.cpp</code></a></td> <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 <td>Tests <code>flyweight</code> <a href="reference/flyweight.html#constructors">multiple
argument and initializer-list constructors</a>.</td> argument and initializer-list constructors</a>.</td>
</tr> </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="../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> <td><a href="tutorial/configuration.html#no_locking"><code>no_locking</code></a> policy.</td>
</tr> </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="../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> <td><a href="tutorial/configuration.html#no_tracking"><code>no_tracking</code></a> policy.</td>
</tr> </tr>
<tr> <tr class="odd_tr">
<td><a href="../test/test_serialization.cpp"><code>test_serialization.cpp</code></a></td> <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 <td>Exercises <code>flyweight</code> <a href="tutorial/basics.html#serialization">serialization
capabilities</a>.</td> capabilities</a>.</td>
</tr> </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="../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> <td><a href="tutorial/configuration.html#set_factory"><code>set_factory</code></a>
factory specifier.</td> factory specifier.</td>
@@ -106,9 +111,9 @@ Future work
<br> <br>
<p>Revised September 1st 2014</p> <p>Revised September 17th 2024</p>
<p>&copy; Copyright 2006-2014 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz. <p>&copy; Copyright 2006-2024 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt"> 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"> LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">

View File

@@ -41,6 +41,7 @@ Extending Boost.Flyweight
<ul> <ul>
<li><a href="#factory_types">Types involved in the configuration of factories</a></li> <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="#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="#set_factory"><code>set_factory</code></a></li>
<li><a href="#assoc_container_factory"><code>assoc_container_factory</code></a></li> <li><a href="#assoc_container_factory"><code>assoc_container_factory</code></a></li>
</ul> </ul>
@@ -228,7 +229,7 @@ type <code>boost::mpl::_1</code> can be used.
<p> <p>
This specifier, which Boost.Flyweight takes by default, controls the usage of a 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 equivalent by means of the
<a href="https://boost.org/sgi/stl/BinaryPredicate.html"><code>Binary <a href="https://boost.org/sgi/stl/BinaryPredicate.html"><code>Binary
Predicate</code></a> <code>Pred</code>, and indexed into the factory container 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>&gt;</span> <span class=special>&gt;</span>
</pre></blockquote> </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&lt;[Hash[,Pred[,Allocator]]]&gt;</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>&lt;</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>&lt;&gt;,</span>
<span class=identifier>no_locking</span><span class=special>,</span>
<span class=identifier>no_tracking</span>
<span class=special>&gt;</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>&lt;</span><span class=identifier>T</span><span class=special>,</span><span class=identifier>concurrent_factory</span><span class=special>&lt;&gt;</span> <span class=special>&gt;</span>
</pre></blockquote>
<p>
is equivalent to
</p>
<blockquote><pre>
<span class=identifier>flyweight</span><span class=special>&lt;</span>
<span class=identifier>T</span><span class=special>,</span>
<span class=identifier>concurrent_factory</span><span class=special>&lt;</span>
<span class=identifier>boost</span><span class=special>::</span><span class=identifier>hash</span><span class=special>&lt;</span><span class=identifier>key_value</span><span class=special>&gt;,</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>equal_to</span><span class=special>&lt;</span><span class=identifier>key_value</span><span class=special>&gt;,</span>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>allocator</span><span class=special>&lt;</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>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</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> <h3><a name="set_factory"><code>set_factory</code></a></h3>
<blockquote> <blockquote>
@@ -351,7 +411,7 @@ requirements:
<a href="https://boost.org/sgi/stl/UniqueAssociativeContainer.html"><code>Unique <a href="https://boost.org/sgi/stl/UniqueAssociativeContainer.html"><code>Unique
Associative Container</code></a> where equivalence of <code>Entry</code>s Associative Container</code></a> where equivalence of <code>Entry</code>s
is determined by the <code>key_type</code> values the entries are convertible is determined by the <code>key_type</code> values the entries are convertible
to . to.
</li> </li>
<li>The container must be <i>stable</i>, i.e. its iterators must remain valid <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 after insert and erase operations. Note that this condition is not met by
@@ -634,9 +694,9 @@ Extending Boost.Flyweight
<br> <br>
<p>Revised April 24th 2019</p> <p>Revised September 18th 2024</p>
<p>&copy; Copyright 2006-2019 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz. <p>&copy; Copyright 2006-2024 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../../LICENSE_1_0.txt"> 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"> LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">

View File

@@ -1,6 +1,6 @@
# Boost.Flyweight examples Jamfile # 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. # Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at # (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt) # http://www.boost.org/LICENSE_1_0.txt)
@@ -41,6 +41,11 @@ exe key_value
/boost/array//boost_array /boost/array//boost_array
; ;
exe parallel
: parallel.cpp
: <include>$(BOOST_ROOT)
;
exe perf exe perf
: perf.cpp : perf.cpp
/boost/tokenizer//boost_tokenizer /boost/tokenizer//boost_tokenizer

163
example/parallel.cpp Normal file
View 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);
}

View 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

View 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

View File

@@ -14,7 +14,7 @@
#endif #endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */ #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/perfect_fwd.hpp>
#include <boost/flyweight/detail/value_tag.hpp> #include <boost/flyweight/detail/value_tag.hpp>
@@ -67,11 +67,11 @@ struct default_value_policy:value_marker
value_type x; value_type x;
}; };
static void construct_value(const rep_type&){} static void key_construct_value(const rep_type&){}
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) #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 #endif
}; };

View File

@@ -15,10 +15,11 @@
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */ #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/core/no_exceptions_support.hpp> #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/flyweight/detail/perfect_fwd.hpp>
#include <boost/mpl/apply.hpp> #include <boost/mpl/apply.hpp>
#include <boost/type_traits/declval.hpp> #include <boost/type_traits/declval.hpp>
#include <utility>
#if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1400)) #if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1400))
#pragma warning(push) #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< template<
typename ValuePolicy,typename Tag,typename TrackingPolicy, typename ValuePolicy,typename Tag,typename TrackingPolicy,
typename FactorySpecifier,typename LockingPolicy,typename HolderSpecifier typename FactorySpecifier,typename LockingPolicy,typename HolderSpecifier
@@ -177,27 +221,56 @@ private:
holder_arg holder_arg
>::type holder_type; >::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) static handle_type insert_rep(const rep_type& x)
{ {
init(); init();
entry_type e(x); entry_type e(x);
lock_type lock(mutex());(void)lock; 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{ #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
ValuePolicy::construct_value( return static_cast<handle_type>(
static_cast<const rep_type&>(entry(h))); insert_and_visit(factory(),std::move(e),key_construct_value()));
} #else
BOOST_CATCH(...){ return static_cast<handle_type>(
factory().erase(h); insert_and_visit(factory(),e,key_construct_value()));
BOOST_RETHROW; #endif
}
BOOST_CATCH_END
return static_cast<handle_type>(h);
} }
static handle_type insert_value(const value_type& x) static handle_type insert_value(const value_type& x)
@@ -207,21 +280,12 @@ private:
lock_type lock(mutex());(void)lock; lock_type lock(mutex());(void)lock;
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) #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 #else
base_handle_type h(factory().insert(e)); return static_cast<handle_type>(
insert_and_visit(factory(),e,copy_construct_value(x)));
#endif #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) #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
@@ -230,18 +294,9 @@ private:
init(); init();
entry_type e(std::move(x)); entry_type e(std::move(x));
lock_type lock(mutex());(void)lock; lock_type lock(mutex());(void)lock;
base_handle_type h(factory().insert(std::move(e)));
BOOST_TRY{ return static_cast<handle_type>(
ValuePolicy::construct_value( insert_and_visit(factory(),std::move(e),key_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);
} }
static handle_type insert_value(value_type&& x) static handle_type insert_value(value_type&& x)
@@ -249,17 +304,10 @@ private:
init(); init();
entry_type e(rep_type(std::move(x))); entry_type e(rep_type(std::move(x)));
lock_type lock(mutex());(void)lock; lock_type lock(mutex());(void)lock;
base_handle_type h(factory().insert(std::move(e)));
BOOST_TRY{ return static_cast<handle_type>(
ValuePolicy::move_value( insert_and_visit(
static_cast<const rep_type&>(entry(h))); factory(),std::move(e),move_construct_value(std::move(x))));
}
BOOST_CATCH(...){
factory().erase(h);
BOOST_RETHROW;
}
BOOST_CATCH_END
return static_cast<handle_type>(h);
} }
#endif #endif

View File

@@ -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. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * 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/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)||\ #if BOOST_WORKAROUND(__GNUC__, <4)||\
BOOST_WORKAROUND(__GNUC__,==4)&&(__GNUC_MINOR__<2)||\ BOOST_WORKAROUND(__GNUC__,==4)&&(__GNUC_MINOR__<2)||\

View File

@@ -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. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
@@ -60,7 +60,7 @@ private:
} /* namespace boost */ } /* namespace boost */
#elif defined(BOOST_HAS_PTHREADS) #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/assert.hpp>
#include <boost/noncopyable.hpp> #include <boost/noncopyable.hpp>

View File

@@ -17,9 +17,9 @@
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */ #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm> #include <algorithm>
#include <boost/config/workaround.hpp>
#include <boost/core/addressof.hpp> #include <boost/core/addressof.hpp>
#include <boost/core/invoke_swap.hpp> #include <boost/core/invoke_swap.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/flyweight/detail/default_value_policy.hpp> #include <boost/flyweight/detail/default_value_policy.hpp>
#include <boost/flyweight/detail/flyweight_core.hpp> #include <boost/flyweight/detail/flyweight_core.hpp>
#include <boost/flyweight/detail/perfect_fwd.hpp> #include <boost/flyweight/detail/perfect_fwd.hpp>

View File

@@ -14,8 +14,8 @@
#endif #endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */ #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/templated_streams.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/parameter/parameters.hpp> #include <boost/parameter/parameters.hpp>
#include <boost/preprocessor/punctuation/comma.hpp> #include <boost/preprocessor/punctuation/comma.hpp>
#include <iosfwd> #include <iosfwd>

View File

@@ -14,7 +14,8 @@
#endif #endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */ #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/perfect_fwd.hpp>
#include <boost/flyweight/detail/value_tag.hpp> #include <boost/flyweight/detail/value_tag.hpp>
#include <boost/flyweight/key_value_fwd.hpp> #include <boost/flyweight/key_value_fwd.hpp>
@@ -47,7 +48,7 @@ namespace flyweights{
namespace detail{ namespace detail{
template<typename Key,typename Value,typename KeyFromValue> template<typename Key,typename Value,typename KeyFromValue>
struct optimized_key_value:value_marker struct variant_key_value:value_marker
{ {
typedef Key key_type; typedef Key key_type;
typedef Value value_type; typedef Value value_type;
@@ -58,9 +59,9 @@ struct optimized_key_value:value_marker
/* template ctors */ /* template ctors */
#define BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY(args) \ #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( BOOST_FLYWEIGHT_PERFECT_FWD(
@@ -69,55 +70,61 @@ struct optimized_key_value:value_marker
#undef BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY #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) #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 #endif
~rep_type() ~rep_type()
{ {
if(!value_ptr) key_ptr()->~key_type(); if(value_cted)value_ptr()->~value_type();
else if(value_cted())value_ptr->~value_type(); else key_ptr()->~key_type();
} }
operator const key_type&()const operator const key_type&()const
BOOST_NOEXCEPT_IF(noexcept( BOOST_NOEXCEPT_IF(noexcept(
boost::declval<KeyFromValue>()(boost::declval<const value_type&>()))) boost::declval<KeyFromValue>()(boost::declval<const value_type&>())))
{ {
if(value_ptr)return key_from_value(*value_ptr); if(value_cted)return key_from_value(*value_ptr());
else return *key_ptr(); else return *key_ptr();
} }
operator const value_type&()const operator const value_type&()const
{ {
/* This is always called after construct_value() or copy_value(), BOOST_ASSERT(value_cted);
* so we access spc directly rather than through value_ptr to return *value_ptr();
* save us an indirection.
*/
return *static_cast<value_type*>(spc_ptr());
} }
private: private:
friend struct optimized_key_value; friend struct variant_key_value;
void* spc_ptr()const{return static_cast<void*>(&spc);}
bool value_cted()const{return value_ptr==spc_ptr();}
key_type* key_ptr()const 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) static const key_type& key_from_value(const value_type& x)
@@ -126,68 +133,66 @@ struct optimized_key_value:value_marker
return k(x); return k(x);
} }
void construct_value()const void key_construct_value()const
{ {
if(!value_cted()){ if(!value_cted){
/* value_ptr must be ==0, oherwise copy_value would have been called */ new(value_ptr())value_type(*key_ptr());
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
key_type k(std::move(*key_ptr()));
#else
key_type k(*key_ptr());
#endif
key_ptr()->~key_type(); key_ptr()->~key_type();
value_ptr= /* guarantees key won't be re-dted at ~rep_type if the */ value_cted=true;
static_cast<value_type*>(spc_ptr())+1; /* next statement throws */
value_ptr=new(spc_ptr())value_type(k);
} }
} }
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) #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
void move_value()const void move_construct_value(value_type&& x)const
{ {
if(!value_cted())value_ptr= if(!value_cted){
new(spc_ptr())value_type(std::move(const_cast<value_type&>(*value_ptr))); new(value_ptr())value_type(std::move(x));
key_ptr()->~key_type();
value_cted=true;
}
} }
#endif #endif
mutable typename boost::aligned_storage< mutable typename boost::aligned_storage<
(sizeof(key_type)>sizeof(value_type))? sizeof(key_type),
sizeof(key_type):sizeof(value_type), boost::alignment_of<key_type>::value
(boost::alignment_of<key_type>::value > >::type key_spc;
boost::alignment_of<value_type>::value)? mutable typename boost::aligned_storage<
boost::alignment_of<key_type>::value: sizeof(value_type),
boost::alignment_of<value_type>::value boost::alignment_of<value_type>::value
>::type spc; >::type value_spc;
mutable const value_type* value_ptr; 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) #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 #endif
}; };
template<typename Key,typename Value> template<typename Key,typename Value>
struct regular_key_value:value_marker struct product_key_value:value_marker
{ {
typedef Key key_type; typedef Key key_type;
typedef Value value_type; typedef Value value_type;
@@ -205,11 +210,11 @@ struct regular_key_value:value_marker
* variadic temmplate ctor below fails to value-initialize key. * variadic temmplate ctor below fails to value-initialize key.
*/ */
rep_type():key(),value_ptr(0){} rep_type():key(),value_cted(false){}
#endif #endif
#define BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY(args) \ #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( BOOST_FLYWEIGHT_PERFECT_FWD(
explicit rep_type, explicit rep_type,
@@ -217,34 +222,34 @@ struct regular_key_value:value_marker
#undef BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY #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()){} rep_type(const value_type&):key(no_key_from_value_failure()){}
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) #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()){} rep_type(value_type&&):key(no_key_from_value_failure()){}
#endif #endif
~rep_type() ~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 key_type&()const BOOST_NOEXCEPT{return key;}
operator const value_type&()const operator const value_type&()const
{ {
/* This is always called after construct_value(),so we access spc BOOST_ASSERT(value_cted);
* directly rather than through value_ptr to save us an indirection. return *value_ptr();
*/
return *static_cast<value_type*>(spc_ptr());
} }
private: 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 struct no_key_from_value_failure
{ {
@@ -256,33 +261,36 @@ struct regular_key_value:value_marker
operator const key_type&()const; 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; key_type key;
mutable typename boost::aligned_storage< mutable typename boost::aligned_storage<
sizeof(value_type), sizeof(value_type),
boost::alignment_of<value_type>::value boost::alignment_of<value_type>::value
>::type spc; >::type value_spc;
mutable const value_type* value_ptr; 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 /* [copy|move]_construct_value() can't really ever be called, provided to
* compile errors (it is the no_key_from_value_failure compile error we want to * avoid compile errors (it is the no_key_from_value_failure compile error
* appear in these cases). * 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) #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 #endif
}; };
@@ -292,8 +300,8 @@ template<typename Key,typename Value,typename KeyFromValue>
struct key_value: struct key_value:
mpl::if_< mpl::if_<
is_same<KeyFromValue,no_key_from_value>, is_same<KeyFromValue,no_key_from_value>,
detail::regular_key_value<Key,Value>, detail::product_key_value<Key,Value>,
detail::optimized_key_value<Key,Value,KeyFromValue> detail::variant_key_value<Key,Value,KeyFromValue>
>::type >::type
{}; {};

View File

@@ -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. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * 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 <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm> #include <algorithm>
#include <boost/config/workaround.hpp>
#include <boost/core/invoke_swap.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/refcounted_fwd.hpp>
#include <boost/flyweight/tracking_tag.hpp> #include <boost/flyweight/tracking_tag.hpp>
#include <boost/smart_ptr/detail/atomic_count.hpp>
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
#include <utility> #include <utility>

View File

@@ -1,6 +1,6 @@
# Boost.Flyweight tests Jamfile # 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. # Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at # (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt) # http://www.boost.org/LICENSE_1_0.txt)
@@ -14,22 +14,23 @@ project
; ;
test-suite "flyweight" : test-suite "flyweight" :
[ run test_assoc_cont_factory.cpp test_assoc_cont_fact_main.cpp ] [ run test_assoc_cont_factory.cpp test_assoc_cont_fact_main.cpp ]
[ run test_basic.cpp test_basic_main.cpp ] [ run test_basic.cpp test_basic_main.cpp ]
[ run test_custom_factory.cpp test_custom_factory_main.cpp ] [ run test_concurrent_factory.cpp test_concurrent_factory_main.cpp ]
[ run test_init.cpp test_init_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 [ run test_intermod_holder.cpp test_intermod_holder_main.cpp
intermod_holder_dll intermod_holder_dll
: # command line : # command line
: # input files : # input files
: # requirements : # requirements
<threading>multi ] <threading>multi ]
[ run test_multictor.cpp test_multictor_main.cpp ] [ run test_multictor.cpp test_multictor_main.cpp ]
[ run test_no_locking.cpp test_no_locking_main.cpp ] [ run test_no_locking.cpp test_no_locking_main.cpp ]
[ run test_no_tracking.cpp test_no_tracking_main.cpp ] [ run test_no_tracking.cpp test_no_tracking_main.cpp ]
[ run test_serialization.cpp test_serialization_main.cpp [ run test_serialization.cpp test_serialization_main.cpp
/boost/serialization//boost_serialization/<link>static ] /boost/serialization//boost_serialization/<link>static ]
[ run test_set_factory.cpp test_set_factory_main.cpp ] [ run test_set_factory.cpp test_set_factory_main.cpp ]
; ;
lib intermod_holder_dll : intermod_holder_dll.cpp : lib intermod_holder_dll : intermod_holder_dll.cpp :

View File

@@ -1,6 +1,6 @@
/* Classes for Boost.Flyweight key-value tests. /* 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. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
@@ -90,11 +90,17 @@ struct throwing_value_exception{};
struct throwing_value struct throwing_value
{ {
throwing_value():n(0){} throwing_value(bool does_throw_=true):n(0),does_throw(does_throw_){}
throwing_value(const throwing_value&){throw throwing_value_exception();}
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();} throwing_value(int){throw throwing_value_exception();}
int n; int n;
bool does_throw;
}; };
struct from_throwing_value_to_int struct from_throwing_value_to_int

View File

@@ -1,6 +1,6 @@
/* Boost.Flyweight test suite. /* 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. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * 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/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_assoc_cont_factory.hpp"
#include "test_basic.hpp" #include "test_basic.hpp"
#include "test_concurrent_factory.hpp"
#include "test_custom_factory.hpp" #include "test_custom_factory.hpp"
#include "test_intermod_holder.hpp" #include "test_intermod_holder.hpp"
#include "test_init.hpp" #include "test_init.hpp"
@@ -25,6 +26,7 @@ int main()
{ {
test_assoc_container_factory(); test_assoc_container_factory();
test_basic(); test_basic();
test_concurrent_factory();
test_custom_factory(); test_custom_factory();
test_init(); test_init();
test_intermodule_holder(); test_intermodule_holder();

View File

@@ -1,6 +1,6 @@
/* Boost.Flyweight test of assoc_container_factory. /* 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. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
@@ -8,7 +8,7 @@
* See http://www.boost.org/libs/flyweight for library home page. * 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" #include "test_assoc_cont_factory.hpp"
int main() int main()

View File

@@ -1,6 +1,6 @@
/* Boost.Flyweight basic test. /* 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. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
@@ -8,7 +8,7 @@
* See http://www.boost.org/libs/flyweight for library home page. * 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" #include "test_basic.hpp"
int main() int main()

View File

@@ -1,6 +1,6 @@
/* Boost.Flyweight basic test template. /* 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. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
@@ -16,7 +16,7 @@
#endif #endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */ #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/flyweight/key_value.hpp>
#include <boost/mpl/apply.hpp> #include <boost/mpl/apply.hpp>
#include <boost/utility/value_init.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()); throwing_flyweight fw=throwing_flyweight(throwing_value());
(void)fw; (void)fw;
}catch(const throwing_value_exception&){} }catch(const throwing_value_exception&){}
throwing_flyweight fw=throwing_flyweight(
throwing_value(false /* doesn't throw */));
(void)fw.get();
#endif #endif
} }

View 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>();
}

View 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();

View 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();
}

View File

@@ -1,6 +1,6 @@
/* Boost.Flyweight test of a custom factory. /* 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. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
@@ -8,7 +8,7 @@
* See http://www.boost.org/libs/flyweight for library home page. * 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" #include "test_custom_factory.hpp"
int main() int main()

View File

@@ -1,6 +1,6 @@
/* Boost.Flyweight test of static data initialization facilities. /* 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. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
@@ -11,7 +11,7 @@
#include "test_init.hpp" #include "test_init.hpp"
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */ #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> #include <boost/flyweight.hpp>
using namespace boost::flyweights; using namespace boost::flyweights;

View File

@@ -1,6 +1,6 @@
/* Boost.Flyweight test of static data initialization facilities. /* 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. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
@@ -8,7 +8,7 @@
* See http://www.boost.org/libs/flyweight for library home page. * 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" #include "test_init.hpp"
int main() int main()

View File

@@ -1,6 +1,6 @@
/* Boost.Flyweight test of intermodule_holder. /* 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. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
@@ -8,7 +8,7 @@
* See http://www.boost.org/libs/flyweight for library home page. * 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" #include "test_intermod_holder.hpp"
int main() int main()

View File

@@ -1,6 +1,6 @@
/* Boost.Flyweight test of flyweight forwarding and initializer_list ctors. /* 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. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
@@ -11,8 +11,8 @@
#include "test_multictor.hpp" #include "test_multictor.hpp"
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */ #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/detail/lightweight_test.hpp> #include <boost/config/workaround.hpp>
#include <boost/detail/workaround.hpp> #include <boost/core/lightweight_test.hpp>
#include <boost/flyweight.hpp> #include <boost/flyweight.hpp>
#include <boost/functional/hash.hpp> #include <boost/functional/hash.hpp>
#include <boost/tuple/tuple.hpp> #include <boost/tuple/tuple.hpp>

View File

@@ -1,6 +1,6 @@
/* Boost.Flyweight test of flyweight forwarding ctors. /* 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. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
@@ -8,7 +8,7 @@
* See http://www.boost.org/libs/flyweight for library home page. * 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" #include "test_multictor.hpp"
int main() int main()

View File

@@ -1,6 +1,6 @@
/* Boost.Flyweight test of no_locking. /* 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. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
@@ -8,7 +8,7 @@
* See http://www.boost.org/libs/flyweight for library home page. * 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" #include "test_no_locking.hpp"
int main() int main()

View File

@@ -1,6 +1,6 @@
/* Boost.Flyweight test of no_tracking. /* 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. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
@@ -8,7 +8,7 @@
* See http://www.boost.org/libs/flyweight for library home page. * 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" #include "test_no_tracking.hpp"
int main() int main()

View File

@@ -1,6 +1,6 @@
/* Boost.Flyweight test of serialization capabilities. /* 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. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
@@ -8,7 +8,7 @@
* See http://www.boost.org/libs/flyweight for library home page. * 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" #include "test_serialization.hpp"
int main() int main()

View File

@@ -1,6 +1,6 @@
/* Boost.Flyweight test template for serialization capabilities. /* 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. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * 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/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/archive/text_oarchive.hpp> #include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.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/key_value.hpp>
#include <boost/flyweight/serialize.hpp> #include <boost/flyweight/serialize.hpp>
#include <boost/functional/hash.hpp> #include <boost/functional/hash.hpp>

View File

@@ -1,6 +1,6 @@
/* Boost.Flyweight test of set_factory. /* 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. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
@@ -8,7 +8,7 @@
* See http://www.boost.org/libs/flyweight for library home page. * 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" #include "test_set_factory.hpp"
int main() int main()