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="#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&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>
<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>&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
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">

View File

@@ -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>&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
<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>&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
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">

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#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>&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
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">

View File

@@ -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>&copy; Copyright 2006-2024 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software

View File

@@ -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>&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
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">

View File

@@ -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>&gt;</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&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>
<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>&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
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">

View File

@@ -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
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
#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
};

View File

@@ -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

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.
* (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)||\

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.
* (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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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
{};

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.
* (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>

View File

@@ -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 :

View File

@@ -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

View File

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

View File

@@ -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()

View File

@@ -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()

View File

@@ -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
}

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.
*
* 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()

View File

@@ -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;

View File

@@ -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()

View File

@@ -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()

View File

@@ -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>

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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>

View File

@@ -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()