From a5665e6ee1daacd1e692a79be71cb09f6f87edde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20M=20L=C3=B3pez=20Mu=C3=B1oz?= Date: Thu, 18 Dec 2008 22:18:11 +0000 Subject: [PATCH] added flyweight from trunk [SVN r50320] --- .gitattributes | 96 +++ doc/acknowledgements.html | 88 +++ doc/examples.html | 258 +++++++ doc/future_work.html | 128 ++++ doc/html.png | Bin 0 -> 24278 bytes doc/index.html | 82 +++ doc/memory.png | Bin 0 -> 8262 bytes doc/memory_gcc_344.png | Bin 0 -> 10405 bytes doc/memory_msvc_80.png | Bin 0 -> 10706 bytes doc/next.gif | Bin 0 -> 852 bytes doc/performance.html | 472 +++++++++++++ doc/prev.gif | Bin 0 -> 852 bytes doc/reference/factories.html | 583 ++++++++++++++++ doc/reference/flyweight.html | 630 +++++++++++++++++ doc/reference/holders.html | 243 +++++++ doc/reference/index.html | 158 +++++ doc/reference/key_value.html | 124 ++++ doc/reference/locking.html | 287 ++++++++ doc/reference/tags.html | 107 +++ doc/reference/tracking.html | 291 ++++++++ doc/release_notes.html | 70 ++ doc/style.css | 54 ++ doc/tests.html | 114 +++ doc/time_gcc_344.png | Bin 0 -> 12600 bytes doc/time_msvc_80.png | Bin 0 -> 11937 bytes doc/tutorial/basics.html | 227 ++++++ doc/tutorial/configuration.html | 647 ++++++++++++++++++ doc/tutorial/extension.html | 562 +++++++++++++++ doc/tutorial/flyweight_rep.png | Bin 0 -> 53631 bytes doc/tutorial/index.html | 170 +++++ doc/tutorial/key_value.html | 231 +++++++ doc/tutorial/lambda_expressions.html | 181 +++++ doc/tutorial/technical.html | 193 ++++++ doc/up.gif | Bin 0 -> 853 bytes example/Jamfile.v2 | 49 ++ example/basic.cpp | 152 ++++ example/composite.cpp | 179 +++++ example/custom_factory.cpp | 122 ++++ example/fibonacci.cpp | 58 ++ example/html.cpp | 343 ++++++++++ example/key_value.cpp | 99 +++ example/perf.cpp | 312 +++++++++ include/boost/flyweight.hpp | 22 + .../flyweight/assoc_container_factory.hpp | 88 +++ .../flyweight/assoc_container_factory_fwd.hpp | 35 + .../flyweight/detail/default_value_policy.hpp | 58 ++ .../flyweight/detail/dyn_perfect_fwd.hpp | 75 ++ .../boost/flyweight/detail/flyweight_core.hpp | 256 +++++++ .../detail/handle_factory_adaptor.hpp | 48 ++ .../flyweight/detail/not_placeholder_expr.hpp | 58 ++ .../boost/flyweight/detail/perfect_fwd.hpp | 28 + .../boost/flyweight/detail/pp_perfect_fwd.hpp | 153 +++++ include/boost/flyweight/detail/process_id.hpp | 81 +++ .../flyweight/detail/recursive_lw_mutex.hpp | 91 +++ include/boost/flyweight/detail/value_tag.hpp | 50 ++ include/boost/flyweight/factory_tag.hpp | 44 ++ include/boost/flyweight/flyweight.hpp | 407 +++++++++++ include/boost/flyweight/flyweight_fwd.hpp | 166 +++++ include/boost/flyweight/hashed_factory.hpp | 128 ++++ .../boost/flyweight/hashed_factory_fwd.hpp | 40 ++ include/boost/flyweight/holder_tag.hpp | 44 ++ .../boost/flyweight/intermodule_holder.hpp | 202 ++++++ .../flyweight/intermodule_holder_fwd.hpp | 29 + include/boost/flyweight/key_value.hpp | 238 +++++++ include/boost/flyweight/key_value_fwd.hpp | 29 + include/boost/flyweight/locking_tag.hpp | 44 ++ include/boost/flyweight/no_locking.hpp | 36 + include/boost/flyweight/no_locking_fwd.hpp | 26 + include/boost/flyweight/no_tracking.hpp | 46 ++ include/boost/flyweight/no_tracking_fwd.hpp | 26 + include/boost/flyweight/refcounted.hpp | 152 ++++ include/boost/flyweight/refcounted_fwd.hpp | 26 + include/boost/flyweight/set_factory.hpp | 96 +++ include/boost/flyweight/set_factory_fwd.hpp | 40 ++ include/boost/flyweight/simple_locking.hpp | 37 + .../boost/flyweight/simple_locking_fwd.hpp | 26 + include/boost/flyweight/static_holder.hpp | 66 ++ include/boost/flyweight/static_holder_fwd.hpp | 29 + include/boost/flyweight/tag.hpp | 46 ++ include/boost/flyweight/tracking_tag.hpp | 44 ++ index.html | 20 + test/Jamfile.v2 | 34 + test/heavy_objects.hpp | 87 +++ test/intermod_holder_dll.cpp | 17 + test/intermod_holder_dll.hpp | 45 ++ test/test_all_main.cpp | 36 + test/test_assoc_cont_fact_main.cpp | 18 + test/test_assoc_cont_factory.cpp | 68 ++ test/test_assoc_cont_factory.hpp | 11 + test/test_basic.cpp | 68 ++ test/test_basic.hpp | 11 + test/test_basic_main.cpp | 18 + test/test_basic_template.hpp | 232 +++++++ test/test_custom_factory.cpp | 111 +++ test/test_custom_factory.hpp | 11 + test/test_custom_factory_main.cpp | 18 + test/test_init.cpp | 47 ++ test/test_init.hpp | 11 + test/test_init_main.cpp | 18 + test/test_intermod_holder.cpp | 34 + test/test_intermod_holder.hpp | 11 + test/test_intermod_holder_main.cpp | 18 + test/test_multictor.cpp | 105 +++ test/test_multictor.hpp | 11 + test/test_multictor_main.cpp | 18 + test/test_no_locking.cpp | 35 + test/test_no_locking.hpp | 11 + test/test_no_locking_main.cpp | 18 + test/test_no_tracking.cpp | 35 + test/test_no_tracking.hpp | 11 + test/test_no_tracking_main.cpp | 18 + test/test_set_factory.cpp | 71 ++ test/test_set_factory.hpp | 11 + test/test_set_factory_main.cpp | 18 + 114 files changed, 11726 insertions(+) create mode 100644 .gitattributes create mode 100644 doc/acknowledgements.html create mode 100644 doc/examples.html create mode 100644 doc/future_work.html create mode 100644 doc/html.png create mode 100644 doc/index.html create mode 100644 doc/memory.png create mode 100644 doc/memory_gcc_344.png create mode 100644 doc/memory_msvc_80.png create mode 100644 doc/next.gif create mode 100644 doc/performance.html create mode 100644 doc/prev.gif create mode 100644 doc/reference/factories.html create mode 100644 doc/reference/flyweight.html create mode 100644 doc/reference/holders.html create mode 100644 doc/reference/index.html create mode 100644 doc/reference/key_value.html create mode 100644 doc/reference/locking.html create mode 100644 doc/reference/tags.html create mode 100644 doc/reference/tracking.html create mode 100644 doc/release_notes.html create mode 100644 doc/style.css create mode 100644 doc/tests.html create mode 100644 doc/time_gcc_344.png create mode 100644 doc/time_msvc_80.png create mode 100644 doc/tutorial/basics.html create mode 100644 doc/tutorial/configuration.html create mode 100644 doc/tutorial/extension.html create mode 100644 doc/tutorial/flyweight_rep.png create mode 100644 doc/tutorial/index.html create mode 100644 doc/tutorial/key_value.html create mode 100644 doc/tutorial/lambda_expressions.html create mode 100644 doc/tutorial/technical.html create mode 100644 doc/up.gif create mode 100644 example/Jamfile.v2 create mode 100644 example/basic.cpp create mode 100644 example/composite.cpp create mode 100644 example/custom_factory.cpp create mode 100644 example/fibonacci.cpp create mode 100644 example/html.cpp create mode 100644 example/key_value.cpp create mode 100644 example/perf.cpp create mode 100644 include/boost/flyweight.hpp create mode 100644 include/boost/flyweight/assoc_container_factory.hpp create mode 100644 include/boost/flyweight/assoc_container_factory_fwd.hpp create mode 100644 include/boost/flyweight/detail/default_value_policy.hpp create mode 100644 include/boost/flyweight/detail/dyn_perfect_fwd.hpp create mode 100644 include/boost/flyweight/detail/flyweight_core.hpp create mode 100644 include/boost/flyweight/detail/handle_factory_adaptor.hpp create mode 100644 include/boost/flyweight/detail/not_placeholder_expr.hpp create mode 100644 include/boost/flyweight/detail/perfect_fwd.hpp create mode 100644 include/boost/flyweight/detail/pp_perfect_fwd.hpp create mode 100644 include/boost/flyweight/detail/process_id.hpp create mode 100644 include/boost/flyweight/detail/recursive_lw_mutex.hpp create mode 100644 include/boost/flyweight/detail/value_tag.hpp create mode 100644 include/boost/flyweight/factory_tag.hpp create mode 100644 include/boost/flyweight/flyweight.hpp create mode 100644 include/boost/flyweight/flyweight_fwd.hpp create mode 100644 include/boost/flyweight/hashed_factory.hpp create mode 100644 include/boost/flyweight/hashed_factory_fwd.hpp create mode 100644 include/boost/flyweight/holder_tag.hpp create mode 100644 include/boost/flyweight/intermodule_holder.hpp create mode 100644 include/boost/flyweight/intermodule_holder_fwd.hpp create mode 100644 include/boost/flyweight/key_value.hpp create mode 100644 include/boost/flyweight/key_value_fwd.hpp create mode 100644 include/boost/flyweight/locking_tag.hpp create mode 100644 include/boost/flyweight/no_locking.hpp create mode 100644 include/boost/flyweight/no_locking_fwd.hpp create mode 100644 include/boost/flyweight/no_tracking.hpp create mode 100644 include/boost/flyweight/no_tracking_fwd.hpp create mode 100644 include/boost/flyweight/refcounted.hpp create mode 100644 include/boost/flyweight/refcounted_fwd.hpp create mode 100644 include/boost/flyweight/set_factory.hpp create mode 100644 include/boost/flyweight/set_factory_fwd.hpp create mode 100644 include/boost/flyweight/simple_locking.hpp create mode 100644 include/boost/flyweight/simple_locking_fwd.hpp create mode 100644 include/boost/flyweight/static_holder.hpp create mode 100644 include/boost/flyweight/static_holder_fwd.hpp create mode 100644 include/boost/flyweight/tag.hpp create mode 100644 include/boost/flyweight/tracking_tag.hpp create mode 100644 index.html create mode 100644 test/Jamfile.v2 create mode 100644 test/heavy_objects.hpp create mode 100644 test/intermod_holder_dll.cpp create mode 100644 test/intermod_holder_dll.hpp create mode 100644 test/test_all_main.cpp create mode 100644 test/test_assoc_cont_fact_main.cpp create mode 100644 test/test_assoc_cont_factory.cpp create mode 100644 test/test_assoc_cont_factory.hpp create mode 100644 test/test_basic.cpp create mode 100644 test/test_basic.hpp create mode 100644 test/test_basic_main.cpp create mode 100644 test/test_basic_template.hpp create mode 100644 test/test_custom_factory.cpp create mode 100644 test/test_custom_factory.hpp create mode 100644 test/test_custom_factory_main.cpp create mode 100644 test/test_init.cpp create mode 100644 test/test_init.hpp create mode 100644 test/test_init_main.cpp create mode 100644 test/test_intermod_holder.cpp create mode 100644 test/test_intermod_holder.hpp create mode 100644 test/test_intermod_holder_main.cpp create mode 100644 test/test_multictor.cpp create mode 100644 test/test_multictor.hpp create mode 100644 test/test_multictor_main.cpp create mode 100644 test/test_no_locking.cpp create mode 100644 test/test_no_locking.hpp create mode 100644 test/test_no_locking_main.cpp create mode 100644 test/test_no_tracking.cpp create mode 100644 test/test_no_tracking.hpp create mode 100644 test/test_no_tracking_main.cpp create mode 100644 test/test_set_factory.cpp create mode 100644 test/test_set_factory.hpp create mode 100644 test/test_set_factory_main.cpp diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3e84d7c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,96 @@ +* text=auto !eol svneol=native#text/plain +*.gitattributes text svneol=native#text/plain + +# Scriptish formats +*.bat text svneol=native#text/plain +*.bsh text svneol=native#text/x-beanshell +*.cgi text svneol=native#text/plain +*.cmd text svneol=native#text/plain +*.js text svneol=native#text/javascript +*.php text svneol=native#text/x-php +*.pl text svneol=native#text/x-perl +*.pm text svneol=native#text/x-perl +*.py text svneol=native#text/x-python +*.sh eol=lf svneol=LF#text/x-sh +configure eol=lf svneol=LF#text/x-sh + +# Image formats +*.bmp binary svneol=unset#image/bmp +*.gif binary svneol=unset#image/gif +*.ico binary svneol=unset#image/ico +*.jpeg binary svneol=unset#image/jpeg +*.jpg binary svneol=unset#image/jpeg +*.png binary svneol=unset#image/png +*.tif binary svneol=unset#image/tiff +*.tiff binary svneol=unset#image/tiff +*.svg text svneol=native#image/svg%2Bxml + +# Data formats +*.pdf binary svneol=unset#application/pdf +*.avi binary svneol=unset#video/avi +*.doc binary svneol=unset#application/msword +*.dsp text svneol=crlf#text/plain +*.dsw text svneol=crlf#text/plain +*.eps binary svneol=unset#application/postscript +*.gz binary svneol=unset#application/gzip +*.mov binary svneol=unset#video/quicktime +*.mp3 binary svneol=unset#audio/mpeg +*.ppt binary svneol=unset#application/vnd.ms-powerpoint +*.ps binary svneol=unset#application/postscript +*.psd binary svneol=unset#application/photoshop +*.rdf binary svneol=unset#text/rdf +*.rss text svneol=unset#text/xml +*.rtf binary svneol=unset#text/rtf +*.sln text svneol=native#text/plain +*.swf binary svneol=unset#application/x-shockwave-flash +*.tgz binary svneol=unset#application/gzip +*.vcproj text svneol=native#text/xml +*.vcxproj text svneol=native#text/xml +*.vsprops text svneol=native#text/xml +*.wav binary svneol=unset#audio/wav +*.xls binary svneol=unset#application/vnd.ms-excel +*.zip binary svneol=unset#application/zip + +# Text formats +.htaccess text svneol=native#text/plain +*.bbk text svneol=native#text/xml +*.cmake text svneol=native#text/plain +*.css text svneol=native#text/css +*.dtd text svneol=native#text/xml +*.htm text svneol=native#text/html +*.html text svneol=native#text/html +*.ini text svneol=native#text/plain +*.log text svneol=native#text/plain +*.mak text svneol=native#text/plain +*.qbk text svneol=native#text/plain +*.rst text svneol=native#text/plain +*.sql text svneol=native#text/x-sql +*.txt text svneol=native#text/plain +*.xhtml text svneol=native#text/xhtml%2Bxml +*.xml text svneol=native#text/xml +*.xsd text svneol=native#text/xml +*.xsl text svneol=native#text/xml +*.xslt text svneol=native#text/xml +*.xul text svneol=native#text/xul +*.yml text svneol=native#text/plain +boost-no-inspect text svneol=native#text/plain +CHANGES text svneol=native#text/plain +COPYING text svneol=native#text/plain +INSTALL text svneol=native#text/plain +Jamfile text svneol=native#text/plain +Jamroot text svneol=native#text/plain +Jamfile.v2 text svneol=native#text/plain +Jamrules text svneol=native#text/plain +Makefile* text svneol=native#text/plain +README text svneol=native#text/plain +TODO text svneol=native#text/plain + +# Code formats +*.c text svneol=native#text/plain +*.cpp text svneol=native#text/plain +*.h text svneol=native#text/plain +*.hpp text svneol=native#text/plain +*.ipp text svneol=native#text/plain +*.tpp text svneol=native#text/plain +*.jam text svneol=native#text/plain +*.java text svneol=native#text/plain diff --git a/doc/acknowledgements.html b/doc/acknowledgements.html new file mode 100644 index 0000000..081f6d1 --- /dev/null +++ b/doc/acknowledgements.html @@ -0,0 +1,88 @@ + + + + + +Boost.Flyweight Documentation - Acknowledgements + + + + + + + +

Boost logoBoost.Flyweight Acknowledgements

+ + + +
+ +
+ +

+The following people have provided valuable feedback and suggestions during the +development of the library: Ion Gaztañaga, Janek Kozicki, Tobias Schwinger, +Pavel Voženílek. Simon Atanasyan contributed a workaround for a +problem with Sun Studio compilers. Rosa Bernárdez has proofread the +documentation from the first drafts up to its present form. +

+ +

+The acceptance review of Boost.Flyweight took place between January 21st +and February 3rd 2008. Many thanks to Ion Gaztañaga, the stalwart review manager, +and to all the reviewers: Alberto Ganesh Barbati, Tim Blechmann, +Vicente Juan Botet Escribá, Matías Capeletto, Neil Hunt, Marcus Lindblom, +John Reid, David Sankel, Kevin Sopp, John Torjo, Markus Werle. Alberto identified +important limitations of the initial design, which led to the +introduction of key-value flyweights. +

+ +

+Boost.Flyweight relies on the +Boost MPL Library from +Aleksey Gurtovoy. The +free-order template +parameter interface offered by the library has been implemented +with the Boost Parameter +Library from David Abrahams and Daniel Wallin. Ion Gaztañaga's +Boost Interprocess Library +is the core element behind the +intermodule_holder +component. +

+ +

+This work is dedicated to Jorge López, in the hope that past +dire straits gentler oceans will lie. +

+ +
+ + + +
+ +
+ +

Revised December 10th 2008

+ +

© Copyright 2006-2008 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) +

+ + + diff --git a/doc/examples.html b/doc/examples.html new file mode 100644 index 0000000..2bef5cf --- /dev/null +++ b/doc/examples.html @@ -0,0 +1,258 @@ + + + + + +Boost.Flyweight Documentation - Examples + + + + + + + + +

Boost logoBoost.Flyweight Examples

+ + + +
+
+ +
+ +

Contents

+ + + +

Example 1: basic usage

+ +

+See source code. +

+ +

+Dummy program showing the basic capabilities of flyweight +explained at the tutorial. +

+ +

Example 2: key-value flyweights

+ +

+See source code. +

+ +

+The program simulates the scenario described at the tutorial section on +key-value flyweights: The class +texture manages some texture rendering data stored in +a file whose location is given at construction time. The program +handles large quantities of objects of this class by encapsulating +them into key-value flyweights keyed by filename. Observe how the +execution of the program results in no extra constructions or copies +of objects of type texture except those absolutely +necessary. +

+ +

Example 3: flyweights and the composite pattern

+ +

+See source code. +

+ +

+The composite +design pattern revolves about the idea that a tree data structure +can be easily constructed and manipulated by defining the tree node type +polymorphically so that either is a leaf node or else contains a list of +pointers to their child nodes. +This way, a tree is the exact same entity as its root node, which allows +for very simple recursive tree-handling algorithms. Large composite trees +having a high degree of duplication of nodes and subtrees (as for instance +those generated when parsing a computer program) are a natural fit for the +flyweight idiom: simply turning the node type into a flyweight +automatically deals with duplication at the node and subtree level. +

+ +

+The example program parses Lisp-like lists of the form +(a1 ... an) where each +ai is a terminal string or a list. The parsed +data structure is a composite type defined using Boost.Flyweight in conjunction +with the recursive facilities of +Boost.Variant. So, given the list +

+ +
+(= (tan (+ x y))(/ (+ (tan x)(tan y))(- 1 (* (tan x)(tan y)))))
+
+ +

+the resulting data structure implicitly detects the duplicated +occurrences of +, x, y, +tan, (tan x) and (tan y). +

+ +

Example 4: formatted text processing

+ +

+See source code. +

+ +

+A classic example of application of the flyweight pattern is that of a +text processor which handles characters with rich formatting information, +like font type, size, color and special options (boldness, italics, etc.) +Coding the formatting information of each character takes considerable +space, but, given the high degree of repetition typical in a document, +maintaining formatted characters as flyweight objects drastically reduces +memory consumption. +

+ +

+The example program parses, manipulates and stores HTML documents following +flyweight-based representation techniques. Given the hierarchical nature +of HTML markup, a crude approximation to the formatting options of a given +character is just to equate them with the stack of tag contexts to which +the character belongs, as the figure shows. +

+ +

+
+Fig. 1: Formatting contexts of characters in an HTML document. +

+ +

+HTML documents are then parsed as arrays of (character, format) +pairs, where the format is the tag context as described above. The very high +degree of redundancy in formatting information is taken care of by the +use of Boost.Flyweight. This character-based representation makes it +easy to manipulate the document: transposition and elimination of +portions of text are trivial operations. As an example, the program +reverses the text occupying the central portion of the document. +Saving the result in HTML reduces to traversing the array of formatted +characters and emitting opening/closing HTML tags as the context of adjacent +characters varies. +

+ +

+For the sake of brevity, the HTML parsing capabilities of this program +are coarse: for instance, elements without end-tag (like <BR>), character +enconding and HTML entities (e.g. "&copy;" for ©) are not properly +handled. Improving the parsing code is left as an exercise to the reader. +

+ +

Example 5: flyweight-based memoization

+ +

+See source code. +

+ +

+Memoization +is an optimization technique consisting in caching +the results of a computation for later reuse; this can dramatically +improve performance when calculating recursive numerical functions, +for instance. Key-value flyweights +can be used to implement memoization for a numerical function f +by modeling a memoized invocation of the function as a value of +type flyweight<key_value<int,compute_f> >, where +compute_f is a type that does the computation of +f(n) at its compute_f::compute_f(int) constructor. +For instance, the Fibonacci +numbers can be computed with memoization like this: +

+ +
+typedef flyweight<key_value<int,compute_fibonacci>,no_tracking> fibonacci;
+
+struct compute_fibonacci
+{
+  compute_fibonacci(int n):
+    result(n==0?0:n==1?1:fibonacci(n-2).get()+fibonacci(n-1).get())
+  {}
+
+  operator int()const{return result;}
+  int result;
+};
+
+ +

+The no_tracking +policy is used so that the memoized computations persist for future +use throughout the program. The provided program develops this example in full. +

+ +

Example 6: performance comparison

+ +

+See source code. +

+ +

+This program measures the time and space performances of a simple +string type against several differently configured flyweight +instantations as used in a conventional task involving parsing a file and +doing some manipulations on the parsed text. +Memory consumption is computed by instrumenting the relevant +components (the string type itself, flyweight factories, etc.) with custom +allocators that keep track of the allocations and deallocations requested. +The program has been used to produce the experimental results given +at the performance section. +

+ +

Example 7: custom factory

+ +

+See source code. +

+ +

+The example shows how to write and use a custom factory class. This +"verbose" factory outputs messages tracing the invocations of its public interface +by Boost.Flyweight, so helping the user visualize factory usage patterns. +

+ +
+ + + +
+
+ +
+ +

Revised December 2nd 2008

+ +

© Copyright 2006-2008 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) +

+ + + diff --git a/doc/future_work.html b/doc/future_work.html new file mode 100644 index 0000000..17e48e5 --- /dev/null +++ b/doc/future_work.html @@ -0,0 +1,128 @@ + + + + + +Boost.Flyweight Documentation - Future work + + + + + + + + +

Boost logoBoost.Flyweight Future work

+ + + +
+
+ +
+ +

+New functionalities can be included into future releases of Boost.Flyweight +to meet the demands of users and to leverage upcoming C++0x features +and new Boost libraries. The following is a list of candidate additions. +

+ +

Contents

+ + + +

Introspection API

+ +

+Currently there is no way to access the internal components of a +flyweight instantiation (factory, holder, etc.) or even +to know the types of these components. With such an API it would be +possible to instrument and monitor the usage of Boost.Flyweight like in +the following example: +

+ +
+typedef flyweight<std::string> fw_type;
+...
+std::cout<<"factory used:  "<<typeid(fw_type::factory_type).name()<<std::endl;
+std::cout<<"values stored: "<<fw_type::factory().size()<<std::endl;
+
+ +

Perfect forwarding

+ +

+When constructing a flyweight<T> object, some spurious copies +of objects of type T are incurred in the process of moving the value +into the internal factory. So-called perfect +forwarding, i.e. performing the move without generating temporary +copies, will be solved in an optimum manner by a new +type of rvalue references to be included in the next revision of the +C++ standard. Boost.Flyweight will take advantage of this feature as +compilers begin to provide it. +

+ +

Read/write locking policy

+ +

+The nature of the flyweight pattern implies that most accesses +to the internal flyweight factory do not cause new insertions and can +thus be considered read-only. This hints at the convenience of using +a locking policy based on read/write locks such as those provided by +Boost.Thread. +Implementing a locking policy will also require extending the +Factory concept +to allow for pure lookup operations. Tim Blechmann has provided a +preliminary implementation +of this idea. Before committing to this library extension it is +necessary to do a profiling study to determine whether read/write +locking actually improves performance. +

+ +

Integration with new Boost libraries

+ +

+Recently accepted Boost libraries like +Boost.Functional/Forward +and Boost.Functional/Factory +might be used in the future to replace some internal machinery of +Boost.Flyweight. +

+ +
+ + + +
+
+ +
+ +

Revised September 1st 2008

+ +

© Copyright 2006-2008 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) +

+ + + diff --git a/doc/html.png b/doc/html.png new file mode 100644 index 0000000000000000000000000000000000000000..d06799f33ee1d2a2bc3573e3c60ce3cab7462dfd GIT binary patch literal 24278 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ø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 P3=9mOu6{1-oD!M + + + + +Boost.Flyweight Documentation - Index + + + + + + +

Boost logoBoost Flyweight Library

+ + + +
+ +
+ +

+Flyweights are small-sized handle classes granting constant access to shared +common data, thus allowing for the management of large amounts of entities +within reasonable memory limits. Boost.Flyweight makes it easy to use this +common programming idiom by providing the class template +flyweight<T>, which acts as a drop-in replacement for +const T. +

+ +

+Learning to use Boost.Flyweight can be accomplished in a matter of minutes. +When special needs arise, however, an extensive customization interface +is provided which allows the user to control and extend the following aspects: +

    +
  • Type tagging for separation of domains using the same basic + flyweight types.
  • +
  • Specification and parameterization of the so-called flyweight + factory.
  • +
  • Control of the factory instantiation procedure.
  • +
  • Specification of the internal synchronization mechanisms.
  • +
  • Flyweight tracking, allowing for the disposal of stored + values when no longer referenced by any flyweight object.
  • +
+

+ +

Contents

+ + + +
+ + + +
+ +
+ +

Revised September 3rd 2008

+ +

© Copyright 2006-2008 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) +

+ + + diff --git a/doc/memory.png b/doc/memory.png new file mode 100644 index 0000000000000000000000000000000000000000..703878d0ccb75c89d54bf5440a26fd0eaa4b7a37 GIT binary patch literal 8262 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 R83O|YgQu&X%Q~loCIIrz!y*6x literal 0 HcmV?d00001 diff --git a/doc/memory_gcc_344.png b/doc/memory_gcc_344.png new file mode 100644 index 0000000000000000000000000000000000000000..0870c13416e8ea8c6724dad7ebc6256c066e0395 GIT binary patch literal 10405 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 D8K!=} literal 0 HcmV?d00001 diff --git a/doc/next.gif b/doc/next.gif new file mode 100644 index 0000000000000000000000000000000000000000..d6c18a578d75a4e0ae47981af259b164603e0864 GIT binary patch literal 852 zcmZ?wbhEHb6krfw_|5>L~%oSd9oTwL7T+&nxy zyu7@8e0==;`~m_3f`WoVLPEmA!XhFfqN1W=Vq)Ur;t~=Pl9G~AQc}{=(lRnKva+&r za&q$W@(KzHii(O#N=nMg$|@=KYmvnwpwgT3XuL+B!Nqy1Kf0dV2c$ z`UVCDhK7blMn=ZQ#wI2vrlzK5W@hH*<`xzfmX?-QR#w*5);2aawzjr*c6Rpm_6`mX zj*gB_PEO9w&Mq!4uCA_bZf@@G?j9ZO-;?s%`Gi0t*xzX zZEfxC?HwH*ot>RsU0vPX-90@$y}iACeSQ7?{Szikm^g9bq)C$|Po6ww%9N>7r%szT zZTj@-GiJ<~IdkT$S+i!(o;_#IoVj!7&YL%H{`~n17A#n}aN(jwixw|lykyCerAwDC zTefWZ^5rX5tXR2n<*HSyRoH%*%du|Ns9wpd0|o3k)2V z42%pv+&3(6Y-VDWi}|6S=+wq4Yt^C=_~=lVs9@5W8wHDx_bV6*@vJO->^hOhGN^{b N@X>*3Y|Kmy)&O#?mni@M literal 0 HcmV?d00001 diff --git a/doc/performance.html b/doc/performance.html new file mode 100644 index 0000000..3ef0e2b --- /dev/null +++ b/doc/performance.html @@ -0,0 +1,472 @@ + + + + + +Boost.Flyweight Documentation - Performance + + + + + + + + +

Boost logoBoost.Flyweight Performance

+ + + +
+
+ +
+ +

Contents

+ + + +

Introduction

+ +

+We show how to estimate the memory reduction obtained by the usage of +Boost.Flyweight in a particular scenario and study the impact on the execution +time for the different functional areas of flyweight. +Some experimental results are provided. +

+ +

Memory consumption

+ +

+As we saw in the tutorial rationale, +the flyweight pattern is based on two types of objects: +

    +
  • The flyweight objects proper, which have very small size, typically + that of a pointer. +
  • +
  • The shared values, which are stored as internal entries into the + flyweight factory. +
  • +
+The overall memory consumption is then a function of the size of the +flyweight objects, the size of the entry objects and the degree of +value redundancy. +

+ +

Flyweight size

+ +

+The only data member of a flyweight object is a so-called +handle, an opaque object of small size provided by the internal +flyweight factory to refer to the entries it stores. For the default +hashed_factory, +this handle is merely a pointer, so sizeof(flyweight<T>)=sizeof(void*), +4 bytes in typical 32-bit architectures. +For other types of factories, the handle is an iterator to an internal +container used in the implementation of the factory: again, its size +is typically that of a pointer. +

+ +

Entry size

+ +

+The entries stored in the factory associated to flyweight<T,...> +need not only hold a value of T, but also contain additional +information related to the internal implementation of +flyweight<T,...>: +

+ +
+entry = sizeof(T) + overhead. +
+ +

+For the current implementation of Boost.Flyweight, the following aspects +contribute to overhead: +

+The table summarizes the separate contributions to overhead introduced +by the different components taking part of the definition of +a flyweight instantiation. Values are given in words, +i.e. the size of a pointer, which is 4 bytes in a typical 32-bit architecture. +Alignment may introduce additional overhead. +

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Entry overhead of the components of Boost.Flyweight.
componentoverhead (words)
  key_value    with key extractor    1(1)  
  without key extractor    1 + sizeof(Key)  
  factory    hashed_factory    ~2.5  
  set_factory    4(2)  
  assoc_container_factory    depends on the container used  
  tracking mechanism    refcounted    1(3)  
  no_tracking    0  
+(1) Assuming that sizeof(Key)<=sizeof(Value).
+(2) For some implementations of std::set this overhead reduces to 3.
+(3) In some platforms this value can be 2. +

+ +

+For instance, for the default configuration parameters of flyweight, +overhead is typically 2.5(hashed_factory) + 1(refcounted) += 3 words. +

+ +

Overall memory consumption

+ +

+Consider a scenario where there are N different objects of type T +jointly taking M different values. The objects consume then +S = N·T bytes, where T is defined as the +average size of T (sizeof(T) plus dynamic +memory allocated by T objects). +If we now replace T by some instantiation +flyweight<T,...>, the resulting memory consumption +will be +

+ +
+SF = +N·P + M·(T + overhead), +
+ +

+where P is sizeof(flyweight<T,...>), typically +equal to sizeof(void*), as seen before. +The ratio SF / S is then +

+ +
+SF / S = +(P / T)+ (M / N)(1 + overhead / T). +
+ +

+SF / S tends to its minimum, P / T, +as M / N tends to 0, i.e. when the degree of value redundancy +among T objects grows higher. On the other hand, the worst possible case +SF / S = 1 + (P + overhead) / T +happens when M / N = 1, that is, if there is no value redundancy at all; in this situation there is +no point in applying the flyweight pattern in the first place. +

+ +

+relative memory consumption of Boost.Flyweight as a function of value diversity
+Fig. 1: Relative memory consumption of Boost.Flyweight as a function of value diversity. +

+ +

+Time efficiency +

+ +

+The introduction of the flyweight pattern involves an extra level of indirection +that, in general, results in some execution overhead when accessing the values. On +the other hand, manipulation of flyweight objects is considerably faster than +moving around the heavy values they stand for. We analyze qualitatively the +execution overheads or improvements associated to the different usage contexts +of Boost.Flyweight. +

+ +

Initialization

+ +

+As compared with the initialization an object of type T, constructing +a flyweight<T> performs important extra work like looking +up the value in the flyweight factory and inserting it if it is not present. +So, construction of flyweights (other than copy construction, which is +cheap), is expected to be noticeably slower than the construction of the +underlying type T. Much of the time spent at constructing +the associated T value proper can be saved, however, by +using key-value flyweights. +

+ +

Assignment

+ +

+Assignment of flyweight objects is extremely fast, as it only involves +assigning an internal handle type used to refer to the shared value. Moreover, +assignment of flyweight objects never throws. Assignment time +is influenced by the type of tracking +policy used; in this regard, +no_tracking +is the fastest option. +

+ +

Equality comparison

+ +

+Comparing two flyweight objects for equality reduces to +checking that the addresses of the values they are associated to +are equal; in general, this operation is much faster than comparing the +underlying values. This aspect is of particular relevance when the flyweight +objects stand for complex values like those arising in the application of +the composite pattern. +

+ +

Value access

+ +

+The conversion from flyweight<T> to const T& +relies on a level of indirection relating the flyweight objects to the +values they are associated to; so, value access is expected to be slower +when using Boost.Flyweight as compared to using the associated values +directly. This overhead, however, can be masked by an indirect improvement +resulting from locality and cache effects: as the set of different T +values handled by an instantiation of flyweight<T> is +generally much smaller than the equivalent family of T objects +when Boost.Flyweight is not used, active values can fit better +into the processor cache. +

+ +

Experimental results

+ +

+A profiling program was devised to test +the space and time efficiency of different instantiations of flyweight +against a base situation not using Boost.Flyweight. The profiled scenarios are: +

    +
  1. std::string.
  2. +
  3. flyweight<std::string> with default configuration aspects + (hashed_factory, + refcounted tracking, + simple_locking). +
  4. +
  5. flyweight<std::string,no_tracking>.
  6. +
  7. flyweight<std::string,set_factory>.
  8. +
  9. flyweight<std::string,set_factory,no_tracking>.
  10. +
+

+ +

+Actually the types tested are not exactly those listed above, but instrumented +versions that keep track of the allocated memory for profiling purposes. +The program parses a text file into an array of words and then perform various +manipulations involving the different context usages of Boost.Flyweight discussed +previously. As our text file we have used the +plain text +version of Project Gutenberg edition of Don +Quijote (2.04 MB). +

+ +

Microsoft Visual C++ 8.0

+ +

+The program was built with default release settings and _SECURE_SCL=0. +Tests were run under Windows XP in a machine equipped with an Intel Core 2 Duo T5500 +processor and 1 GB of RAM. +

+ +

Memory

+ +

+memory consumption (MB), MSVC++ 8.0
+Fig. 2: Memory consumption, MSVC++ 8.0. Values in MB. +

+ +

+The results show the memory consumption figures for the different profiled +scenarios. +The standard library implementation of MSVC++ 8.0 features the so-called +small buffer optimization for strings, by which std::string +objects hold a small buffer that can be used when the string is short, +thus avoding dynamic allocations. This results in sizeof(std::string) +being quite high, 28 bytes. In our particular test strings are almost always +held in the small buffer, so the minimum SF / S +achievable is 4/28 = 14.3%, which is quite close to the experimental +results, given that the memory devoted to storage of shared values +is residual (around 3% of total memory) due to the high word redundancy +of the text source. +

+ +

Execution time

+ +

+execution time (s), MSVC++ 8.0
+Fig. 3: Execution time, MSVC++ 8.0. Values in seconds. +

+ +

+The figure displays execution times for the profiled scenarios in different +usage contexts. In accordance with our previous +qualitative analysis, initialization of flyweights +carries an important overhead with respect to the base case scenario (between 10% and 40% +of additional execution time), while the other usage contexts +(assignment, equality comparison and value access) have performance gains, +with speedup factors of up to 14 in some cases. The use of a +refcounted +tracking policy introduces penalties with respect to +no_tracking +in initialization and assignment, but has no effect in equality comparison +and value access. +

+ +

GNU GCC 3.4.4

+ +

+The Cygwin/MinGW version of the compiler was used, with command options +-ftemplate-depth-128 -O3 -finline-functions -DNDEBUG. +Tests were run under a Cygwin terminal in the same machine as before. +

+ +

Memory

+ +

+memory consumption (MB), GCC 3.4.4
+Fig. 4: Memory consumption, GCC 3.4.4. Values in MB. +

+ +

+The standard library used by GCC 3.4.4 implements std::string +using copy-on-write +optimization techniques, which leads to very small value redundancy for +some usage patterns. This explains why the memory reduction achieved +by Boost.Flyweight is so poor in this case. Other contexts where assignment +is much less used than direct construction will favor Boost.Flyweight +over plain copy-on-write std::strings. +

+ +

Execution time

+ +

+execution time (s), GCC 3.4.4
+Fig. 5: Execution time, GCC 3.4.4. Values in seconds. +

+ +

+Relative performance figures are similar to those obtained for +MSVC++ 8.0, although some of the +speedups achieved by Boost.Flyweight are higher here (×25 +in equality comparison and up to ×100 in assignment when +no_tracking +is in effect). +

+ +

Conclusions

+ +

+The introduction of Boost.Flyweight in application scenarios with very +high value redundancy yields important reductions in memory consumption: +this is especially relevant when data volume approaches the limits of +physical memory in the machine, since Boost.Flyweight can avoid virtual +memory thrashing thus making the application viable. We have shown +how to estimate the achievable reduction in memory consumption from +some basic value statistics and knowledge of the flyweight +configuration aspects being used. +

+ +

+Boost.Flyweight can also accelerate execution times in areas other than +object initialization, due to the fastest manipulation of small +flyweight objects and to locality and cache effects arising from the +drastic reduction of the set of allocated values. +

+ +
+ + + +
+
+ +
+ +

Revised December 2nd 2008

+ +

© Copyright 2006-2008 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) +

+ + + diff --git a/doc/prev.gif b/doc/prev.gif new file mode 100644 index 0000000000000000000000000000000000000000..c35dfeec25d2397b8746300b0bf6a62caacd728e GIT binary patch literal 852 zcmZ?wbhEHb6krfw_|5>L~%oSd9oTwL7T+&nxy zyu7@8e0==;`~m_3f`WoVLPEmA!XhFfqN1W=Vq)Ur;t~=Pl9G~AQc}{=(lRnKva+&r za&q$W@(KzHii(O#N=nMg$|@=KYmvnwpwgT3XuL+B!Nqy1Kf0dV2c$ z`UVCDhK7blMn=ZQ#wI2vrlzK5W@hH*<`xzfmX?-QR#w*5);2aawzjr*c6Rpm_6`mX zj*gB_PEO9w&Mq!4uCA_bZf@@G?j9ZO-;?s%`Gi0t*xzX zZEfxC?HwH*ot>RsU0vPX-90@$y}iACeSQ7?{Szikm^g9bq)C$|Po6ww%9N>7r%szT zZTj@-GiJ<~IdkT$S+i!(o;_#IoVj!7&YL%H{`~n17A#n}aN(jwixw|lykyCerAwDC zTefWZ^5rX5tXR2n<*HSyRoH%*%du|Ns9wpd0|o3k)2V z4F5T0JSHeGFt7^$v#tnu=+MR^>(nx%;E_wSn7-bb6B`#F?`N`itKrzRz`avaw(ZJ_ NqU6KVRG66 + + + + +Boost.Flyweight Documentation - Factories reference + + + + + + + + +

Boost logoBoost.Flyweight +Factories reference

+ + + +
+ +
+ +

Contents

+ + + +

Factories and factory specifiers

+ +

+Given a type Key and an +Assignable +type Entry implicitly convertible to const Key&, a +factory of Entry elements (implicitly associated to +Key) is a +Default +Constructible entity able to store and retrieve immutable elements of +type Entry. A factory is governed by an associated equivalence +relation defined on Key so that no two +Entry objects convertible to equivalent Keys +can be stored simultaneously in the factory. Different factory types can +use different equivalence relations. +

+ +

+In the following table, Factory is a factory of elements +of type Entry, f denotes an object of type Factory, +x is an object of type Entry and h is a +value of Factory::handle_type. +

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Factory requirements.
expressionreturn typeassertion/note
pre/post-condition
Factory::handle_typehandle to elements of type T
+ stored in the factory +
handle_type is + Assignable + and its copy and
+ assignment operations never throw an exception. +
f.insert(x);handle_typeInserts a copy of x if there is no equivalent entry in f;
+ returns a handle to the inserted or equivalent element. +
f.erase(h);voidErases the element associated to h.
+ This operation does not throw. +
f.entry(h);const Entry&Returns a reference to the element associated to h.
+ This operation does not throw. +
+

+ +

+Additionally to the basic thread safety guarantee which is implicitly assumed +for most classes including the majority of components of the +C++ standard library, it is required that the member function entry +can be invoked simultaneously from different threads, even in the presence +of concurrent accesses to insert and erase (as long +as the entry returned by entry is not the one which is being +erased). +

+ +

+A type S is said to be a factory specifier if: +

    +
  1. One of the following conditions is satisfied: +
      +
    1. is_factory<S>::type is + boost::mpl::true_,
    2. +
    3. S is of the form factory<S'>.
    4. +
    +
  2. +
  3. S, or S' if (b) applies, is an + MPL Lambda + Expression such that invoking it with types (Entry, + Key) resolves to a factory type of Entry elements + (implicitly associated to Key). +
  4. +
+

+ +

Header +"boost/flyweight/factory_tag.hpp" synopsis

+ +
+namespace boost{
+
+namespace flyweights{
+
+struct factory_marker;
+
+template<typename T>
+struct is_factory;
+
+template<typename T>
+struct factory;
+
+} // namespace boost::flyweights
+
+} // namespace boost
+
+ +

Class template is_factory

+ +

+Unless specialized by the user, is_factory<T>::type is +boost::mpl::true_ +if T is derived from factory_marker, and it is +boost::mpl::false_ +otherwise. +

+ +

Class template factory

+ +

+factory<T> is a syntactic construct meant to indicate +that T is a factory specifier without resorting to the +mechanisms provided by the is_factory class template. +

+ +

Header +"boost/flyweight/hashed_factory_fwd.hpp" synopsis

+ +
+namespace boost{
+
+namespace flyweights{
+
+template<
+  typename Entry,typename Key,
+  typename Hash=implementation defined,
+  typename Pred=implementation defined,
+  typename Allocator=implementation defined
+>
+class hashed_factory_class;
+
+template<
+  typename Hash=implementation defined,
+  typename Pred=implementation defined,
+  typename Allocator=implementation defined
+>
+struct hashed_factory;
+
+} // namespace boost::flyweights
+
+} // namespace boost
+
+ +

+hashed_factory_fwd.hpp forward declares the class templates +hashed_factory_class +and hashed_factory. +

+ +

Header +"boost/flyweight/hashed_factory.hpp" synopsis

+ +

Class template hashed_factory_class

+ +

+hashed_factory_class is a Factory +implemented with a hashed container. +

+ +
+template<
+  typename Entry,typename Key,
+  typename Hash,typename Pred,typename Allocator
+>
+class hashed_factory_class
+{
+public:
+  typedef implementation defined handle_type;
+  
+  handle_type  insert(const Entry& x);
+  void         erase(handle_type h);
+  const Entry& entry(handle_type h);
+};
+
+ +

+Hash is a +Default +Constructible +Unary Function +taking a single argument of type Key and returning a +value of type std::size_t in the range +[0, std::numeric_limits<std::size_t>::max()). +Pred is a +Default +Constructible + +Binary Predicate inducing an equivalence relation +on elements of Key. It is required that +a Hash object return the same value for objects +equivalent under Pred. +The equivalence relation on Key associated to the factory is +that induced by Pred. +The default arguments for Hash and Pred are +boost::hash<Key> +and std::equal_to<Key>, respectively. +Allocator must be an allocator of Entry objects +satisfying the associated C++ requirements at [lib.allocator.requirements]. +The default argument is std::allocator<Entry>. The internal +hashed container upon which hashed_factory_class is based is +constructed with default initialized objects of type Hash, +Pred and Allocator. +

+ +

Class template hashed_factory

+ +

+Factory Specifier for hashed_factory_class. +

+ +
+template<typename Hash,typename Pred,typename Allocator>
+struct hashed_factory;
+
+ +

+hashed_factory<Hash,Pred,Allocator> is an +MPL Metafunction +Class such that the type +

+ +
+boost::mpl::apply<
+  hashed_factory<Hash,Pred,Allocator>,
+  Entry,Key
+>::type
+
+ +

+is the same as +

+ +
+boost::mpl::apply<
+  hashed_factory_class<boost::mpl::_1,boost::mpl::_2,Hash,Pred,Allocator>,
+  Entry,Key
+>::type
+
+ +

+This implies that Hash, Pred and Allocator +can be +MPL +Placeholder Expressions resolving to the actual types used by +hashed_factory_class. +

+ +

Header +"boost/flyweight/set_factory_fwd.hpp" synopsis

+ +
+namespace boost{
+
+namespace flyweights{
+
+template<
+  typename Entry,typename Key,
+  typename Compare=implementation defined,
+  typename Allocator=implementation defined
+>
+class set_factory_class;
+
+template<
+  typename Compare=implementation defined,
+  typename Allocator=implementation defined
+>
+struct set_factory;
+
+} // namespace boost::flyweights
+
+} // namespace boost
+
+ +

+set_factory_fwd.hpp forward declares the class templates +set_factory_class +and set_factory. +

+ +

Header +"boost/flyweight/set_factory.hpp" synopsis

+ +

Class template set_factory_class

+ +

+set_factory_class is a Factory +implemented on top of an orderded associative container. +

+ +
+template<
+  typename Entry,typename Key,
+  typename Compare,typename Allocator
+>
+class set_factory_class
+{
+public:
+  typedef implementation defined handle_type;
+  
+  handle_type  insert(const Entry& x);
+  void         erase(handle_type h);
+  const Entry& entry(handle_type h);
+};
+
+ +

+Compare is a +Default +Constructible + +Strict Weak Ordering on Key. Two Keys +x and y are considered equivalent if +!c(x,y)&&!c(y,x) for c of type Compare. +The default argument of Compare is std::less<Key> +Allocator must be an allocator of Entry objects +satisfying the associated C++ requirements at [lib.allocator.requirements]. +The default argument is std::allocator<Entry>. The internal +container upon which set_factory_class is based is +constructed with default initialized objects of type Compare +and Allocator. +

+ +

Class template set_factory

+ +

+Factory Specifier for set_factory_class. +

+ +
+template<typename Compare,typename Allocator>
+struct set_factory;
+
+ +

+set_factory<Compare,Allocator> is an +MPL Metafunction +Class such that the type +

+ +
+boost::mpl::apply<
+  set_factory<Compare,Allocator>,
+  Entry,Key
+>::type
+
+ +

+is the same as +

+ +
+boost::mpl::apply<
+  set_factory_class<boost::mpl::_1,boost::mpl::_2,Compare,Allocator>,
+  Entry,Key
+>::type
+
+ +

+This implies that Compare and Allocator +can be +MPL +Placeholder Expressions resolving to the actual types used by +set_factory_class. +

+ +

Header +"boost/flyweight/assoc_container_factory_fwd.hpp" synopsis

+ +
+namespace boost{
+
+namespace flyweights{
+
+template<typename Container>
+class assoc_container_factory_class;
+
+template<typename ContainerSpecifier>
+struct assoc_container_factory;
+
+} // namespace boost::flyweights
+
+} // namespace boost
+
+ +

+assoc_container_factory_fwd.hpp forward declares the class templates +assoc_container_factory_class +and assoc_container_factory. +

+ +

Header +"boost/flyweight/assoc_container_factory.hpp" synopsis

+ +

Class template assoc_container_factory_class

+ +

+assoc_container_factory_class wraps a suitable associative container +to provide a Factory interface. +

+ +
+template<typename Container>
+class assoc_container_factory_class
+{
+public:
+  typedef typename Container::iterator handle_type;
+  
+  handle_type insert(const typename Container::value_type& x);
+  void        erase(handle_type h);
+  const typename Container::value_type& entry(handle_type h);
+};
+
+ +

+Container must be an (ordered or unordered) associative container +such that +

    +
  1. Container::key_type is the same as + Container::value_type (which is the entry type associated to + the factory). +
  2. +
  3. Unique keys (rather than equivalent keys) are supported.
  4. +
  5. Container is stable, i.e. its iterators are not + invalidated upon insert or erase operations.
  6. +
+The equivalence relation associated to assoc_container_factory_class +is the one induced by Container. If equivalence of elements +of Container::value_type is determined solely on the basis of a +type value_type' to which value_type is +implicitly convertible, then assoc_container_factory_class is +a factory of entries of type value_type implicitly associated to +value_type'. For example, the instantiation +

+ +
+assoc_container_factory_class<
+  std::set<derived,std::less<base> > // derived inherits from base
+>
+
+ +

+is a factory of derived elements implicitly associated to +base. +

+ +

Class template assoc_container_factory

+ +

+Factory Specifier for assoc_container_factory_class. +

+ +
+template<typename ContainerSpecifier>
+struct assoc_container_factory;
+
+ +

+ContainerSpecifier must be an +MPL Lambda +Expression resolving, when invoked with (Entry, +Key), to a type Container such that +assoc_container_factory_class<Container> is a factory +of Entry elements implicitly associated to Key. +

+ +
+ + + +
+ +
+ +

Revised August 13th 2008

+ +

© Copyright 2006-2008 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) +

+ + + diff --git a/doc/reference/flyweight.html b/doc/reference/flyweight.html new file mode 100644 index 0000000..e0cf998 --- /dev/null +++ b/doc/reference/flyweight.html @@ -0,0 +1,630 @@ + + + + + +Boost.Flyweight Documentation - flyweight reference + + + + + + + + +

Boost logoBoost.Flyweight +flyweight reference

+ + + +
+ +
+ +

Contents

+ + + +

+Header +"boost/flyweight/flyweight_fwd.hpp" +synopsis +

+ +
+namespace boost{
+  
+namespace flyweights{
+
+template<
+  typename T,
+  typename Arg1=implementation defined,
+  typename Arg2=implementation defined,
+  typename Arg3=implementation defined,
+  typename Arg4=implementation defined,
+  typename Arg5=implementation defined
+>
+class flyweight;
+
+// comparison:
+
+// OP is any of ==,<,!=,>,>=,<=
+
+template<
+  typename T1,typename Arg11,...,typename Arg15,
+  typename T2,typename Arg21,...,typename Arg25
+>
+bool operator OP(
+  const flyweight<T1,Arg11,...,Arg15>& x,
+  const flyweight<T2,Arg21,...,Arg25>& y);
+
+template<
+  typename T1,typename Arg11,...,typename Arg15,
+  typename T2
+>
+bool operator OP(const flyweight<T1,Arg11,...,Arg15>& x,const T2& y);
+
+template<
+  typename T1,
+  typename T2,typename Arg21,...,typename Arg25
+>
+bool operator OP(const T1& x,const flyweight<T2,Arg21,...,Arg25>& y);
+
+// specialized algorithms:
+
+template<typename T,typename Arg1,...,typename Arg5>
+inline void swap(
+  flyweight<T,Arg1,...,Arg5>& x,flyweight<T,Arg1,...,Arg5>& y);
+
+template<
+  typename ElemType,typename Traits, 
+  typename T,typename Arg1,...,typename Arg5
+>
+inline std::basic_ostream<ElemType,Traits>& operator<<(
+  std::basic_ostream<ElemType,Traits>& out,
+  const flyweight<T,Arg1,...,Arg5>& x);
+
+template<
+  typename ElemType,typename Traits, 
+  typename T,typename Arg1,...,typename Arg5
+>
+inline std::basic_ostream<ElemType,Traits>& operator>>(
+  std::basic_istream<ElemType,Traits>& in,
+  flyweight<T,Arg1,...,Arg5>& x);
+
+} // namespace boost::flyweights
+
+using flyweights::flyweight;
+
+} // namespace boost
+
+ +

+flyweight_fwd.hpp forward declares the class template +flyweight and its associated global functions. +

+ +

+Header +"boost/flyweight/flyweight.hpp" +synopsis +

+ +

+Class template flyweight +

+ +

+Objects of type flyweight<...> provide access to immutable +values of type flyweight<...>::value_type, with the following advantages over using +plain value_type objects: +

    +
  • Flyweight objects with equivalent value share the same representation + (the associated value_type object). +
  • +
  • The size of flyweights is typically that of a pointer, which is in general + smaller than sizeof(value_type). +
  • +
+ +So, if the level of redundancy (ratio of total objects to different values) +is high enough, substituting a suitable instantiation of flyweight +for value_type results in a reduction in memory usage. +

+ +

+flyweight is parameterized according to some aspects: +

    +
  • Types key_value and value_type + (possibly equal), where key_type serves as a + key type to lookup and construct internal shared instances of + objects of value_type. +
  • +
  • An optional tag type meant to syntactically + differentiate between otherwise identical instantiations. +
  • +
  • The factory class used to store + and retrieve the shared value objects. +
  • +
  • The type of holder used to + instantiate the flyweight factory and a mutex object, both of + which are unique to each specialization of the flyweight + class template. +
  • +
  • A locking policy determining + the synchronization mechanisms for internal access to shared resources. +
  • +
  • A tracking policy which controls + how values are treated when all their associated flyweight objects are + destroyed. +
  • +
+These aspects impact the internal structure and behavior +of the flyweight instantiation in the following manner: +
    +
  • Each instantation of flyweight internally owns + a unique factory object and a unique synchronization + mutex object, both of which + are created through the use of an associated holder type. +
  • +
  • The flyweight factory stores elements of an undisclosed type + Entry that is implicitly convertible to + const key_type& and also stores a subobject of + value_type. Every flyweight object is associated + to a value_type subobject of some Entry + stored in the factory. +
  • +
  • The associated mutex object is used to protect all invocations + to the insertion and deletion functions of the internal flyweight + factory. +
  • +
  • Each flyweight object internally stores a value of some + undisclosed type Handle. Handle and + the Entry type referred to above are obtained + from invocations to the associated tracking policy, in the + manner described for this concept. +
  • +
+In what follows, we implicitly assume that key_type equivalence +refers to the equivalence relationship induced by the factory class used. +Also, two values of value_type are considered equivalent +if they are constructed from equivalent keys, or are copies of +objects constructed from equivalent keys. +

+ +
+template<
+  typename T,
+  typename Arg1,typename Arg2,typename Arg3,typename Arg4,typename Arg5
+>
+class flyweight
+{
+public:
+  typedef dependent on T key_type;
+  typedef dependent on T value_type;
+
+  // static data initialization:
+
+  static bool init();
+  class initializer{public:initializer();};
+    
+  // construct/copy/destroy:
+  
+  flyweight();
+  flyweight(const flyweight& x);
+  flyweight(flyweight& x);
+
+  // forwarding constructors:
+  // n is implementation defined. All combinations of constant
+  // and non constant reference arguments are provided.
+
+  template<typename T0>
+  explicit flyweight([const] T0& t0);
+  template<typename T0,typename T1>
+  flyweight([const] T0& t0,[const] T1& t1);
+  ...
+  template<typename T0,...,typename Tn-1>
+  flyweight([const] T0& t0,...,[const] Tn-1& tn-1);
+
+  flyweight& operator=(const flyweight& x);  
+  flyweight& operator=(const value_type& x);
+
+  // convertibility to underlying type:
+
+  const key_type&   get_key()const;
+  const value_type& get()const;
+  operator const    value_type&()const;  
+
+  // modifiers:
+
+  void swap(flyweight& x);
+};
+
+ +

Instantiation types

+ +

+T can be either: +

+In the first case, the nested types key_type and value_type +are both equal to T. In the second case, key_type=Key, +value_type=Value; we say then that the instantiation +of flyweight is a key-value flyweight. +value_type is the type of the values flyweight objects give access to, +while value lookup is based on associated key_type values. +key_value must be +Assignable +and value_type must be constructible from key_type; +additionally, key_value must +conform to any extra requirements imposed by the type of factory used. +For key-value flyweights, it is guaranteed that the creation or assignment of a flyweight +object results in at most one construction (or copy construction in some +particular cases) of an object +of value_type, and this construction only occurs in the case that no +equivalent value existed previously in the flyweight factory. +

+ +

+The types Arg1, ... , Arg5, if provided, must be any +of the following, in no particular order: +

+No aspect can be specified twice. Each internal component of the +flyweight instantiation is obtained through use of the +corresponding specifier; for instance, the factory results from a +certain (MPL) invocation of the given factory specifier, the internal +mutex from the given locking policy, etc. +The default configuration arguments are: + +

+ +

Static data initialization

+ +

+The static data internal to a given flyweight instantiation +(factory instance, etc.) is constructed during the dynamic initialization +phase of the program and always before the first program-wide use of the +instantiated class. The following utilities can be +used when more control about the moment of construction is required. +

+ +static bool init(); + +
+Effects: After execution of this function the static data associated +to the instantiation of flyweight is guaranteed to be +constructed.
+Note: Concurrent execution of this function is not thread safe. +
+ +initializer::initializer(); + +
+Effects: Executes init(). +
+ +

Constructors, copy and assignment

+ +flyweight(); + +
+Requires: key_type is +Default +Constructible.
+Effects: Constructs a flyweight object associated +with value value_type(key_type()). +
+ +flyweight(const flyweight& x);
+flyweight(flyweight& x);
+ +
+Effects: Constructs a flyweight object with value +x.get().
+Exception safety: nothrow. +
+ + +template<typename T0>
+explicit flyweight([const] T0& t0);
+template<typename T0,typename T1>
+flyweight([const] T0& t0,[const] T1& t1);
+...
+template<typename T0,...,typename Tn-1>
+flyweight([const] T0& t0,...,[const] Tn-1& tn-1);
+ +
+Effects: Constructs a flyweight object with value +value_type(key_type(t0,...,ti)), up to an implementation defined number +of arguments.
+Note: In this implementation, the maximum number of arguments +can be globally configured by the user. +
+ +flyweight& operator=(const flyweight& x); + +
+Effects: Associates the flyweight object with the same value +as x.
+Returns: *this.
+Exception safety: nothrow. +
+ +flyweight& operator=(const value_type& x); + +
+Requires: If flyweight is key-value, +value_type is +Assignable +and the +Key Extractor +KeyFromValue must have been supplied as part of the +key_value<> construct.
+Effects: Associates the flyweight object with a +copy of x or with a value_type constructed +from a key equivalent to that associated to x. For non-key-value +flyweights, x is its own key; for key-value flyweights, +the key is extracted through use of an object of type KeyFromValue.
+Returns: *this.
+
+ +

Convertibility to the underlying types

+ +const key_type& get_key()const; + +
+Return: A copy of the key used to construct the +value_type associated to the flyweight +object.
+Exception safety: If flyweight is not key-value or +if KeyFromValue was not provided, nothrow. +
+ +const value_type& get()const;
+ operator const value_type&()const;
+ +
+Return: The value associated to the flyweight +object.
+Exception safety: nothrow. +
+ +

Modifiers

+ +void swap(flyweight& x); + +
+Effects: Swaps the associations to value_types each +flyweight object has. No swapping of key_type or +value_type objects is done.
+Exception safety: nothrow. +
+ +

Comparison operators

+ +template<
+  typename T1,typename Arg11,...,typename Arg15,
+  typename T2,typename Arg21,...,typename Arg25
+>
+bool operator ==(
+  const flyweight<T1,Arg11,...,Arg15>& x,
+  const flyweight<T2,Arg21,...,Arg25>& y);
+ +
+Returns: If x and y are of the same type, returns +true if and only if they are associated to the same value; if +x and y have different types, returns +x.get()==y.get().
+Exception safety: If x and y are of the same type, +nothrow. +
+ +template<
+  typename T1,typename Arg11,...,typename Arg15,
+  typename T2
+>
+bool operator ==(const flyweight<T1,Arg11,...,Arg15>& x,const T2& y);
+ +
+Returns: x.get()==y. +
+ +template<
+  typename T1,
+  typename T2,typename Arg21,...,typename Arg25
+>
+bool operator ==(const T1& x,const flyweight<T2,Arg21,...,Arg25>& y);
+ +
+Returns: x()==y.get(). +
+ +template<
+  typename T1,typename Arg11,...,typename Arg15,
+  typename T2,typename Arg21,...,typename Arg25
+>
+bool operator <(
+  const flyweight<T1,Arg11,...,Arg15>& x,
+  const flyweight<T2,Arg21,...,Arg25>& y);
+ +
+Returns: x.get()<y.get(). +
+ +template<
+  typename T1,typename Arg11,...,typename Arg15,
+  typename T2
+>
+bool operator <(const flyweight<T1,Arg11,...,Arg15>& x,const T2& y);
+ +
+Returns: x.get()<y. +
+ +template<
+  typename T1,
+  typename T2,typename Arg21,...,typename Arg25
+>
+bool operator <(const T1& x,const flyweight<T2,Arg21,...,Arg25>& y);
+ +
+Returns: x()<y.get(). +
+ + +template<
+  typename T1,typename Arg11,...,typename Arg15,
+  typename T2,typename Arg21,...,typename Arg25
+>
+bool operator OP(
+  const flyweight<T1,Arg11,...,Arg15>& x,
+  const flyweight<T2,Arg21,...,Arg25>& y);
+template<
+  typename T1,typename Arg11,...,typename Arg15,
+  typename T2
+>
+bool operator OP(const flyweight<T1,Arg11,...,Arg15>& x,const T2& y);
+template<
+  typename T1,
+  typename T2,typename Arg21,...,typename Arg25
+>
+bool operator OP(const T1& x,const flyweight<T2,Arg21,...,Arg25>& y);
+ +

+(OP is any of !=, >, +>=, <=.) +

+ +
+Returns: true if and only if +
+!(x==y) (OP is !=),
+  y< x  (OP is ),
+!(x< y) (OP is >=),
+!(y< x) (OP is <=). +
+
+ +

Specialized algorithms

+ +template<typename T,typename Arg1,...,typename Arg5>
+inline void swap(
+  flyweight<T,Arg1,...,Arg5>& x,flyweight<T,Arg1,...,Arg5>& y);
+ +
+Effects: x.swap(y). +
+ +template<
+  typename ElemType,typename Traits,
+  typename T,typename Arg1,...,typename Arg5
+>
+inline std::basic_ostream<ElemType,Traits>& operator<<(
+  std::basic_ostream<ElemType,Traits>& out,
+  const flyweight<T,Arg1,...,Arg5>& x);
+ +
+Effects: out<<x.get().
+Returns: out. +
+ +template<
+  typename ElemType,typename Traits,
+  typename T,typename Arg1,...,typename Arg5
+>
+inline std::basic_ostream<ElemType,Traits>& operator>>(
+  std::basic_istream<ElemType,Traits>& in,
+  flyweight<T,Arg1,...,Arg5>& x);
+ +
+Requires: If flyweight is key-value, +value_type is +Assignable +and the +Key Extractor +KeyFromValue must have been supplied as part of the +key_value<> construct.
+Effects: Reads an object of type value_type from in +and assigns it to x.
+Returns: in. +
+ +

Configuration macros

+ + +BOOST_FLYWEIGHT_LIMIT_PERFECT_FWD_ARGS + +
+Effects: Globally define this macro to set the maximum number of +arguments accepted by flyweight +forwarding constructors, which by default +is 5. +
+ +
+ + + +
+ +
+ +

Revised December 2nd 2008

+ +

© Copyright 2006-2008 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) +

+ + + diff --git a/doc/reference/holders.html b/doc/reference/holders.html new file mode 100644 index 0000000..c8e910d --- /dev/null +++ b/doc/reference/holders.html @@ -0,0 +1,243 @@ + + + + + +Boost.Flyweight Documentation - Holders reference + + + + + + + + +

Boost logoBoost.Flyweight +Holders reference

+ + + +
+ +
+ +

Contents

+ + + +

Holders and holder specifiers

+ +

+Given a type C, a type Holder is said to be a holder +of C if the expression Holder::get() returns +a reference to a default initialized C object unique to +Holder. No invocation of Holder::get(), except possibly +the first one in the program, does throw. +flyweight +privately uses a holder to instantiate a factory +and some additional data (like a mutex for +internal synchronization) unique to each instantiation type of the class template. +

+ +

+A type S is a holder specifier if: +

    +
  1. One of the following conditions is satisfied: +
      +
    1. is_holder<S>::type is + boost::mpl::true_,
    2. +
    3. S is of the form holder<S'>.
    4. +
    +
  2. +
  3. S, or S' if (b) applies, is an + MPL Lambda + Expression such that invoking it with type C resolves to + a holder of C. +
  4. +
+

+ +

Header +"boost/flyweight/holder_tag.hpp" synopsis

+ +
+namespace boost{
+
+namespace flyweights{
+
+struct holder_marker;
+
+template<typename T>
+struct is_holder;
+
+template<typename T>
+struct holder;
+
+} // namespace boost::flyweights
+
+} // namespace boost
+
+ +

Class template is_holder

+ +

+Unless specialized by the user, is_holder<T>::type is +boost::mpl::true_ +if T is derived from holder_marker, and it is +boost::mpl::false_ +otherwise. +

+ +

Class template holder

+ +

+holder<T> is a syntactic construct meant to indicate +that T is a holder specifier without resorting to the +mechanisms provided by the is_holder class template. +

+ +

Header +"boost/flyweight/static_holder_fwd.hpp" synopsis

+ +
+namespace boost{
+
+namespace flyweights{
+
+template<typename C>
+struct static_holder_class;
+
+struct static_holder;
+
+} // namespace boost::flyweights
+
+} // namespace boost
+
+ +

+static_holder_fwd.hpp forward declares +static_holder_class +and static_holder. +

+ +

Header +"boost/flyweight/static_holder.hpp" synopsis

+ +

Class template static_holder_class

+ +

+static_holder_class<C> keeps its unique instance of C as a +local static object. +

+ +

Class static_holder

+ +

+Holder Specifier for static_holder_class. +

+ +

Header +"boost/flyweight/intermodule_holder_fwd.hpp" synopsis

+ +
+namespace boost{
+
+namespace flyweights{
+
+template<typename C>
+struct intermodule_holder_class;
+
+struct intermodule_holder;
+
+} // namespace boost::flyweights
+
+} // namespace boost
+
+ +

+intermodule_holder_fwd.hpp forward declares +intermodule_holder_class +and intermodule_holder. +

+ +

Header +"boost/flyweight/intermodule_holder.hpp" synopsis

+ +

Class template intermodule_holder_class

+ +

+intermodule_holder_class<C> maintains a C +instance which is unique even across different dynamically linked modules of +the program using this same type. In general, this guarantee is not provided by +static_holder_class, as most +C++ implementations are not able to merge duplicates of static variables stored +in different dynamic modules of a program. +

+ +

Class intermodule_holder

+ +

+Holder Specifier for intermodule_holder_class. +

+ +
+ + + +
+ +
+ +

Revised August 11th 2008

+ +

© Copyright 2006-2008 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) +

+ + + diff --git a/doc/reference/index.html b/doc/reference/index.html new file mode 100644 index 0000000..a9754a1 --- /dev/null +++ b/doc/reference/index.html @@ -0,0 +1,158 @@ + + + + + +Boost.Flyweight Documentation - Reference + + + + + + + + +

Boost logoBoost.Flyweight Reference

+ + + +
+ +
+ +

Contents

+ + + +

Header summary

+ +

+Boost.Flyweight comprises the following public headers: +

+

+ +

+Boost.Flyweight is a header-only library, requiring no additional +object modules. +

+ +

+Header +"boost/flyweight.hpp" +synopsis +

+ +
+#include <boost/flyweight/flyweight.hpp>
+#include <boost/flyweight/hashed_factory.hpp>
+#include <boost/flyweight/refcounted.hpp>
+#include <boost/flyweight/simple_locking.hpp>
+#include <boost/flyweight/static_holder.hpp>
+
+ +

+This convenience header includes the main class template +flyweight along with +the default components used by flyweight. +

+ +
+ + + +
+ +
+ +

Revised December 2nd 2008

+ +

© Copyright 2006-2008 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) +

+ + + diff --git a/doc/reference/key_value.html b/doc/reference/key_value.html new file mode 100644 index 0000000..d1d0364 --- /dev/null +++ b/doc/reference/key_value.html @@ -0,0 +1,124 @@ + + + + + +Boost.Flyweight Documentation - Key-value flyweights reference + + + + + + + + +

Boost logoKey-value flyweights reference

+ + + +
+ +
+ +

Contents

+ + + +

Key extractors

+ +

+Let Key be a type with some implicit equivalence relationship +and Value a type constructible from Key. +A Default +Constructible type KeyFromValue is said +to be a key extractor from Value to Key if +

    +
  1. kfv(cv) is defined and have type const Key&,
  2. +
  3. kfv(cv) is equivalent to kfv(Value(cv)),
  4. +
  5. kfv(Value(k)) is equivalent to k,
  6. +
+for every kfv of type const KeyFromValue, +cv of type const Value and +k of type Key. +

+ +

Header +"boost/flyweight/key_value_fwd.hpp" synopsis

+ +
+namespace boost{
+
+namespace flyweights{
+
+struct no_key_from_value;
+
+template<
+  typename Key,typename Value,
+  typename KeyFromValue=no_key_from_value
+>
+struct key_value;
+
+} // namespace boost::flyweights
+
+} // namespace boost
+
+ +

Header +"boost/flyweight/key_value.hpp" synopsis

+ +

Class template key_value

+ +

+In flyweight instantiations +of the form flyweight<T,...>, the associated +key_type and value_type are both equal to T. +Instantiations of the form flyweight<key_value<Key,Value[,KeyFromValue]>,...> +allow to specify these types separately. Key and Value +must be different types. When provided, KeyFromValue +must be a Key Extractor from +Value to Key. +

+ +
+ + + +
+ +
+ +

Revised September 15th 2008

+ +

© Copyright 2006-2008 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) +

+ + + diff --git a/doc/reference/locking.html b/doc/reference/locking.html new file mode 100644 index 0000000..f8369a6 --- /dev/null +++ b/doc/reference/locking.html @@ -0,0 +1,287 @@ + + + + + +Boost.Flyweight Documentation - Locking policies reference + + + + + + + + +

Boost logoBoost.Flyweight +Locking policies reference

+ + + +
+ +
+ +

Contents

+ + + +

Preliminary concepts

+ +

+A mutex is a type whose objects can be in either of two states, called +locked and unlocked, with the property that when a thread A has locked a +mutex m and a different thread B tries to lock m, +B is blocked until A unlocks m. Additionally, a mutex is said to +support recursive locking if a thread can succesfully invoke the locking +operation for a mutex already locked by this same thread; in this case, it is +required that the thread execute as many unlock operations as lock +operations it has performed for the mutex to become effectively unlocked. +A scoped lock is a +type associated to some mutex type whose objects do the locking/unlocking +of a mutex on construction/destruction time. +

+ +

+In the following table, Mutex is a mutex type, m +is an object of type Mutex, Lock is a scoped lock +associated to Mutex and lk is a value of +Lock. + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Mutex and Scoped Lock requirements.
expressionreturn typeassertion/note
pre/post-condition
Mutex m; Post: m is unlocked. +
(&m)->~Mutex();voidPre: m is unlocked.
Lock lk(m); Associates m to lk and locks m.
(&lk)->~Lock();voidUnlocks the mutex associated to lk.
+

+ +

+These concepts are very similar, but not entirely equivalent, to +the homonym ones described in the +Boost Thread +Library. +

+ +

Locking policies

+ +

+Locking policies describe a mutex type and an associated +scoped lock type. +flyweight uses a given locking +policy to synchronize the access to its internal +factory. +

+ +

+A type Locking is a locking policy if: +

    +
  • One of the following conditions is satisfied: +
      +
    1. is_locking<Locking>::type is + boost::mpl::true_,
    2. +
    3. Locking is of the form + locking<Locking'>.
    4. +
    +
  • +
  • The type Locking::mutex_type (or + Locking'::mutex_type if (b) applies) is a + model of Mutex + and supports recursive locking. +
  • +
  • The type Locking::lock_type (or + Locking'::lock_type if (b) applies) is a + Scoped Lock of + the mutex referred to above. +
  • +
+

+ +

Header +"boost/flyweight/locking_tag.hpp" synopsis

+ +
+namespace boost{
+
+namespace flyweights{
+
+struct locking_marker;
+
+template<typename T>
+struct is_locking
+
+template<typename T>
+struct locking;
+
+} // namespace boost::flyweights
+
+} // namespace boost
+
+ +

Class template is_locking

+ +

+Unless specialized by the user, is_locking<T>::type is +boost::mpl::true_ +if T is derived from locking_marker, and it is +boost::mpl::false_ +otherwise. +

+ +

Class template locking

+ +

+locking<T> is a syntactic construct meant to indicate +that T is a locking policy without resorting to the +mechanisms provided by the is_locking class template. +

+ +

Header +"boost/flyweight/simple_locking_fwd.hpp" synopsis

+ +
+namespace boost{
+
+namespace flyweights{
+
+struct simple_locking;
+
+} // namespace boost::flyweights
+
+} // namespace boost
+
+ +

+simple_locking_fwd.hpp forward declares the class +simple_locking. +

+ +

Header +"boost/flyweight/simple_locking.hpp" synopsis

+ +

Class simple_locking

+ +

+Locking Policy that specifies a basic +mutex type based on the simplest synchronization mechanisms provided by +the environment; When no threading capabilities are available, +simple_locking specifies a dummy type without actual +synchronization capabilities. +

+ +

Header +"boost/flyweight/no_locking_fwd.hpp" synopsis

+ +
+namespace boost{
+
+namespace flyweights{
+
+struct no_locking;
+
+} // namespace boost::flyweights
+
+} // namespace boost
+
+ +

+no_locking_fwd.hpp forward declares the class +no_locking. +

+ +

Header +"boost/flyweight/no_locking.hpp" synopsis

+ +

Class no_locking

+ +

+Null Locking Policy: it specifies a dummy +type that satisfies the formal requirements for the +Mutex concept but does not perform +thread blocking. no_locking should only be used in single-threaded +environments. +

+ +
+ + + +
+ +
+ +

Revised August 13th 2008

+ +

© Copyright 2006-2008 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) +

+ + + diff --git a/doc/reference/tags.html b/doc/reference/tags.html new file mode 100644 index 0000000..c58ab86 --- /dev/null +++ b/doc/reference/tags.html @@ -0,0 +1,107 @@ + + + + + +Boost.Flyweight Documentation - Tags reference + + + + + + + + +

Boost logoBoost.Flyweight +Tags reference

+ + + +
+ +
+ +

Contents

+ + + +

Tags

+ +

+A tag is a type of the form +tag<T> for some arbitrary +T. +In the context of Boost.Flyweight, tags are syntactic artifacts used +to differentiate instantiations of the class template +flyweight which would +otherwise be identical. Tagging a flyweight instantiation with +a tag type local to a given context ensures that the global resources +of that instantiation (for instance, the associated +factory class) will not be unintentionally +shared by other areas of the program. +

+ +

Header +"boost/flyweight/tag.hpp" synopsis

+ +
+namespace boost{
+
+namespace flyweights{
+
+template<typename T>
+struct tag;
+
+} // namespace boost::flyweights
+
+} // namespace boost
+
+ +

Class template tag

+ +

+For any type T, tag<T> is a suitable +tag for use in instantiations of +flyweight. +

+ +
+ + + +
+ +
+ +

Revised August 11th 2008

+ +

© Copyright 2006-2008 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) +

+ + + diff --git a/doc/reference/tracking.html b/doc/reference/tracking.html new file mode 100644 index 0000000..b310bfc --- /dev/null +++ b/doc/reference/tracking.html @@ -0,0 +1,291 @@ + + + + + +Boost.Flyweight Documentation - Tracking policies reference + + + + + + + + +

Boost logoBoost.Flyweight +Tracking policies reference

+ + + +
+ +
+ +

Contents

+ + + +

Preliminary concepts

+ +

+A tracking policy helper provides access to some of the functionality +of a factory so as to be used +in the implementation of an associated Tracking Policy. +In the following table, TrackingHelper is a tracking policy +helper associated to a factory type +Factory of elements of type Entry, h +is a value of +Factory::handle_type associated to a Factory f +and check is a value of +a Predicate +type Checker with argument of type Factory::handle_type. +

+ +

+ + + + + + + + + + + + + + + + + +
Tracking Policy Helper requirements.
expressionreturn typeassertion/note
pre/post-condition
TrackingHelper::entry(h);const Entry&Returns f.entry(h).
TrackingHelper::erase(h,check);voidIf check(h), invokes f.erase(h).
+

+ +

+The execution of TrackingHelper::erase (including the +invocation of check(h)) is done in a +synchronized manner so as to prevent any other thread of execution from +simultaneously accessing the factory's insertion or deletion facilities. +

+ +

Tracking policies

+ +

+A tracking policy defines the strategy to be followed by a +flyweight instantiation when +all the flyweight objects associated to a given value are destroyed. +The tracking policy contributes some type information necessary for the +definition of the flyweight internal +factory. +

+ +

+A type Tracking is a tracking policy if: +

    +
  • One of the following conditions is satisfied: +
      +
    1. is_tracking<Tracking>::type is + boost::mpl::true_,
    2. +
    3. Tracking is of the form + tracking<Tracking'>.
    4. +
    +
  • +
  • The expression Tracking::entry_type (or + Tracking'::entry_type if (b) applies) is an + MPL Lambda + Expression that resolves, when invoked with different types + (Value,Key) such that Value is + Assignable + and implicitly convertible to const Key&, to an + Assignable + type Entry implicitly convertible to both const Value& + and const Key&. +
  • +
  • The expression Tracking::handle_type (or + Tracking'::handle_type if (b) applies) is an + MPL Lambda + Expression; this expression, when invoked with types + (InternalHandle,TrackingHelper), + with InternalHandle being + Assignable + and providing the nothrow guarantee for copy and assignment, + resolves to an + Assignable + type Handle which also provides the nothrow guarantee for + copy and assignment and is constructible from and implicitly + convertible to InternalHandle. + TrackingHelper is an incomplete type at the time of + invocation of Tracking::handle_type. +
  • +
+Tracking::handle_type is parameterized by a helper that provides +access to some of the functionality of the factory associated to the +tracking policy. This factory's associated entry and handle types are the types +Entry and Handle defined above, respectively. +

+ +

Header +"boost/flyweight/tracking_tag.hpp" synopsis

+ +
+namespace boost{
+
+namespace flyweights{
+
+struct tracking_marker;
+
+template<typename T>
+struct is_tracking
+
+template<typename T>
+struct tracking;
+
+} // namespace boost::flyweights
+
+} // namespace boost
+
+ +

Class template is_tracking

+ +

+Unless specialized by the user, is_tracking<T>::type is +boost::mpl::true_ +if T is derived from tracking_marker, and it is +boost::mpl::false_ +otherwise. +

+ +

Class template tracking

+ +

+tracking<T> is a syntactic construct meant to indicate +that T is a tracking policy without resorting to the +mechanisms provided by the is_tracking class template. +

+ +

Header +"boost/flyweight/refcounted_fwd.hpp" synopsis

+ +
+namespace boost{
+
+namespace flyweights{
+
+struct refcounted;
+
+} // namespace boost::flyweights
+
+} // namespace boost
+
+ +

+refcounted_fwd.hpp forward declares the class +refcounted. +

+ +

Header +"boost/flyweight/refcounted.hpp" synopsis

+ +

Class refcounted

+ +

+Tracking Policy providing +flyweight +instantiations with reference counting semantics: when all the flyweight objects +associated to a given value are destroyed, the corresponding entry is +erased from flyweight's internal +factory. +

+ +

Header +"boost/flyweight/no_tracking_fwd.hpp" synopsis

+ +
+namespace boost{
+
+namespace flyweights{
+
+struct no_tracking;
+
+} // namespace boost::flyweights
+
+} // namespace boost
+
+ +

+no_tracking_fwd.hpp forward declares the class +no_tracking. +

+ +

Header +"boost/flyweight/no_tracking.hpp" synopsis

+ +

Class no_tracking

+ +

+Null Tracking Policy: elements inserted +into flyweight's internal factory +are not erased until program termination. +

+ +
+ + + +
+ +
+ +

Revised August 18th 2008

+ +

© Copyright 2006-2008 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) +

+ + + diff --git a/doc/release_notes.html b/doc/release_notes.html new file mode 100644 index 0000000..54a5868 --- /dev/null +++ b/doc/release_notes.html @@ -0,0 +1,70 @@ + + + + + +Boost.Flyweight Documentation - Release notes + + + + + + + + +

Boost logoBoost.Flyweight Release notes

+ + + +
+
+ +
+ +

Contents

+ + + +

Boost 1.38 release

+ +

+

    +
  • Initial release of Boost.Flyweight.
  • +
+

+ +
+ + + +
+
+ +
+ +

Revised August 27th 2008

+ +

© Copyright 2006-2008 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) +

+ + + diff --git a/doc/style.css b/doc/style.css new file mode 100644 index 0000000..99e7da3 --- /dev/null +++ b/doc/style.css @@ -0,0 +1,54 @@ +/* Copyright 2003-2004 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) + */ + +pre{ + BORDER-RIGHT: gray 1pt solid; + PADDING-RIGHT: 2pt; + BORDER-TOP: gray 1pt solid; + DISPLAY: block; + PADDING-LEFT: 2pt; + PADDING-BOTTOM: 2pt; + BORDER-LEFT: gray 1pt solid; + MARGIN-RIGHT: 32pt; + PADDING-TOP: 2pt; + BORDER-BOTTOM: gray 1pt solid; + FONT-FAMILY: "Courier New", Courier, mono; + background-color: #EEEEEE; +} + +table{ + PADDING-RIGHT: 2pt; + BORDER-TOP: gray 1pt solid; + DISPLAY: block; + PADDING-LEFT: 2pt; + PADDING-BOTTOM: 2pt; + BORDER-LEFT: gray 1pt solid; + MARGIN-RIGHT: 32pt; + PADDING-TOP: 2pt; + background-color: #EEEEEE; +} +td{ + BORDER-STYLE: solid; + BORDER-WIDTH: 1pt; + BORDER-LEFT: ; + BORDER-RIGHT: gray 1pt solid; + BORDER-TOP: ; + BORDER-BOTTOM: gray 1pt solid; +} +th{color: #ffffff; background-color: #000000;} +.odd_tr{background-color: #ffffff;} + +.keyword{color: #0000FF;} +.identifier{} +.comment{font-style: italic; color: #008000;} +.special{color: #800040;} +.preprocessor{color: #3F007F;} +.string{font-style: italic; color: #666666;} +.literal{font-style: italic; color: #666666;} + +.prev_link{width: 30%; float: left; text-align: left;} +.up_link{width: 39.9%; float: left; text-align: center;} +.next_link{width: 30%; float: left; text-align: right;} diff --git a/doc/tests.html b/doc/tests.html new file mode 100644 index 0000000..3da7f22 --- /dev/null +++ b/doc/tests.html @@ -0,0 +1,114 @@ + + + + + +Boost.Flyweight Documentation - Tests + + + + + + + + +

Boost logoBoost.Flyweight Tests

+ + + +
+ +
+ +

+The Boost.Flyweight test suite exercises the whole spectrum of +functionalities provided by the library. Although the tests are not meant +to serve as a learning guide, the interested reader may find it +useful to inspect the source code to gain familiarity with the usage +of Boost.Flyweight. +

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Boost.Flyweight test suite.
ProgramDescription
test_assoc_cont_factory.cppassoc_container_factory + factory specifier.
test_basic.cppExercises the default components of flyweight.
test_custom_factory.cppCreates a user-defined factory class and specifier.
test_init.cppBoost.Flyweight static + data initialization facilities.
test_intermod_holder.cpp
+ intermod_holder_dll.cpp
Exercises intermodule_holder.
test_multictor.cppTests flyweight multiple + argument constructors.
test_no_locking.cppno_locking policy.
test_no_tracking.cppno_tracking policy.
test_set_factory.cppset_factory + factory specifier.
+

+ +
+ + + +
+ +
+ + +

Revised December 2nd 2008

+ +

© Copyright 2006-2008 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) +

+ + + diff --git a/doc/time_gcc_344.png b/doc/time_gcc_344.png new file mode 100644 index 0000000000000000000000000000000000000000..86f878aec542f8b29f40c6d711c88887b98f250d GIT binary patch literal 12600 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 + + + + +Boost.Flyweight Documentation - Tutorial - Basics + + + + + + + + +

Boost logoBoost.Flyweight Tutorial: Basics

+ + + +
+ +
+ +

Contents

+ + + +

Introduction

+ +

+Suppose we are writing a massive multiplayer online game +which has to maintain hundreds of thousands or millions of instances +of the following class in memory: +

+ +
+struct user_entry
+{
+  std::string first_name;
+  std::string last_name;
+  int         age;
+  ...
+};
+
+ +

+In this kind of environments memory resources are precious, so we are seeking +ways to make user_entry as compact as possible. Typically, there +exists a very high level of repetition of first and last names among +the community users, so an obvious optimization consists in moving +user_entry::first_name and user_entry::last_name +objects to a common repository where duplicates are avoided, and leaving +references to these inside user_entry. This is precisely what +Boost.Flyweight does in the simplest possible way for the programmer: +

+ +
+#include <boost/flyweight.hpp>
+
+struct user_entry
+{
+  flyweight<std::string> first_name;
+  flyweight<std::string> last_name;
+  int                    age;
+  ...
+};
+
+ +

+Boost.Flyweight automatically performs the optimization just described behind +the scenes, so that the net effect of this change is that the memory +usage of the program decreases by a factor proportional to the level of +redundancy among user names. +

+ +

+flyweight<std::string> behaves in many ways like +std::string; for instance, the following code works +unchanged after the redefinition of user_entry: +

+ +
+// flyweight<T> can be constructed in the same way as T objects can,
+// even with multiple argument constructors
+
+user_entry::user_entry(const char* f,const char* l,int a,...):
+  first_name(f),
+  last_name(l),
+  age(a),
+  ...
+{}
+
+// flyweight classes have relational operators replicating the
+// semantics of the underyling type
+
+bool same_name(const user_entry& user1,const user_entry& user2)
+{
+  return user1.first_name==user2.first_name &&
+         user1.last_name==user2.last_name;
+}
+
+// flyweight<T> provides operator<< and operator>> internally
+// forwarding to T::operator<< and T::operator>>
+
+std::ostream& operator<<(std::ostream& os,const user_entry& user)
+{
+  return os<<user.first_name<<" "<<user.last_name<<" "<<user.age;
+}
+
+std::istream& operator>>(std::istream& is,user_entry& user)
+{
+  return is>>user.first_name>>user.last_name>>user.age;
+}
+
+ +

+Besides, flyweight<T> is convertible to +const T&, either implicitly or through the get +member function: +

+ +
+std::string full_name(const user_entry& user)
+{
+  std::string full;
+
+  full.reserve(
+    user.first_name.get().size()+   // get() returns the underlying
+    user.last_name.get().size()+1); // const std::string&
+
+  full+=user.first_name;            // implicit conversion is used here
+  full+=" ";
+  full+=user.last_name;
+
+  return full;
+}
+
+ +

+The most important restriction to take into account when replacing a class +with an equivalent flyweight is the fact that flyweights are not +mutable: since several flyweight objects can share the same representation +value, modifying this value is not admissible. On the other hand, flyweight +objects can be assigned new values: +

+ +
+void change_name(
+  user_entry& user,
+  const std::string& f,const std::string& l)
+{
+  user.first_name=f;
+  user.last_name=l;
+}
+
+ +

+In general, flyweight<T> interface is designed to make +the transition from plain T as straightforward as possible. +Check the reference for +further details on the interface of the class template flyweight. +The examples section explores +some common usage scenarios of Boost.Flyweight. +

+ +

Flyweight requirements

+ +

+For flyweight<T> to be instantiable, T must +be Assignable, +Equality +Comparable and must interoperate with +Boost.Hash. +The first requirement is probably met without any extra effort by the user, +not so the other two, except for the most common basic types of C++ +and the standard library. Equality and hashing of T are used +internally by flyweight<T> internal factory to maintain the +common repository of unique T values referred to by the flyweight +objects. Consult the Boost.Hash documentation +section on extending +that library for custom data types. +

+ +

+As we have seen, equality and hash requirements on T are +imposed by the particular type of flyweight factory internally used by +flyweight<T>. We will see later how the user can customize +this factory to use equality and hash predicates other than the default, +or even switch to an entirely different kind of factory which may impose +another requirements on T, as described in the section on +configuring Boost.Flyweight. +

+ +
+ + + +
+ +
+ +

Revised December 2nd 2008

+ +

© Copyright 2006-2008 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) +

+ + + diff --git a/doc/tutorial/configuration.html b/doc/tutorial/configuration.html new file mode 100644 index 0000000..f8a53a3 --- /dev/null +++ b/doc/tutorial/configuration.html @@ -0,0 +1,647 @@ + + + + + +Boost.Flyweight Documentation - Tutorial - Configuring Boost.Flyweight + + + + + + + + +

Boost logoBoost.Flyweight Tutorial: Configuring Boost.Flyweight

+ + + +
+ +
+ +

Contents

+ + + +

Configurable aspects of Boost.Flyweight

+ +

+Most of the time, flyweight default configuration is just good +enough and the user need not care about further tuning of her flyweight +instantiations; however, when the necessity for more control over Boost.Flyweight +behavior arises, comprehensive mechanisms are provided to select, configure and +even extend the following implementation aspects: +

+

+ +

Free-order template parameter interface

+ +

+The flyweight class template features a "smart" specification +interface by which the configuration aspects can be provided as optional template arguments +in whatever order the user pleases. For instance, a tagged flyweight +of std::strings with a set-based factory and +no tracking can be specified like this: +

+ +
+flyweight<std::string, tag<label_t>,  set_factory<>, no_tracking   >
+
+ +

+or like this: +

+ +
+flyweight<std::string, no_tracking,   tag<label_t>,  set_factory<> >
+
+ +

+or in any other order; only std::string is required to occupy +the first place in the specification. +

+ +

Header inclusion

+ +

+The example code shown at the introductory section +uses the +"boost/flyweight.hpp" +convenience header, which simply includes the headers for the class template +flyweight and its default configuration components: +

+ +
+#include <boost/flyweight/flyweight.hpp>      // class template flyweight
+#include <boost/flyweight/hashed_factory.hpp> // hashed flyweight factory
+#include <boost/flyweight/static_holder.hpp>  // regular factory instantiation
+#include <boost/flyweight/simple_locking.hpp> // simple locking policy
+#include <boost/flyweight/refcounted.hpp>     // refcounting tracking policy
+
+ +

+When using components other than these, their specific headers must be +explicitly included. +

+ +

Tagging

+ +

+Consider the following two types: +

+ +
+typedef flyweight<std::string> name_t;
+typedef flyweight<std::string> ip_address_t;
+
+ +

+Although technically both types are identical, this is so by virtue of +coincidence, as there is no sensible relation between names and IP addresses. +Internally, the fact that name_t and ip_address_t +are the same flyweight type causes values of both classes to be stored together +in the same flyweight factory, although their respective ranges +are not expected to overlap. Tagging can be used to turn these +into really different types: +

+ +
+struct name_tag{};
+typedef flyweight<std::string,tag<name_tag> > name_t;
+
+struct ip_address_tag{};
+typedef flyweight<std::string,tag<ip_address_tag> > ip_address_t;
+
+ +

+Now, name_t and ip_address_t are different +flyweight classes having separate factories each. Tags are a purely syntactic +device: any type can be used for tagging inside the tag +construct, though good style recommends using tag classes with +descriptive names which are local to the context where the flyweight type +is being defined. +

+ +

Factory specification

+ +

+flyweight uses a type of internal component called +factory whose purpose is to store and retrieve the different values +flyweight objects refer to at a given time. By default, a factory based on +a hashed container is used, so that flyweight<T> is +actually equivalent to +

+ +
+flyweight<T,hashed_factory<> >
+
+ +

+where hashed_factory is a so-called factory specifier. +Boost.Flyweight provides several predefined factory specifiers, which not +only let the user select the specific type of factory used, but also +accept their own template arguments to customize each factory. +

+ +

Types involved in the configuration of factories

+ +

+A given flyweight instantiation has associated +flyweight::key_type +and flyweight::value_type types (which are equal in the case +of regular flyweights or different if key-value +flyweights +are used). Also, there is an internal Entry type which +corresponds to the type of the objects actually stored in the factory: +Entry contains the shared value_type objects +of flyweight as well a some internal bookkeeping information; +also, Entry is implicitly convertible to +const key_type&, so that factories can rely on +key_type to look up Entries. Since +Entry is internal to the implementation of flyweight, +it cannot be directly referred to by the user in the configuration of +factories. Instead, the proxy +placeholder +type boost::mpl::_1 can be used. +

+ +

hashed_factory

+ +
+Header: "boost/flyweight/hashed_factory.hpp"
+Syntax: hashed_factory<[Hash[,Pred[,Allocator]]]> +
+ +

+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 +equivalent by means of the +Binary +Predicate Pred, and indexed into the factory container +using Hash, which is assumed to be a hash function, +i.e. a +Unary +Function assigning to each value a hash identifier of +type std::size_t. The Allocator parameter is +used by the factory container for its memory allocation needs. The default +types for these parameters are such that the expression +

+ +
+flyweight<T,hashed_factory<> >
+
+ +

+is equivalent to +

+ +
+flyweight<
+  T,
+  hashed_factory<
+    boost::hash<key_value>,
+    std::equal_to<key_value>,
+    std::allocator<boost::mpl::_1>
+  >
+>
+
+ +

+where key_type is the key type of the flyweight and +boost::mpl::_1, as explained above, stands for the +internal Entry type of the elements stored in the factory. +Suppose we would like to configure hashed_factory for +a std::string flyweight with +a special hash predicate special_hash and a custom allocator +custom_allocator; this would be specified as follows: +

+ +
+flyweight<
+  std::string,
+  hashed_factory<
+    special_hash<std::string>,
+    std::equal_to<key_value>,
+    custom_allocator<boost::mpl::_1>
+  >
+>
+
+ +

set_factory

+ +
+Header: "boost/flyweight/set_factory.hpp"
+Syntax: set_factory<[Compare[,Allocator]]> +
+ +

+set_factory resorts to an std::set-like ordered +container for the implementation of the flyweight factory. +Compare must be a +Strict +Weak Ordering on the value type flyweight is +acting upon; as is customary with STL ordered containers, two values +are considered equivalent if none is less than the other according to Pred. +Allocator is an allocator type passed along to the factory +internal container for its memory-related tasks. When default parameters are +used, the expression +

+ +
+flyweight<T,set_factory<> >
+
+ +

+is equivalent to +

+ +
+flyweight<
+  T,
+  set_factory<std::less<key_type>,std::allocator<boost::mpl::_1> >
+>
+
+ +

+Usual tradeoffs arising in the comparison of ordered and hashed containers +also apply when choosing between set_factory and +hashed_factory: +so, set-based lookup and insertion of values are generally slower than those based on hashing, +but the latter can be affected by pathological worst-case scenarios with very +poor performance. +

+ +

assoc_container_factory

+ +
+Header: "boost/flyweight/assoc_container_factory.hpp"
+Syntax: assoc_container_factory<ContainerSpecifier> +
+ +

+This specifier can be seen as a generalization of +hashed_factory and set_factory where the user +supplies the exact type of container on which the factory is based. +The way in which the container is specified might seem at first a little +daunting to those unfamiliar with the +Boost MPL Library: +ContainerSpecifier must be an +MPL Lambda +Expression such that, when invoked with the +types Entry and key_type +explained above, it produces the type of +a container of Entry elements satisfying the following +requirements: +

    +
  1. The container type must be a model of + Unique + Associative Container where equivalence of Entrys + is determined by the key_type values the entries are convertible + to . +
  2. +
  3. The container must be stable, i.e. its iterators must remain valid + after insert and erase operations. Note that this condition is not met by + many existing implementations of hashed containers that invalidate iterators + upon a rehashing operation. +
  4. +
+

+ +

+Let us see what a container specifier looks like with an example. +Suppose we have our own ordered container like the following: +

+ +
+template<
+  typename Elem,
+  typename Compare=std::less<Elem>,
+  typename Allocator=std::allocator<Elem>
+>
+class ultrafast_set
+{
+  ...
+};
+
+ +

+Then ultrafast_set can be plugged into +assoc_container_factory like this: +

+ +
+typedef flyweight<
+  std::string,
+  assoc_container_factory<
+    // MPL lambda expression follows
+    ultrafast_set<mpl::_1,std::less<std::string> >
+  >
+> flyweight_string;
+
+ +

+As has been explained, mpl::_1 is a so-called MPL +placeholder standing as a "slot" to be replaced with +Entry by the internal machinery of Boost.Flyweight. +Note that we have not +relied on the default argument of ultrafast_set for +Compare and instead we have provided a fixed +instantiation for std::string: this is so because +requirements state that the type with which ContainerSpecifier +will be filled in internally is convertible to const key_type& +(here const std::string&), and it is based on +key_type that lookup and equivalence of entries +should be determined. On the other hand, +the default argument for the Allocator parameter works +just fine, as is more apparent if we write it down explicitly: +

+ +
+typedef flyweight<
+  std::string,
+  assoc_container_factory<
+    ultrafast_set<
+      mpl::_1,
+      std::less<std::string>,
+      std::allocator<mpl::_1>
+    >
+  >
+> flyweight_string;
+
+ +

Holder specification

+ +

+Each flyweight type, that is, each distinct instantiation of the class +template flyweight, is associated with exactly one factory +object. In most cases, how this factory object is created is of little +importance to the user of Boost.Flyweight, but there are special +circumstances where control of this aspect is necessary. An internal +component called holder is in charge of instantiating the +factory class and some other internal information; this component is +stipulated by means of a holder specifier, static_holder +being the default one. +

+ +

static_holder

+ +
+Header: "boost/flyweight/static_holder.hpp"
+Syntax: static_holder +
+ +

+This the default holder specifier of Boost.Flyweight, and produces +holders where the unique factory lives as a local static variable of the +program. +

+ +

intermodule_holder

+ +
+Header: "boost/flyweight/intermodule_holder.hpp"
+Syntax: intermodule_holder +
+ +

+In most C++ environments, static variables do not mix well with +dynamically loaded modules in the sense that instances of the same +static variable can be duplicated across different modules, even +though by definition the variable should be unique. In many +cases, this duplication goes unnoticed if the modules do not communicate +between each other using the affected types, but consider this +case where such communication does happen: +

+ +
+// module 1
+
+typedef flyweight<std::string> flyweight_string;
+
+// produce_string is exported so that it can be dynamically
+// linked
+
+flyweight_string produce_string()
+{
+  return flyweight_string("boost");
+}
+
+ +
+// main program
+
+typedef flyweight<std::string> flyweight_string;
+
+int main()
+{
+  ... // import module 1
+
+  flyweight_string str1=produce_string();
+  flyweight_string str2("boost");
+  assert(str1==str2);
+}
+
+ +

+In many environments, this program results in an assertion +failure because the flyweight factory object used +by flyweight_string as seen within module 1 is +not the same factory object as seen within the main program: hence +the value representations internally pointed to by str1 +and str2 will differ and will be mistakenly +considered as not equal. Many other problems might arise +due to factory duplication, including undefined behavior. +

+ +

+intermodule_holder specifies a factory holder which +is capable of avoiding the duplication problem and ensuring that +all modules of a program are using the same factory instance. +To fix the example above, it suffices to redefine +flyweight_string in both modules as: +

+ +
+typedef flyweight<std::string,intermodule_holder> flyweight_string;
+
+ +

+intermodule_holder is considerably more onerous than +static_holder in terms of compilation times and +introduces a non-negligible overhead at program start-up, so its use +should be reserved to the situations where it is really necessary. +

+ + +

Locking policies

+ +

+The internal factory associated to each flyweight +type is a shared resource and as such access to it must be properly +synchronized in multithreaded environments. A locking policy +specifies the synchronization mechanisms to be used for this purpose. +

+ +

simple_locking

+ +
+Header: "boost/flyweight/simple_locking.hpp"
+Syntax: simple_locking +
+ +

+This is the default locking policy. It specifies the simplest native +synchronization primitives provided by the operating system, whenever +available. +

+ +

no_locking

+ +
+Header: "boost/flyweight/no_locking.hpp"
+Syntax: no_locking +
+ +

+No synchronization is enforced so that irrestricted internal access +to the implementation shared resources is allowed. +Selecting no_locking results in somewhat faster execution than +the default simple_locking, but it renders the type +thread-unsafe, which can have catastrophic consequences. +This policy should not be used except in single-threaded environments or +when there is an absolute guarantee that the particular flyweight +type will not be used in a concurrent scenario. +

+ +

Tracking policies

+ +

+A tracking policy controls the lifetimes of the flyweight +objects and can act based on this information. For instance, a suitable +tracking mechanism can determine when a given value stored in the factory +can be safely erased because it is no longer referenced by any +flyweight; this is precisely what the default tracking policy, +refcounted, does. +

+ +

refcounted

+ +
+Header: "boost/flyweight/refcounted.hpp"
+Syntax: refcounted +
+ +

+This tracking policy determines that values stored in the factory be +equipped with reference counting mechanisms so that a factory entry is +erased when the last flyweight object associated to it +is destroyed. +

+ +

no_tracking

+ +
+Header: "boost/flyweight/no_tracking.hpp"
+Syntax: no_tracking +
+ +

+No flyweight tracking is done when this policy is selected, which implies +that the values stored in the factory remain in it until program termination. +As compared with refcounted, no_tracking presents +advantages and drawbacks. The benefits are: +

    +
  • Non-tracked flyweight objects are faster to pass around than refcounted ones.
  • +
  • There is some reduction in memory usage due to the + absence of reference counters.
  • +
+whereas potential drawbacks of using no_tracking include: +
    +
  • The number of unused entries stored in the factory can keep growing + during the program lifetime, which can become a problem for certain + patterns of flyweight creation where the set of active values "drifts" + over time.
  • +
  • There can be a potential delay during program termination, since + it is then when all the factory entries get destroyed at once.
  • +
+

+ +
+ + + +
+ +
+ +

Revised November 8th 2008

+ +

© Copyright 2006-2008 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) +

+ + + diff --git a/doc/tutorial/extension.html b/doc/tutorial/extension.html new file mode 100644 index 0000000..b829673 --- /dev/null +++ b/doc/tutorial/extension.html @@ -0,0 +1,562 @@ + + + + + +Boost.Flyweight Documentation - Tutorial - Extending Boost.Flyweight + + + + + + + + +

Boost logoBoost.Flyweight Tutorial: Extending Boost.Flyweight

+ + + +
+ +
+ +

Contents

+ + + +

Introduction

+ +

+Boost.Flyweight provides public interface specifications of +its configurable aspects so that the user +can extend the library by implementing her own components and providing them to +instantiations of the flyweight class template. +

+ +

+In most cases there are two types of entities involved in extending a given +aspect of Boost.Flyweight: +

    +
  • The component itself (for instance, a factory class template).
  • +
  • The associated component specifier, which is the type + provided as a template argument of a flyweight + instantiation. +
  • +
+For example, the type +static_holder +is a holder specifier which is used by flyweight to generate +actual holder classes, in this case instantiations of the class +template +static_holder_class. +Note that static_holder is a concrete type while +static_holder_class is a class template, so a specifier can be +seen as a convenient way to provide access to a family of related concrete +components (the different possible instantiations of the class template): +flyweight internally selects the particular component +appropriate for its internal needs. +

+ +

Custom factories

+ +

+In a way, factories resemble unique associative containers like std::set, +though their expected interface is much more concise: +

+ +
+// example of a possible factory class template
+
+template<typename Entry,typename Key>
+class custom_factory_class
+{
+public:
+  typedef ... handle_type;
+  
+  handle_type  insert(const Entry& x);
+  void         erase(handle_type h);
+  const Entry& entry(handle_type h);
+};
+
+ +

+Factories are parameterized by Entry and Key: +the first is the type of the objects stored, while the second is the public +key type on which flyweight operates (e.g. the std::string +in flyweight<std::string> or +flyweight<key_value<std::string,texture> >). An entry holds a +shared value to which flyweight objects are associated as well as internal bookkeeping information, but from the +point of view of the factory, though, the only fact known about Entry +is that it is implicitly convertible to const Key&, and it is +based on their associated Key that entries are to be considered +equivalent or not. The factory insert() +member function locates a previously stored entry whose +associated Key is equivalent to that of the Entry +object being passed (for some equivalence relation on Key germane to +the factory), or stores the new entry if no equivalent one is found. A +handle_type to the equivalent or newly inserted entry is returned; +this handle_type is a token for further access to an entry via +erase() and entry(). Consult the +reference for the formal +definition of the Factory concept. +

+ +

+Let us see an actual example of realization of a custom factory class. Suppose +we want to trace the different invocations by Boost.Flyweight of the +insert() and erase() member functions: this can be +done by using a custom factory whose member methods emit trace messages +to the program console. We base the implementation of the repository +functionality on a regular std::set: + +

+template<typename Entry,typename Key>
+class verbose_factory_class
+{ 
+  typedef std::set<Entry,std::less<Key> > store_type;
+
+  store_type store;
+
+public:
+  typedef typename store_type::iterator handle_type;
+
+  handle_type insert(const Entry& x)
+  {
+    std::pair<handle_type, bool> p=store.insert(x);
+    if(p.second){ /* new entry */
+      std::cout<<"new: "<<(const Key&)x<<std::endl;
+    }
+    else{         /* existing entry */
+      std::cout<<"hit: "<<(const Key&)x<<std::endl;
+    }
+    return p.first;
+  }
+
+  void erase(handle_type h)
+  {
+    std::cout<<"del: "<<(const Key&)*h<<std::endl;
+    store.erase(h);
+  }
+
+  const Entry& entry(handle_type h)
+  {
+    return *h;
+  }
+};
+
+ +

+The code deserves some commentaries: +

    +
  • + Note that the factory is parameterized by Entry + and Key, as these types are provided internally by Boost.Flyweight + when the factory is instantiated as part of the machinery of flyeight; + but there is nothing to prevent us from having more template parameters for + finer configuration of the factory type: for instance, we could extend + verbose_factory_class to accept some comparison predicate rather than + the default std::less<Key>, or to specify the allocator + used by the internal std::set. +
  • +
  • + The fact that Entry is convertible to const Key& + (which is about the only property known about Entry) is + exploited in the specification of std::less<Key> as + the comparison predicate for the std::set of Entrys + used as the internal repository. +
  • +
  • + As our public handle_type we are simply using an iterator to the + internal std::set. +
  • +
+

+ +

+In order to plug a custom factory into the specification of a flyweight +type, we need an associated construct called the factory specifier. +A factory specifier is a +Lambda +Expression accepting the two argument types Entry +and Key and returning the corresponding factory class: +

+ +
+// Factory specifier (metafunction class version)
+
+struct custom_factory_specifier
+{
+  template<typename Entry,Key>
+  struct apply
+  {
+    typedef custom_factory_class<Entry,Key> type;
+  } 
+};
+
+// Factory specifier (placeholder version)
+
+typedef custom_factory_class<
+  boost::mpl::_1,
+  boost::mpl::_2
+> custom_factory_specifier;
+
+ +

+There is one last detail: in order to implement flyweight +free-order template +parameter interface, it is necessary to explicitly tag a +factory specifier as such, so that it can be distinguised from other +types of specifiers. Boost.Flyweight provides three different mechanisms +to do this tagging: +

    +
  1. Have the specifier derive from the dummy type factory_marker. + Note that this mechanism cannot be used with placeholder expressions. +
    +#include <boost/flyweight/factory_tag.hpp>
    +
    +struct custom_factory_specifier: factory_marker
    +{
    +  template<typename Entry,Key>
    +  struct apply
    +  {
    +    typedef custom_factory_class<Entry,Key> type;
    +  } 
    +};
    +
    +
  2. +
  3. Specialize a special class template called + is_factory: +
    +#include <boost/flyweight/factory_tag.hpp>
    +
    +struct custom_factory_specifier{};
    +
    +namespace boost{
    +namespace flyweights{
    +
    +template<> struct is_factory<custom_factory_specifier>: boost::mpl::true_{};
    +
    +}
    +}
    +
    +
  4. +
  5. The third mechanism, which is the least intrusive, consists in + wrapping the specifier inside the + factory + construct: +
    +#include <boost/flyweight/factory_tag.hpp>
    +
    +typedef flyweight<
    +  std::string,
    +  factory<custom_factory_specifier>
    +> flyweight_string;
    +
    +
  6. +
+

+ +

+Example 7 in the examples section develops +in full the verbose_factory_class case sketched above. +

+ +

Custom holders

+ +

+A holder is a class with a static member function get() giving +access to a unique instance of a given type C: +

+ +
+// example of a possible holder class template
+
+template<typename C>
+class custom_holder_class
+{
+public:
+  static C& get();
+};
+
+ +

+flyweight internally uses a holder to create its associated +factory as well as some other global data. A holder specifier is a +Lambda +Expression accepting the type C upon which +the associated holder class operates: +

+ +
+// Holder specifier (metafunction class version)
+
+struct custom_holder_specifier
+{
+  template<typename C>
+  struct apply
+  {
+    typedef custom_holder_class<C> type;
+  } 
+};
+
+// Holder specifier (placeholder version)
+
+typedef custom_holder_class<boost::mpl::_1> custom_factory_specifier;
+
+ +

+As is the case with factory specifiers, holder +specifiers must be tagged in order to be properly recognized when +provided to flyweight, and there are three available mechanisms +to do so: +

+ +
+// Alternatives for tagging a holder specifier
+
+#include <boost/flyweight/holder_tag.hpp>
+
+// 1: Have the specifier derive from holder_marker
+
+struct custom_holder_specifier: holder_marker
+{
+  ...
+};
+
+// 2: Specialize the is_holder class template
+
+namespace boost{
+namespace flyweights{
+
+template<> struct is_holder<custom_holder_specifier>: boost::mpl::true_{};
+
+}}
+
+// 3: use the holder<> wrapper when passing the specifier
+// to flyweight
+
+typedef flyweight<
+  std::string,
+  holder<custom_holder_specifier>
+> flyweight_string;
+
+ +

Custom locking policies

+ +

+A custom locking policy presents the following simple interface: +

+ +
+// example of a custom policy
+
+class custom_locking
+{
+  typedef ... mutex_type;
+  typedef ... lock_type;
+};
+
+ +

+where lock_type is used to acquire/release mutexes according to +the scoped lock idiom: +

+ +
+mutex_type m;
+...
+{
+  lock_type lk(m); // acquire the mutex
+  // zone of mutual exclusion, no other thread can acquire the mutex
+  ...
+} // m released at lk destruction
+
+ +

+Formal definitions for the concepts +Mutex and +Scoped Lock +are given at the reference. To pass a locking policy as a template argument of +flyweight, the class must be appropriately tagged: +

+ +
+// Alternatives for tagging a locking policy
+
+#include <boost/flyweight/locking_tag.hpp>
+
+// 1: Have the policy derive from locking_marker
+
+struct custom_locking: locking_marker
+{
+  ...
+};
+
+// 2: Specialize the is_locking class template
+
+namespace boost{
+namespace flyweights{
+
+template<> struct is_locking<custom_locking>: boost::mpl::true_{};
+
+}}
+
+// 3: use the locking<> wrapper when passing the policy
+// to flyweight
+
+typedef flyweight<
+  std::string,
+  locking<custom_locking>
+> flyweight_string;
+
+ +

+Note that a locking policy is its own specifier, i.e. there is no +additional class to be passed as a proxy for the real component as is +the case with factories and holders. +

+ +

Custom tracking policies

+ +

+Tracking policies contribute some type information to the process of +definition of the internal flyweight factory, and are given access +to that factory to allow for the implementation of the tracking +code. A tracking policy Tracking is defined as a class with +the following nested elements: +

    +
  • A type Tracking::entry_type.
  • +
  • A type Tracking::handle_type.
  • +
+Each of these elements build on the preceding one, in the sense that +Boost.Flyweight internal machinery funnels the results produced by an +element into the following: +
    +
  • Tracking::entry_type is a + Lambda + Expression accepting two different types named + Value and Key such that + Value is implicitly convertible to + const Key&. The expression is expected + to return + a type implicitly convertible to both const Value& + and const Key&. + Tracking::entry_type corresponds to the actual + type of the entries stored into the + flyweight factory: + by allowing the tracking policy to take part on the definition + of this type it is possible for the policy to add internal + tracking information to the entry data in case this is needed. + If no additional information is required, + the tracking policy can simply return Value as its + Tracking::entry_type type. +
  • +
  • + The binary Lambda + Expression Tracking::handle_type is invoked + with types InternalHandle and TrackingHandler + to produce a type Handle, which will be used as the handle + type of the flyweight factory. + TrackingHandler + is passed as a template argument to Tracking::handle_type + to offer functionality supporting the implementation of the tracking + code. +
  • +
+So, in order to define the factory of some instantiation +fw_t of flyweight, Tracking::entry_type +is invoked with an internal type Value implicitly convertible +to const fw_t::key_type& to obtain the entry type for the factory, +which must be convertible to both const Value& and +const fw_t::key_type&. +Then, Tracking::handle_type is fed an internal handle +type and a tracking policy helper to produce the factory handle type. +The observant reader might have detected an apparent circularity: +Tracking::handle_type produces the handle type of +the flyweight factory, and at the same time is passed a tracking helper +that grants access to the factory being defined! +The solution to this riddle comes from the realization of the fact that +TrackingHandler is an incomplete +type by the time it is passed to Tracking::handle_type: +only when Handle is instantiated at a later stage will this +type be complete. +

+ +

+In order for a tracking policy to be passed to flyweight, +it must be tagged much in the same way as the rest of specifiers. +

+ +
+// Alternatives for tagging a tracking policy
+
+#include <boost/flyweight/tracking_tag.hpp>
+
+// 1: Have the policy derive from tracking_marker
+
+struct custom_tracking: tracking_marker
+{
+  ...
+};
+
+// 2: Specialize the is_tracking class template
+
+namespace boost{
+namespace flyweights{
+
+template<> struct is_tracking<custom_tracking>: boost::mpl::true_{};
+
+}}
+
+// 3: use the tracking<> wrapper when passing the policy
+// to flyweight
+
+typedef flyweight<
+  std::string,
+  tracking<custom_tracking>
+> flyweight_string;
+
+ +

+Tracking policies are their own specifiers, that is, they are provided directly +as template arguments to the flyweight class template. +

+ +
+ + + +
+ +
+ +

Revised December 2nd 2008

+ +

© Copyright 2006-2008 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) +

+ + + diff --git a/doc/tutorial/flyweight_rep.png b/doc/tutorial/flyweight_rep.png new file mode 100644 index 0000000000000000000000000000000000000000..860728a09f016c5f71bfbcc99696adcc477555ef GIT binary patch literal 53631 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 literal 0 HcmV?d00001 diff --git a/doc/tutorial/index.html b/doc/tutorial/index.html new file mode 100644 index 0000000..28b4680 --- /dev/null +++ b/doc/tutorial/index.html @@ -0,0 +1,170 @@ + + + + + +Boost.Flyweight Documentation - Tutorial + + + + + + + + +

Boost logoBoost.Flyweight Tutorial

+ + + +
+ +
+ +

Contents

+ + + +

Rationale

+ + +

+
+Fig. 1: Representation of a flyweight scenario. +

+
+ +

+Consider an application that has to manage large quantities of objects of +moderate size, potentially requiring more memory than reasonably available. +When these objects are immutable, i.e. they do not modify its internal +state except maybe for reattaching to a new set of state data, and some +additional conditions are met, a very convenient optimization technique known +as the flyweight pattern can be introduced. +

+ +

+Let us say there are N different objects living at a given time +inside the application, globally taking M different values. If N +is much greater than M, that is, there are many equivalent objects, +we can eliminate the implicit redundancy by replacing the original objects with +handle classes which refer to a common repository of shared value objects, +as depicted in the figure. The handle objects or flyweights, which act as +proxies for the actual values, typically occupy the size of a mere pointer. +The larger the value classes, and the greater the N/M ratio, +the more significant the memory savings achieved by this tecnhique. The +classical example of application of the flyweight idiom is that of a word +processor: each letter in the document carries a large wealth of +information, such as its Unicode identifier, font, size, typesetting effects, +etc., but given that the degree of letter repetition in a document is extremely +high, implementing those letters as flyweight classes allows us to easily +handle documents ranging in the hundreds of thousands of characters. +

+ +

+Most presentations of the design pattern found in the literature do make a +distinction between the flyweight intrinsic information (the constant +data factored out into the repository) and extrinsic, mutable +information, which is stored along with the flyweight objects or passed +externally. This separation analysis can have some merit from the point of +view of application design, but when it comes to implementation extrinsic +information has no impact on the overall flyweight scheme. So, +Boost.Flyweight assumes that the type onto which the library operates +entirely consists of intrinsic information: this allows for a particularly +appealing realization of the idiom in C++ in which +flyweight<T> is an opaque type convertible to +const T&. +

+ +

+The central repository of shared value objects is known as the flyweight +factory. This component is able to locate and return a reference to an +object with a given value, or insert the value if no copy was previously +stored. Boost.Flyweight controls the interaction of flyweights with +their factory transparently to the programmer, so that a casual user of the +library need not even be concerned about the presence of such factory. +Boost.Flyweight uses by default a factory based on a hashed container which +is expected to be suitable for most situations. When this is not the case, it +is possible to customize the factory or even replace it with another one of +a different type, either provided by Boost.Flyweight or defined by the user. +Other aspects of the implementation are also customizable and extendable. +

+ +

+Namespace +

+ +

+All the public types of Boost.Flyweight reside in namespace ::boost::flyweights. +Additionaly, the main class template flyweight is lifted to namespace +::boost by means of a using declaration. For brevity of +exposition, the fragments of code in the documentation are written as if the following +directives were in effect: +

+ +
+using namespace ::boost;
+using namespace ::boost::flyweights;
+
+ +

Guide to the reader

+ +

+Although Boost.Flyweight features an extensive customization +framework controlling many internal implementation aspects, the library is designed +in such a way that most users need not be concerned about or +even aware of the underlying complexity. Learning to use Boost.Flyweight +as an off-the-shelf component can be acomplished merely by reading +the basics section and skimming through the +part on key-value flyweights, the section on flyweight type +tagging and the discussion of some +technical issues. The +configuration section teaches how to fine tune the +different internal components of the library. Only very advanced usage +scenarios will require implementing user-provided pluggable components: +this is covered on the extension section. +

+ +
+ + + +
+ +
+ +

Revised August 13th 2008

+ +

© Copyright 2006-2008 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) +

+ + + diff --git a/doc/tutorial/key_value.html b/doc/tutorial/key_value.html new file mode 100644 index 0000000..11e6a4c --- /dev/null +++ b/doc/tutorial/key_value.html @@ -0,0 +1,231 @@ + + + + + +Boost.Flyweight Documentation - Tutorial - Key-value flyweights + + + + + + + + +

Boost logoBoost.Flyweight Tutorial: Key-value flyweights

+ + + +
+ +
+ +

Contents

+ + + +

Key-value flyweights

+ +

+Continuing with our online game example, suppose we have a huge class for +handling rendering textures: +

+ +
+class texture
+{
+public:
+  texture(const std::string& filename){/* loads texture file */}
+
+  const std::string& get_filename()const;
+
+  // rest of the interface
+};
+
+ +

+and we decide to use flyweight<texture> to ease the +manipulation of these objects. Now consider this seemingly innocent +expression: +

+ +
+flyweight<texture> fw("grass.texture");
+
+ +

+Note that in order to construct fw we are implicitly +constructing a full grass texture object. The expression is mostly +equivalent to +

+ +
+flyweight<texture> fw(texture("grass.texture"));
+
+ +

+This is unnaceptably costly: we are constructing a massive temporary +object just to throw it away in most cases, since Boost.Flyweight most +likely already has an internal equivalent object to which fw +will be bound --value sharing is the key feature behind the flyweight +pattern after all. In this particular example, texture filenames act +as a key to the actual texture objects: two texture objects +constructed from the same filename are equivalent. So, we would like +for filenames to be used for texture lookup and somehow be sure that +the costly texture construction is only performed when no equivalent +value has been found. +

+ +

+flyweight<T> makes this distinction between key and value +blurry because it uses T both as the key type and +its associated value type. When this is inefficient, as in our texture +example, we can explicity specify both types using the +key_value +construct: +

+ +
+#include <boost/flyweight.hpp>
+#include <boost/flyweight/key_value.hpp>
+...
+flyweight<key_value<std::string,texture> > fw("grass.texture");
+
+ +

+So called key-value flyweights have then the form +flyweight<key_value<K,T> >: the key type K is +used to do the internal lookup for the associated values of type T. Key-value +flyweights guarantee that T values are not constructed except when +no other equivalent value exists; such construction is done from the associated +K value. +

+ +

Key extractors

+ +

+Besides the key-based semantics on construction time, key-value flyweights +behave much the same as regular flyweights, although some differences persist. +Consider the following code, which poses no problems with regular +flyweights: +

+ +
+const texture& get_texture(const object&);
+...
+flyweight<key_value<std::string,texture> > fw;
+...
+fw=get_texture(obj);
+
+ +

+The assignment cannot possibly work, because a key of type std::string +is needed to do the internal lookup whereas we are passing a full texture object. +Indeed, the code produces the a compilation error similar to this: +

+ +
+error: 'boost::mpl::assertion_failed' : cannot convert parameter 1 from
+'boost::mpl::failed ************(__thiscall boost::flyweights::detail::
+regular_key_value<Key,Value>::rep_type::no_key_from_value_failure::
+NO_KEY_FROM_VALUE_CONVERSION_PROVIDED::* ***********)(std::string,texture)'
+to 'boost::mpl::assert<false>::type'...
+
+ +

+It turns out that we can make the assignment work if only we provide a means +to retrieve the key from the value. This is not always possible, but in +our particular example the texture class does store the filename used for +construction, as indicated by the texture::get_filename +member function. We take advantage of this by specifying a +suitable key +extractor as part of the flyweight type definition: +

+ +
+struct texture_filename_extractor
+{
+  const std::string& operator()(const texture& x)const
+  {
+    return x.get_filename();
+  }
+};
+
+flyweight<key_value<std::string,texture,texture_filename_extractor> > fw;
+...
+fw=get_texture(obj); // OK now
+
+ +

+The specification of a key extractor in the +definition of a key-value flyweight results in internal space optimizations, +as the keys need not be stored along the values but are retrieved from +them instead. So, it is always a good idea to provide a key extractor when +possible even if your program does not contain assignment statements like +the one above. +

+ +

+Examples 2 and +5 +of the examples section make use of key-value flyweights. +

+ +

Type requirements

+ +

+Many of the requirements imposed on T for +regular flyweights move to the key +type in the case of a key-value flyweight<key_value<K,T> >. +Now it is K that must be +Assignable, +Equality +Comparable and interoperate with +Boost.Hash, where equality and +hash compatibility are requirements imposed by the default internal factory of +Boost.Flyweight and can change if this factory is further configured or replaced +by the user. The only requisite retained on T is that it must be +constructible from K; only in the case that a flyweight is directly +assigned a T object is also T required to be +Assignable. +

+ +
+ + + +
+ +
+ +

Revised December 2nd 2008

+ +

© Copyright 2006-2008 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) +

+ + + diff --git a/doc/tutorial/lambda_expressions.html b/doc/tutorial/lambda_expressions.html new file mode 100644 index 0000000..c89b2ea --- /dev/null +++ b/doc/tutorial/lambda_expressions.html @@ -0,0 +1,181 @@ + + + + + +Boost.Flyweight Documentation - Tutorial - Annex - MPL lambda expressions + + + + + + + + +

Boost logoBoost.Flyweight Tutorial Annex: MPL lambda expressions

+ + + +
+ +
+ +

This short introduction to lambda expressions is meant for readers unfamiliar +with the Boost MPL Library who +want to rapidly acquire a working knowledge of the basic concepts for the purposes +of using them in Boost.Flyweight. Please refer to the Boost.MPL documentation +for further information beyond these introductory notes. +

+ +

+The specifiers defined by Boost.Flyweight rely heavily on the +Lambda +Expression concept defined by the +Boost MPL Library. A lambda +expression can be thought of as a compile-time "type function", an entity (a +concrete type, actually) that can be invoked with a list of types and returns +some associated type in its turn. Consider for instance an arbitrary class +template: +

+ +
+template<typename T,typename Q>
+class foo
+{
+  ...
+};
+
+ +

+and suppose we want to have a lambda expression that, when invoked +with some generic types Arg1 and Arg2, +returns foo<Arg1,Arg2>. Such a lambda expression +can be implemented in two ways +

    +
  1. As a + MPL + Metafunction Class, a type with a special nested class template + named apply: +
    +struct foo_specifier
    +{
    +  template<typename Arg1,typename Arg2>
    +  struct apply
    +  {
    +    // this is the "return type" of foo_specifier
    +    typedef foo<Arg1,Arg2> type;
    +  };
    +};
    +
    +
  2. +
  3. + As a + MPL + Placeholder Expression, a class template instantiated with one or + more placeholders: +
    +typedef foo<boost::mpl::_1,boost::mpl::_2> foo_specifier;
    +
    + Note that, in this case, foo_specifier is a concrete type, much + as int or std::set<std::string> are; yet, + MPL internal mechanisms are able to detect that this type has been gotten + from instantiating a class template with placeholders boost::mpl::_1 + and boost::mpl::_2 and take these placeholders as slots to + be substituted for actual types (the first and second type supplied, + respectively) when foo_specifier is + invoked. So, an instantiation of foo can be used + to refer back to the foo class template itself! The net + effect is the same as with metafunctions, but placeholder expressions spare + us the need to write boilerplate metafunction classes + --and the kind of metaprogramming magic they depend on has an undeniable + beauty to it. +
  4. +
+So far the examples shown just forward the arguments Arg1 and +Arg2 directly to a class template without further elaboration, +but there is nothing preventing us from doing some argument manipulation, +like, for instance, switching their places: +

+ +
+struct foo_specifier
+{
+  template<typename Arg1,typename Arg2>
+  struct apply{typedef foo<Arg2,Arg1> type;};
+};
+
+typedef foo<boost::mpl::_2,boost::mpl::_1> foo_specifier;
+
+ +

+passing placeholder subexpressions as arguments to the overall expression: +

+ +
+struct foo_specifier
+{
+  template<typename Arg1,typename Arg2>
+  struct apply{typedef foo<boost::shared_ptr<Arg1>,std::less<Arg2> > type;};
+};
+
+typedef foo<
+  boost::shared_ptr<boost::mpl::_1>,
+  std::less<boost::mpl::_2>
+> foo_specifier;
+
+ +

+or accepting less or more arguments than the class template itself +(the number of parameters of a lambda expression is called its arity): +

+ +
+struct foo_specifier
+{
+  template<typename Arg1>
+  struct apply{typedef foo<Arg1,std::less<Arg1> type;};
+};
+
+typedef foo<boost::mpl::_1,std::less<boost::mpl::_1> > foo_specifier;
+
+struct foo_specifier
+{
+  template<typename Arg1,typename Arg2,typename Arg3>
+  struct apply{typedef foo<Arg1,foo<Arg2,Arg3> > type;};
+};
+
+typedef foo<boost::mpl::_1,foo<boost::mpl::_2,boost::mpl::_3> > foo_specifier;
+
+ +
+ + + +
+ +
+ +

Revised August 13th 2008

+ +

© Copyright 2006-2008 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) +

+ + + diff --git a/doc/tutorial/technical.html b/doc/tutorial/technical.html new file mode 100644 index 0000000..14e67b0 --- /dev/null +++ b/doc/tutorial/technical.html @@ -0,0 +1,193 @@ + + + + + +Boost.Flyweight Documentation - Tutorial - Technical issues + + + + + + + + +

Boost logoBoost.Flyweight Tutorial: Technical issues

+ + + +
+ +
+ +

Contents

+ + + +

Static data initialization

+ +

+For any given T, the type flyweight<T> +maintains some class-wide or static data that needs to be properly +initialized before the class can be used. The internal machinery of +Boost.Flyweight guarantees that static data initialization +takes place automatically before the first use of the particular +flyweight<T> instantiation in the program, and in +any case always during the so-called dynamic initialization phase +of the program startup sequence. Although this is not strictly +required by the C++ standard, in current practice dynamic initialization +is completed before main() begins. +

+ +

+So, for all practical purposes, static data initialization is performed +before main() or before the first pre-main() +usage of the class, for instance if we declare a global +static flyweight<T> object. This covers the vast +majority of usage cases in a transparent manner, but there are +some scenarios where the automatic static data initialization +policy of Boost.Flyweight can fail: +

+ +
+// global thread pool
+
+class thread_pool
+{
+public:
+  thread_pool()
+  {
+    for(int i=0;i<100;++i)p[i]=shared_ptr<thread>(new thread(thread_fun));
+  }
+
+private:
+  static void thread_fun()
+  {
+    // uses flyweight<std::string>
+  }
+  array<shared_ptr<thread>,100> p;
+};
+
+static thread_pool thpool;
+
+int main()
+{
+  ...
+
+ +

+The global pool of the example launches several threads, each of which +internally uses flyweight<std::string>. +Static data initialization can potentially be executed twice concurrently +if two threads happen to collide on the first usage of +flyweight<std::string>: Boost.Flyweight initialization +does not consider thread safety. So, we need to explicitly take care of +static data initialization in a thread safe context before launching +the threads: +

+ +
+class thread_pool
+{
+public:
+  thread_pool()
+  {
+    flyweight<std::string>::init();
+    for(int i=0;i<100;++i)p[i]=shared_ptr<thread>(new thread(thread_fun));
+  }
+  ...
+
+ +

+The static member function init is not thread safe, either: in our particular +example it just happens to be called in a single threaded environment. +When concurrency can happen, flyweight<T>::init must +be properly synchronized by the programmer by using some mutual exclusion +mechanisms of her own. +

+ +

+The following is another example where the default static initialization +provided by Boost.Flyweight can fail: +

+ +
+static std::vector<flyweight<std::string> > v;
+
+int main()
+{
+  // use v
+}
+
+ +

+In some environments, the program above fails at termination time with something +like the following: +

+ +
+Assertion failed: count()==0, file c:\boost\flyweight\refcounted.hpp, line 55
+
+ +

+What is the problem? Although the type of v involves +flyweight<std::string>, constructing v as an empty vector +need not create any flyweight object proper; so, +it is perfectly possible that the static initialization of +flyweight<std::string> happens after the construction +of v; when this is the case, the static destruction of +the associated factory will occur before v's +destruction, leaving the vector with dangling flyweights. +Again, the solution consists in explicitly forcing the static instantiation +of flyweight<std::string> before v is +created. Here, calling +the function flyweight<std::string>::init is a little +cumbersome, so we can resort to the utility type +flyweight<std::string>::initializer to do that job for us: +

+ +
+// equivalent to calling flyweight<std::string>::init()
+static flyweight<std::string>::initializer  fwinit;
+static std::vector<flyweight<std::string> > v;
+
+int main()
+{
+  // use v; no dangling flyweights at termination now
+}
+
+ +
+ + + +
+ +
+ +

Revised August 11th 2008

+ +

© Copyright 2006-2008 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) +

+ + + diff --git a/doc/up.gif b/doc/up.gif new file mode 100644 index 0000000000000000000000000000000000000000..acb3777770f86aaa1172eae92255d962d5ed6edc GIT binary patch literal 853 zcmZ?wbhEHb6krfw_|5>L~%oSd9oTwL7T+&nxy zyu7@8e0==;`~m_3f`WoVLPEmA!XhFfqN1W=Vq)Ur;t~=Pl9G~AQc}{=(lRnKva+&r za&q$W@(KzHii(O#N=nMg$|@=KYmvnwpwgT3XuL+B!Nqy1Kf0dV2c$ z`UVCDhK7blMn=ZQ#wI2vrlzK5W@hH*<`xzfmX?-QR#w*5);2aawzjr*c6Rpm_6`mX zj*gB_PEO9w&Mq!4uCA_bZf@@G?j9ZO-;?s%`Gi0t*xzX zZEfxC?HwH*ot>RsU0vPX-90@$y}iACeSQ7?{Szikm^g9bq)C$|Po6ww%9N>7r%szT zZTj@-GiJ<~IdkT$S+i!(o;_#IoVj!7&YL%H{`~n17A#n}aN(jwixw|lykyCerAwDC zTefWZ^5rX5tXR2n<*HSyRoH%*%du|Ns9wpd0|o3k)1q z4F5T0e(*CeG;s(@`JA}$z^RQzR<1=O;E{8On7Y}S6@iM!du6P{cr+(1IozRUy38iB O;Hl$u16?*225SKAsFtPx literal 0 HcmV?d00001 diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 new file mode 100644 index 0000000..b329a6c --- /dev/null +++ b/example/Jamfile.v2 @@ -0,0 +1,49 @@ +# Boost.Flyweight examples Jamfile +# +# Copyright 2006-2008 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) +# +# See http://www.boost.org/libs/flyweight for library home page. + +project + : requirements + LINUX:multi + ; + +exe basic + : basic.cpp + : $(BOOST_ROOT) + ; + +exe composite + : composite.cpp + : $(BOOST_ROOT) + ; + +exe custom_factory + : custom_factory.cpp + : $(BOOST_ROOT) + ; + +exe fibonacci + : fibonacci.cpp + : $(BOOST_ROOT) + ; + +exe html + : html.cpp + : $(BOOST_ROOT) + ; + +exe key_value + : key_value.cpp + : $(BOOST_ROOT) + ; + +exe perf + : perf.cpp + : $(BOOST_ROOT) + : release + ; diff --git a/example/basic.cpp b/example/basic.cpp new file mode 100644 index 0000000..405dff7 --- /dev/null +++ b/example/basic.cpp @@ -0,0 +1,152 @@ +/* Boost.Flyweight basic example. + * + * Copyright 2006-2008 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 +#include +#include +#include +#include +#include +#include +#include + +using namespace boost::flyweights; + +/* Information associated to a given user of some massive system. + * first_name and last_name are turned into flyweights to leverage the + * implicit redundancy of names within the user community. + */ + +struct user_entry +{ + flyweight first_name; + flyweight last_name; + int age; + + user_entry(); + user_entry(const char* first_name,const char* last_name,int age); + user_entry(const user_entry& x); +}; + +/* flyweight default ctor simply calls the default ctor of + * std::string. + */ + +user_entry::user_entry() +{} + +/* flyweight is constructible from a const char* much as + * a std::string is. + */ + +user_entry::user_entry(const char* f,const char* l,int a): + first_name(f), + last_name(l), + age(a) +{} + +/* flyweight's are copyable and assignable --unlike std::string, + * copy and assignment of flyweights do not ever throw. + */ + +user_entry::user_entry(const user_entry& x): + first_name(x.first_name), + last_name(x.last_name), + age(x.age) +{} + +/* flyweight has operator==,!=,<,>,<=,>= with the same + * semantics as those of std::string. + */ + +bool same_name(const user_entry& user1,const user_entry& user2) +{ + bool b=user1.first_name==user2.first_name && + user1.last_name==user2.last_name; + return b; +} + +/* operator<< forwards to the std::string overload */ + +std::ostream& operator<<(std::ostream& os,const user_entry& user) +{ + return os<> internally uses std::string's operator>> */ + +std::istream& operator>>(std::istream& is,user_entry& user) +{ + return is>>user.first_name>>user.last_name>>user.age; +} + +std::string full_name(const user_entry& user) +{ + std::string full; + + /* get() returns the underlying const std::string& */ + + full.reserve( + user.first_name.get().size()+user.last_name.get().size()+1); + + /* here, on the other hand, implicit conversion is used */ + + full+=user.first_name; + full+=" "; + full+=user.last_name; + + return full; +} + +/* flyweight value is immutable, but a flyweight object can + * be assigned a different value. + */ + +void change_name(user_entry& user,const std::string& f,const std::string& l) +{ + user.first_name=f; + user.last_name=l; +} + +int main() +{ + /* play a little with a vector of user_entry's */ + + std::string users_txt= + "olegh smith 31\n" + "john brown 28\n" + "anna jones 45\n" + "maria garcia 30\n" + "john fox 56\n" + "anna brown 19\n" + "thomas smith 46\n" + "andrew martin 28"; + + std::vector users; + std::istringstream iss(users_txt); + while(iss){ + user_entry u; + if(iss>>u)users.push_back(u); + } + + change_name(users[0],"oleg","smith"); + + user_entry anna("anna","jones",20); + std::replace_if( + users.begin(),users.end(), + boost::bind(same_name,_1,anna), + anna); + + std::copy( + users.begin(),users.end(), + std::ostream_iterator(std::cout,"\n")); + + return 0; +} diff --git a/example/composite.cpp b/example/composite.cpp new file mode 100644 index 0000000..984e4db --- /dev/null +++ b/example/composite.cpp @@ -0,0 +1,179 @@ +/* Boost.Flyweight example of a composite design. + * + * Copyright 2006-2008 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace boost::flyweights; + +/* A node of a lisp-like list can be modeled as a boost::variant of + * 1. A string (primitive node) + * 2. A vector of nodes (embedded list) + * To save space, 2 is stored as a vector of flyweights. + * As is usual with recursive data structures, a node can be thought + * of also as a list. To close the flyweight circle, the final + * type list is a flyweight wrapper, so that the final structure can + * be described as follows in BNF-like style: + * + * list ::= flyweight + * list_impl ::= std::string | std::vector + */ + +struct list_elems; + +typedef boost::variant< + std::string, + boost::recursive_wrapper +> list_impl; + +struct list_elems:std::vector >{}; + +typedef flyweight list; + +/* list_impl must be hashable to be used by flyweight: If a + * node is a std::string, its hash resolves to that of the string; + * if it is a vector of nodes, we compute the hash by combining + * the *addresses* of the stored flyweights' associated values: this is + * consistent because flyweight equality implies equality of reference. + * Using this trick instead of hashing the node values themselves + * allow us to do the computation without recursively descending down + * through the entire data structure. + */ + +struct list_hasher:boost::static_visitor +{ + std::size_t operator()(const std::string& str)const + { + boost::hash h; + return h(str); + } + + std::size_t operator()( + const boost::recursive_wrapper& elmsw)const + { + const list_elems& elms=elmsw.get(); + std::size_t res=0; + for(list_elems::const_iterator it=elms.begin(),it_end=elms.end(); + it!=it_end;++it){ + const list_impl* p=&it->get(); + boost::hash_combine(res,p); + } + return res; + } +}; + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) +namespace boost{ +#endif + +std::size_t hash_value(const list_impl& limpl) +{ + return boost::apply_visitor(list_hasher(),limpl); +} + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) +} /* namespace boost */ +#endif + +/* basic pretty printer with indentation according to the nesting level */ + +struct list_pretty_printer:boost::static_visitor<> +{ + list_pretty_printer():nest(0){} + + void operator()(const std::string& str) + { + indent(); + std::cout<& elmsw) + { + indent(); + std::cout<<"(\n"; + ++nest; + const list_elems& elms=elmsw.get(); + for(list_elems::const_iterator it=elms.begin(),it_end=elms.end(); + it!=it_end;++it){ + boost::apply_visitor(*this,it->get()); + } + --nest; + indent(); + std::cout<<")\n"; + } + +private: + void indent()const + { + for(int i=nest;i--;)std::cout<<" "; + } + + int nest; +}; + +void pretty_print(const list& l) +{ + list_pretty_printer pp; + boost::apply_visitor(pp,l.get()); +} + +/* list parser */ + +template +list parse_list(InputIterator& first,InputIterator last,int nest) +{ + list_elems elms; + while(first!=last){ + std::string str=*first++; + if(str=="("){ + elms.push_back(parse_list(first,last,nest+1)); + } + else if(str==")"){ + if(nest==0)throw std::runtime_error("unmatched )"); + return list(elms); + } + else{ + elms.push_back(list(str)); + } + } + if(nest!=0)throw std::runtime_error("unmatched ("); + return list(elms); +} + +list parse_list(const std::string str) +{ + typedef boost::tokenizer > tokenizer; + tokenizer tok(str,boost::char_separator(" ","()")); + tokenizer::iterator begin=tok.begin(); + return parse_list(begin,tok.end(),0); +} + +int main() +{ + std::cout<<"enter list: "; + std::string str; + std::getline(std::cin,str); + try{ + pretty_print(parse_list(str)); + } + catch(const std::exception& e){ + std::cout<<"error: "< +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace boost::flyweights; + +/* custom factory based on std::set with some logging capabilities */ + +/* Entry is the type of the stored objects. Value is the type + * on which flyweight operates, that is, the T in flyweoght. It + * is guaranteed that Entry implicitly converts to const Value&. + * The factory class could accept other template arguments (for + * instance, a comparison predicate for the values), we leave it like + * that for simplicity. + */ + +template +class verbose_factory_class +{ + /* Entry store. Since Entry is implicitly convertible to const Key&, + * we can directly use std::less as the comparer for std::set. + */ + + typedef std::set > store_type; + + store_type store; + +public: + typedef typename store_type::iterator handle_type; + + handle_type insert(const Entry& x) + { + /* locate equivalent entry or insert otherwise */ + + std::pair p=store.insert(x); + if(p.second){ /* new entry */ + std::cout<<"new: "<<(const Key&)x< accepts it + * as such, is by deriving from boost::flyweights::factory_marker. + * See the documentation for info on alternative tagging methods. + */ + +struct verbose_factory: factory_marker +{ + template + struct apply + { + typedef verbose_factory_class type; + } ; +}; + +/* ready to use it */ + +typedef flyweight fw_string; + +int main() +{ + typedef boost::tokenizer > text_tokenizer; + + + std::string text= + "I celebrate myself, and sing myself, " + "And what I assume you shall assume, " + "For every atom belonging to me as good belongs to you. " + + "I loafe and invite my soul, " + "I lean and loafe at my ease observing a spear of summer grass. " + + "My tongue, every atom of my blood, form'd from this soil, this air, " + "Born here of parents born here from parents the same, and their " + " parents the same, " + "I, now thirty-seven years old in perfect health begin, " + "Hoping to cease not till death."; + + std::vector v; + + text_tokenizer tok(text,boost::char_separator(" \t\n.,;:!?'\"-")); + for(text_tokenizer::iterator it=tok.begin();it!=tok.end();){ + v.push_back(fw_string(*it++)); + } + + return 0; +} diff --git a/example/fibonacci.cpp b/example/fibonacci.cpp new file mode 100644 index 0000000..618c5f2 --- /dev/null +++ b/example/fibonacci.cpp @@ -0,0 +1,58 @@ +/* Boost.Flyweight example of flyweight-based memoization. + * + * Copyright 2006-2008 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 +#include +#include +#include +#include + +using namespace boost::flyweights; + +/* Memoized calculation of Fibonacci numbers */ + +/* This class takes an int n and calculates F(n) at construction time */ + +struct compute_fibonacci; + +/* A Fibonacci number can be modeled as a key-value flyweight + * We choose the no_tracking policy so that the calculations + * persist for future use throughout the program. See + * Tutorial: Configuring Boost.Flyweight: Tracking policies for + * further information on tracking policies. + */ + +typedef flyweight,no_tracking> fibonacci; + +/* Implementation of compute_fibonacci. Note that the construction + * of compute_fibonacci(n) uses fibonacci(n-1) and fibonacci(n-2), + * which effectively memoizes the computation. + */ + +struct compute_fibonacci:private boost::noncopyable +{ + compute_fibonacci(int n): + result(n==0?0:n==1?1:fibonacci(n-2).get()+fibonacci(n-1).get()) + {} + + operator int()const{return result;} + int result; +}; + +int main() +{ + /* list some Fibonacci numbers */ + + for(int n=0;n<40;++n){ + std::cout<<"F("< +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_NO_STDC_NAMESPACE) +namespace std{using ::exit;using ::tolower;} +#endif + +using namespace boost::flyweights; + +/* See the portability section of Boost.Hash at + * http://boost.org/doc/html/hash/portability.html + * for an explanation of the ADL-related workarounds. + */ + +namespace boost{ +#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) +namespace flyweights{ +#endif + +/* We hash the various flyweight types used in the program hashing + * a *pointer* to their contents: this is consistent as equality of + * flyweights implies equality of references. + */ + +template +std::size_t hash_value(const flyweight& x) +{ + boost::hash h; + return h(&x.get()); +} + +#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) +} /* namespace flyweights */ +#endif +} /* namespace boost */ + +/* An HTML tag consists of a name and optional properties of the form + * name1=value1 ... namen=valuen. We do not need to parse the properties + * for the purposes of the program, hence they are all stored in + * html_tag_data::properties in raw form. + */ + +struct html_tag_data +{ + std::string name; + std::string properties; +}; + +bool operator==(const html_tag_data& x,const html_tag_data& y) +{ + return x.name==y.name&&x.properties==y.properties; +} + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) +namespace boost{ +#endif + +std::size_t hash_value(const html_tag_data& x) +{ + std::size_t res=0; + boost::hash_combine(res,x.name); + boost::hash_combine(res,x.properties); + return res; +} + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) +} /* namespace boost */ +#endif + +typedef flyweight html_tag; + +/* parse_tag is passed an iterator positioned at the first char of + * the tag after the opening '<' and returns, if succesful, a parsed tag + * and whether it is opening () or closing (). + */ + +enum tag_type{opening,closing,failure}; + +struct parse_tag_res +{ + parse_tag_res(tag_type type_,const html_tag_data& tag_=html_tag_data()): + type(type_),tag(tag_){} + parse_tag_res(const parse_tag_res& x):type(x.type),tag(x.tag){} + + tag_type type; + html_tag tag; +}; + +template +parse_tag_res parse_tag(ForwardIterator& first,ForwardIterator last) +{ + html_tag_data tag; + std::string buf; + bool in_quote=false; + for(ForwardIterator it=first;it!=last;){ + char ch=*it++; + if(ch=='>'&&!in_quote){ /* ignore '>'s if inside quotes */ + tag_type type; + std::string::size_type + bname=buf.find_first_not_of("\t\n\r "), + ename=bname==std::string::npos? + std::string::npos: + buf.find_first_of("\t\n\r ",bname), + bprop=ename==std::string::npos? + std::string::npos: + buf.find_first_not_of("\t\n\r ",ename); + if(bname==ename){ /* null name */ + return parse_tag_res(failure); + } + else if(buf[bname]=='/'){ /* closing tag */ + type=closing; + ++bname; + } + else type=opening; + tag.name=buf.substr(bname,ename-bname); + std::transform( /* normalize tag name to lower case */ + tag.name.begin(),tag.name.end(),tag.name.begin(), + (int(*)(int))std::tolower); + if(bprop!=std::string::npos){ + tag.properties=buf.substr(bprop,buf.size()); + } + first=it; /* result good, consume the chars */ + return parse_tag_res(type,tag); + } + else{ + if(ch=='"')in_quote=!in_quote; + buf+=ch; + } + } + return parse_tag_res(failure); /* end reached and found no '>' */ +} + +/* A character context is just a vector containing the tags enclosing the + * character, from the outermost level to the innermost. + */ + +typedef std::vector html_context_data; +typedef flyweight html_context; + +/* A character is a char code plus its context. + */ + +struct character_data +{ + character_data(char code_=0,html_context context_=html_context()): + code(code_),context(context_){} + character_data(const character_data& x):code(x.code),context(x.context){} + + char code; + html_context context; +}; + +bool operator==(const character_data& x,const character_data& y) +{ + return x.code==y.code&&x.context==y.context; +} + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) +namespace boost{ +#endif + +std::size_t hash_value(const character_data& x) +{ + std::size_t res=0; + boost::hash_combine(res,x.code); + boost::hash_combine(res,x.context); + return res; +} + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) +} /* namespace boost */ +#endif + +typedef flyweight character; + +/* scan_html converts HTML code into a stream of contextualized characters. + */ + +template +void scan_html(ForwardIterator first,ForwardIterator last,OutputIterator out) +{ + html_context_data context; + while(first!=last){ + if(*first=='<'){ /* tag found */ + ++first; + parse_tag_res res=parse_tag(first,last); + if(res.type==opening){ /* add to contex */ + context.push_back(res.tag); + continue; + } + else if(res.type==closing){ /* remove from context */ + /* Pop all tags from the innermost to the matching one; this takes + * care of missing s like vg. in
  • hello
. + */ + + for(html_context_data::reverse_iterator rit=context.rbegin(); + rit!=context.rend();++rit){ + if(rit->get().name==res.tag.get().name){ + context.erase(rit.base()-1,context.end()); + break; + } + } + continue; + } + } + *out++=character(*first++,html_context(context)); + } +} + +/* HTML-producing utilities */ + +void print_opening_tag(std::ostream& os,const html_tag_data& x) +{ + os<<"<"<"; +} + +void print_closing_tag(std::ostream& os,const html_tag_data& x) +{ + /* SGML declarations (beginning with '!') are not closed */ + + if(x.name[0]!='!')os<<""; +} + +/* change_context takes contexts from and to with tags + * + * from<- c1 ... cn fn+1 ... fm + * to <- c1 ... cn tn+1 ... tk + * + * (that is, they share the first n tags, n might be 0), and + * produces code closing fm ... fn+1 and opening tn+1 ... tk. + */ + +template +void change_context( + const html_context_data& from,const html_context_data& to, + OutputIterator out) +{ + std::ostringstream oss; + html_context_data::const_iterator + it0=from.begin(), + it0_end=from.end(), + it1=to.begin(), + it1_end=to.end(); + for(;it0!=it0_end&&it1!=it1_end&&*it0==*it1;++it0,++it1); + while(it0_end!=it0)print_closing_tag(oss,*--it0_end); + while(it1!=it1_end)print_opening_tag(oss,*it1++); + std::string str=oss.str(); + std::copy(str.begin(),str.end(),out); +} + +/* produce_html is passed a bunch of contextualized characters and emits + * the corresponding HTML. The algorithm is simple: tags are opened and closed + * as a result of the context from one character to the following changing. + */ + +template +void produce_html(ForwardIterator first,ForwardIterator last,OutputIterator out) +{ + html_context context; + while(first!=last){ + if(first->get().context!=context){ + change_context(context,first->get().context,out); + context=first->get().context; + } + *out++=(first++)->get().code; + } + change_context(context,html_context(),out); /* close remaining context */ +} + +/* Without these explicit instantiations, MSVC++ 6.5/7.0 does not + * find some friend operators in certain contexts. + */ + +character dummy1; +html_tag dummy2; + +int main() +{ + std::cout<<"input html file: "; + std::string in; + std::getline(std::cin,in); + std::ifstream ifs(in.c_str()); + if(!ifs){ + std::cout<<"can't open "< istrbuf_iterator; + std::vector html_source; + std::copy( + istrbuf_iterator(ifs),istrbuf_iterator(), + std::back_inserter(html_source)); + + /* parse the HTML */ + + std::vector scanned_html; + scan_html( + html_source.begin(),html_source.end(),std::back_inserter(scanned_html)); + + /* Now that we have the text as a vector of contextualized characters, + * we can shuffle it around and manipulate in almost any way we please. + * For instance, the following reverses the central portion of the doc. + */ + + std::reverse( + scanned_html.begin()+scanned_html.size()/4, + scanned_html.begin()+3*(scanned_html.size()/4)); + + /* emit the resulting HTML */ + + std::cout<<"output html file: "; + std::string out; + std::getline(std::cin,out); + std::ofstream ofs(out.c_str()); + if(!ofs){ + std::cout<<"can't open "< ostrbuf_iterator; + produce_html(scanned_html.begin(),scanned_html.end(),ostrbuf_iterator(ofs)); + + return 0; +} diff --git a/example/key_value.cpp b/example/key_value.cpp new file mode 100644 index 0000000..5a93d07 --- /dev/null +++ b/example/key_value.cpp @@ -0,0 +1,99 @@ +/* Boost.Flyweight example of use of key-value flyweights. + * + * Copyright 2006-2008 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 +#include +#include +#include +#include +#include +#include + +using namespace boost::flyweights; + +/* A class simulating a texture resource loaded from file */ + +class texture +{ +public: + texture(const std::string& filename):filename(filename) + { + std::cout<<"loaded "< +> texture_flyweight; + +int main() +{ + /* texture filenames */ + + const char* texture_filenames[]={ + "grass.texture","sand.texture","water.texture","wood.texture", + "granite.texture","cotton.texture","concrete.texture","carpet.texture" + }; + const int num_texture_filenames= + sizeof(texture_filenames)/sizeof(texture_filenames[0]); + + /* create a massive vector of textures */ + + std::cout<<"creating flyweights...\n"< textures; + for(int i=0;i<50000;++i){ + textures.push_back( + texture_flyweight(texture_filenames[std::rand()%num_texture_filenames])); + } + + /* Just for the sake of making use of the key extractor, + * assign some flyweights with texture objects rather than strings. + */ + + for(int j=0;j<50000;++j){ + textures.push_back( + texture_flyweight( + textures[std::rand()%textures.size()].get())); + } + + std::cout<<"\n"< +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_NO_STDC_NAMESPACE) +namespace std{ +using ::clock; +using ::clock_t; +using ::exit; +} +#endif + +using namespace boost::flyweights; + +/* Instrumented allocator family keeping track of the memory in + * current use. + */ + +std::size_t count_allocator_mem=0; + +template +class count_allocator +{ +public: + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + templatestruct rebind{typedef count_allocator other;}; + + count_allocator(){} + count_allocator(const count_allocator&){} + templatecount_allocator(const count_allocator&,int=0){} + + pointer address(reference x)const{return &x;} + const_pointer address(const_reference x)const{return &x;} + + pointer allocate(size_type n,const void* =0) + { + pointer p=(T*)(new char[n*sizeof(T)]); + count_allocator_mem+=n*sizeof(T); + return p; + } + + void deallocate(void* p,size_type n) + { + count_allocator_mem-=n*sizeof(T); + delete [](char *)p; + } + + size_type max_size() const{return (size_type )(-1);} + void construct(pointer p,const T& val){new(p)T(val);} + void destroy(pointer p){p->~T();} + + friend bool operator==(const count_allocator&,const count_allocator&) + { + return true; + } + + friend bool operator!=(const count_allocator&,const count_allocator&) + { + return false; + } +}; + +template<> +class count_allocator +{ +public: + typedef void* pointer; + typedef const void* const_pointer; + typedef void value_type; + templatestruct rebind{typedef count_allocator other;}; +}; + +/* Define some count_allocator-based types and Boost.Flyweight components */ + +typedef std::basic_string< + char,std::char_traits,count_allocator +> count_string; + +typedef hashed_factory< + boost::hash, + std::equal_to, + count_allocator +> count_hashed_factory; + +typedef set_factory< + std::less, + count_allocator +> count_set_factory; + +/* Some additional utilities used by the test routine */ + +class timer +{ +public: + timer(){restart();} + + void restart(){t=std::clock();} + + void time(const char* str) + { + std::cout< +struct is_flyweight: + boost::mpl::false_{}; + +template< + typename T, + typename Arg1,typename Arg2,typename Arg3,typename Arg4,typename Arg5 +> +struct is_flyweight >: + boost::mpl::true_{}; + +struct length_adder +{ + std::size_t operator()(std::size_t n,const count_string& x)const + { + return n+x.size(); + } +}; + +/* Measure time and memory performance for a String, which is assumed + * to be either a plain string type or a string flyweight. + */ + +template +struct test +{ + static std::size_t run(const std::string& file) + { + typedef std::vector > count_vector; + + /* Define a tokenizer on std::istreambuf. */ + + typedef std::istreambuf_iterator char_iterator; + typedef boost::tokenizer< + boost::char_separator, + char_iterator + > tokenizer; + + std::ifstream ifs(file.c_str()); + if(!ifs){ + std::cout<<"can't open "<( + "", + "\t\n\r !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~")); + count_vector txt; + for(tokenizer::iterator it=tok.begin();it!=tok.end();++it){ + txt.push_back(String(it->c_str())); + } + + t.time("initialization time"); + + /* Assignment */ + + t.restart(); + + count_vector txt2; + for(int i=0;i<10;++i){ + txt2.insert(txt2.end(),txt.begin(),txt.end()); + } + + t.time("assignment time"); + + /* Equality comparison */ + + t.restart(); + + std::size_t c=0; + for(int i=0;i<100;++i){ + c+=std::count(txt.begin(),txt.end(),txt[c%txt.size()]); + } + + t.time("equality comparison time"); + + /* Value access */ + + t.restart(); + + std::size_t s=0; + for(int i=0;i<20;++i){ + s+=std::accumulate(txt2.begin(),txt2.end(),s,length_adder()); + } + + t.time("value access time"); + + std::cout<<"bytes used: "<::value){ + std::size_t flyweight_mem=(txt.capacity()+txt2.capacity())*sizeof(String); + std::cout<<"= flyweights("<::run + }, + { + "flyweight, hashed factory", + test >::run + }, + { + "flyweight, hashed factory, no tracking", + test >::run + }, + { + "flyweight, set-based factory", + test >::run + }, + { + "flyweight, set-based factory, no tracking", + test >::run + } +}; + +const int num_test_cases=sizeof(test_table)/sizeof(test_case); + +int main() +{ + try{ + for(int i=0;i>option; + if(option>=1&&option<=num_test_cases){ + --option; /* pass from 1-based menu to 0-based test_table */ + break; + } + } + + std::cout<<"enter file name: "; + std::string file; + std::getline(std::cin,file); + std::size_t result=0; + result=test_table[option].test(file); + } + catch(const std::exception& e){ + std::cout<<"error: "<=1200) +#pragma once +#endif + +#include +#include +#include +#include +#include + +#endif diff --git a/include/boost/flyweight/assoc_container_factory.hpp b/include/boost/flyweight/assoc_container_factory.hpp new file mode 100644 index 0000000..bf6739d --- /dev/null +++ b/include/boost/flyweight/assoc_container_factory.hpp @@ -0,0 +1,88 @@ +/* Copyright 2006-2008 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_ASSOC_CONTAINER_FACTORY_HPP +#define BOOST_FLYWEIGHT_ASSOC_CONTAINER_FACTORY_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include + +/* Factory class using a given associative container. + */ + +namespace boost{ + +namespace flyweights{ + +template +class assoc_container_factory_class:public factory_marker +{ +public: + typedef typename Container::iterator handle_type; + typedef typename Container::value_type entry_type; + + handle_type insert(const entry_type& x) + { + return cont.insert(x).first; + } + + void erase(handle_type h) + { + cont.erase(h); + } + + static const entry_type& entry(handle_type h){return *h;} + +private: + Container cont; + +public: + typedef assoc_container_factory_class type; + BOOST_MPL_AUX_LAMBDA_SUPPORT(1,assoc_container_factory_class,(Container)) +}; + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) +/* This is preferred to deriving from factory_marker since checking for + * derivation forces the instantiation of the specifier, which is not + * needed when the specifier is a placeholder expression. + */ + +template +struct is_factory >: + boost::mpl::true_{}; +#endif + +/* assoc_container_factory_class specifier */ + +template< + typename ContainerSpecifier + BOOST_FLYWEIGHT_NOT_A_PLACEHOLDER_EXPRESSION_DEF +> +struct assoc_container_factory:factory_marker +{ + template + struct apply + { + typedef assoc_container_factory_class< + typename mpl::apply2::type + > type; + }; +}; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/assoc_container_factory_fwd.hpp b/include/boost/flyweight/assoc_container_factory_fwd.hpp new file mode 100644 index 0000000..2d0c356 --- /dev/null +++ b/include/boost/flyweight/assoc_container_factory_fwd.hpp @@ -0,0 +1,35 @@ +/* Copyright 2006-2008 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_ASSOC_CONTAINER_FACTORY_FWD_HPP +#define BOOST_FLYWEIGHT_ASSOC_CONTAINER_FACTORY_FWD_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include + +namespace boost{ + +namespace flyweights{ + +template +class assoc_container_factory_class; + +template< + typename ContainerSpecifier + BOOST_FLYWEIGHT_NOT_A_PLACEHOLDER_EXPRESSION +> +struct assoc_container_factory; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/detail/default_value_policy.hpp b/include/boost/flyweight/detail/default_value_policy.hpp new file mode 100644 index 0000000..186e1e0 --- /dev/null +++ b/include/boost/flyweight/detail/default_value_policy.hpp @@ -0,0 +1,58 @@ +/* Copyright 2006-2008 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_DETAIL_DEFAULT_VALUE_POLICY_HPP +#define BOOST_FLYWEIGHT_DETAIL_DEFAULT_VALUE_POLICY_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include +#include + +/* Default value policy: the key is the same as the value. + */ + +namespace boost{ + +namespace flyweights{ + +namespace detail{ + +template +struct default_value_policy:value_marker +{ + typedef Value key_type; + typedef Value value_type; + + struct rep_type + { + /* template ctors */ + +#define BOOST_FLYWEIGHT_PERFECT_FWD_NAME explicit rep_type +#define BOOST_FLYWEIGHT_PERFECT_FWD_BODY(n) \ + :x(BOOST_PP_ENUM_PARAMS(n,t)){} +#include + + operator const value_type&()const{return x;} + + value_type x; + }; + + static void construct_value(const rep_type&){} + static void copy_value(const rep_type&){} +}; + +} /* namespace flyweights::detail */ + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/detail/dyn_perfect_fwd.hpp b/include/boost/flyweight/detail/dyn_perfect_fwd.hpp new file mode 100644 index 0000000..e921718 --- /dev/null +++ b/include/boost/flyweight/detail/dyn_perfect_fwd.hpp @@ -0,0 +1,75 @@ +/* Copyright 2006-2008 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. + */ + +/* no include guards */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BOOST_FLYWEIGHT_CONST(b) BOOST_PP_CAT(BOOST_FLYWEIGHT_CONST,b) +#define BOOST_FLYWEIGHT_CONST0 +#define BOOST_FLYWEIGHT_CONST1 const + +/* if mask[n]==0 --> Tn& tn + * if mask[n]==1 --> const Tn& tn + */ + +#define BOOST_FLYWEIGHT_PERFECT_FWD_ARG(z,n,mask) \ +BOOST_FLYWEIGHT_CONST(BOOST_PP_SEQ_ELEM(n,mask)) \ +BOOST_PP_CAT(T,n)& BOOST_PP_CAT(t,n) + +/* overload accepting size(mask) args, where the template args are + * marked const or not according to the given mask (a seq of 0 or 1) + */ + +#define BOOST_FLYWEIGHT_PERFECT_FWD(r,mask) \ +template \ +BOOST_FLYWEIGHT_PERFECT_FWD_NAME( \ + BOOST_PP_ENUM( \ + BOOST_PP_SEQ_SIZE(mask),BOOST_FLYWEIGHT_PERFECT_FWD_ARG,mask)) \ +BOOST_FLYWEIGHT_PERFECT_FWD_BODY(BOOST_PP_SEQ_SIZE(mask)) + +#define BOOST_FLYWEIGHT_01(z,n,_) ((0)(1)) + +/* Perfect forwarding overloads accepting 1 to n args */ + +#define BOOST_FLYWEIGHT_PERFECT_FWDS_N(z,n,_) \ +BOOST_PP_SEQ_FOR_EACH_PRODUCT( \ + BOOST_FLYWEIGHT_PERFECT_FWD, \ + BOOST_PP_REPEAT(n,BOOST_FLYWEIGHT_01,~)) + +#define BOOST_FLYWEIGHT_PERFECT_FWD_OVERLOADS \ +BOOST_PP_REPEAT_FROM_TO( \ + 1,BOOST_PP_ADD(BOOST_FLYWEIGHT_LIMIT_PERFECT_FWD_ARGS,1), \ + BOOST_FLYWEIGHT_PERFECT_FWDS_N,~) + +/* generate the overloads */ + +BOOST_FLYWEIGHT_PERFECT_FWD_OVERLOADS + +/* clean up */ + +#undef BOOST_FLYWEIGHT_PERFECT_FWD_OVERLOADS +#undef BOOST_FLYWEIGHT_01 +#undef BOOST_FLYWEIGHT_PERFECT_FWD +#undef BOOST_FLYWEIGHT_PERFECT_FWD_ARG +#undef BOOST_FLYWEIGHT_CONST1 +#undef BOOST_FLYWEIGHT_CONST0 +#undef BOOST_FLYWEIGHT_CONST + +/* user supplied argument macros */ + +#undef BOOST_FLYWEIGHT_PERFECT_FWD_BODY +#undef BOOST_FLYWEIGHT_PERFECT_FWD_NAME diff --git a/include/boost/flyweight/detail/flyweight_core.hpp b/include/boost/flyweight/detail/flyweight_core.hpp new file mode 100644 index 0000000..786674d --- /dev/null +++ b/include/boost/flyweight/detail/flyweight_core.hpp @@ -0,0 +1,256 @@ +/* Copyright 2006-2008 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_DETAIL_FLYWEIGHT_CORE_HPP +#define BOOST_FLYWEIGHT_DETAIL_FLYWEIGHT_CORE_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include + +#if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1400)) +#pragma warning(push) +#pragma warning(disable:4101) /* unreferenced local vars */ +#endif + +/* flyweight_core provides the inner implementation of flyweight<> by + * weaving together a value policy, a flyweight factory, a holder for the + * factory,a tracking policy and a locking policy. + */ + +namespace boost{ + +namespace flyweights{ + +namespace detail{ + +template< + typename ValuePolicy,typename Tag,typename TrackingPolicy, + typename FactorySpecifier,typename LockingPolicy,typename HolderSpecifier +> +class flyweight_core; + +template< + typename ValuePolicy,typename Tag,typename TrackingPolicy, + typename FactorySpecifier,typename LockingPolicy,typename HolderSpecifier +> +struct flyweight_core_tracking_helper +{ +private: + typedef flyweight_core< + ValuePolicy,Tag,TrackingPolicy, + FactorySpecifier,LockingPolicy, + HolderSpecifier + > core; + typedef typename core::handle_type handle_type; + typedef typename core::entry_type entry_type; + +public: + static const entry_type& entry(const handle_type& h) + { + return core::entry(h); + } + + template + static void erase(const handle_type& h,Checker check) + { + typedef typename core::lock_type lock_type; + lock_type lock(core::mutex()); + if(check(h))core::factory().erase(h); + } +}; + +template< + typename ValuePolicy,typename Tag,typename TrackingPolicy, + typename FactorySpecifier,typename LockingPolicy,typename HolderSpecifier +> +class flyweight_core +{ +public: + typedef typename ValuePolicy::key_type key_type; + typedef typename ValuePolicy::value_type value_type; + typedef typename ValuePolicy::rep_type rep_type; + typedef typename mpl::apply2< + typename TrackingPolicy::entry_type, + rep_type, + key_type + >::type entry_type; + typedef typename mpl::apply2< + FactorySpecifier, + entry_type, + key_type + >::type base_factory_type; + typedef typename mpl::apply2< + typename TrackingPolicy::handle_type, + typename base_factory_type::handle_type, + flyweight_core_tracking_helper< + ValuePolicy,Tag,TrackingPolicy, + FactorySpecifier,LockingPolicy, + HolderSpecifier + > + >::type handle_type; + typedef handle_factory_adaptor< + base_factory_type, + handle_type,entry_type + > factory_type; + typedef typename LockingPolicy::mutex_type mutex_type; + typedef typename LockingPolicy::lock_type lock_type; + + static bool init() + { + if(static_initializer)return true; + else{ + holder_arg& a=holder_type::get(); + static_factory_ptr=&a.factory; + static_mutex_ptr=&a.mutex; + static_initializer=(static_factory_ptr!=0); + return static_initializer; + } + } + + /* insert overloads*/ + +#define BOOST_FLYWEIGHT_PERFECT_FWD_NAME static handle_type insert +#define BOOST_FLYWEIGHT_PERFECT_FWD_BODY(n) \ +{ \ + return insert_rep(rep_type(BOOST_PP_ENUM_PARAMS(n,t))); \ +} +#include + + static handle_type insert(const value_type& x){return insert_value(x);} + static handle_type insert(value_type& x){return insert_value(x);} + + static const entry_type& entry(const handle_type& h) + { + return factory().entry(h); + } + + static const value_type& value(const handle_type& h) + { + return static_cast(entry(h)); + } + + static const key_type& key(const handle_type& h) + { + return static_cast(entry(h)); + } + + static factory_type& factory() + { + return *static_factory_ptr; + } + + static mutex_type& mutex() + { + return *static_mutex_ptr; + } + +private: + struct holder_arg + { + factory_type factory; + mutex_type mutex; + }; + typedef typename mpl::apply1< + HolderSpecifier, + holder_arg + >::type holder_type; + + static handle_type insert_rep(const rep_type& x) + { + init(); + entry_type e(x); + lock_type lock(mutex()); + handle_type h(factory().insert(e)); + BOOST_TRY{ + ValuePolicy::construct_value( + static_cast(entry(h))); + } + BOOST_CATCH(...){ + factory().erase(h); + BOOST_RETHROW; + } + BOOST_CATCH_END + return h; + } + + static handle_type insert_value(const value_type& x) + { + init(); + entry_type e=entry_type(rep_type(x)); + lock_type lock(mutex()); + handle_type h(factory().insert(e)); + BOOST_TRY{ + ValuePolicy::copy_value( + static_cast(entry(h))); + } + BOOST_CATCH(...){ + factory().erase(h); + BOOST_RETHROW; + } + BOOST_CATCH_END + return h; + } + + static bool static_initializer; + static factory_type* static_factory_ptr; + static mutex_type* static_mutex_ptr; +}; + +template< + typename ValuePolicy,typename Tag,typename TrackingPolicy, + typename FactorySpecifier,typename LockingPolicy,typename HolderSpecifier +> +bool +flyweight_core< + ValuePolicy,Tag,TrackingPolicy, + FactorySpecifier,LockingPolicy,HolderSpecifier>::static_initializer= + flyweight_core< + ValuePolicy,Tag,TrackingPolicy, + FactorySpecifier,LockingPolicy,HolderSpecifier>::init(); + +template< + typename ValuePolicy,typename Tag,typename TrackingPolicy, + typename FactorySpecifier,typename LockingPolicy,typename HolderSpecifier +> +typename flyweight_core< + ValuePolicy,Tag,TrackingPolicy, + FactorySpecifier,LockingPolicy,HolderSpecifier>::factory_type* +flyweight_core< + ValuePolicy,Tag,TrackingPolicy, + FactorySpecifier,LockingPolicy,HolderSpecifier>::static_factory_ptr=0; + +template< + typename ValuePolicy,typename Tag,typename TrackingPolicy, + typename FactorySpecifier,typename LockingPolicy,typename HolderSpecifier +> +typename flyweight_core< + ValuePolicy,Tag,TrackingPolicy, + FactorySpecifier,LockingPolicy,HolderSpecifier>::mutex_type* +flyweight_core< + ValuePolicy,Tag,TrackingPolicy, + FactorySpecifier,LockingPolicy,HolderSpecifier>::static_mutex_ptr=0; + +} /* namespace flyweights::detail */ + +} /* namespace flyweights */ + +} /* namespace boost */ + +#if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1400)) +#pragma warning(pop) +#endif + +#endif diff --git a/include/boost/flyweight/detail/handle_factory_adaptor.hpp b/include/boost/flyweight/detail/handle_factory_adaptor.hpp new file mode 100644 index 0000000..90de322 --- /dev/null +++ b/include/boost/flyweight/detail/handle_factory_adaptor.hpp @@ -0,0 +1,48 @@ +/* Copyright 2006-2008 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_DETAIL_HANDLE_FACTORY_ADAPTOR_HPP +#define BOOST_FLYWEIGHT_DETAIL_HANDLE_FACTORY_ADAPTOR_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +/* Given a Factory and a Handle type constructible from and implicitly + * convertible to Factory::handle_type, handle_factory_adaptor + * adapts Factory to present Handle as the associated handle_type. + */ + +namespace boost{ + +namespace flyweights{ + +namespace detail{ + +template +struct handle_factory_adaptor:Factory +{ +public: + typedef Handle handle_type; + + handle_type insert(const Entry& x) + { + return static_cast(base().insert(x)); + } + +private: + Factory& base(){return *this;} +}; + +} /* namespace flyweights::detail */ + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/detail/not_placeholder_expr.hpp b/include/boost/flyweight/detail/not_placeholder_expr.hpp new file mode 100644 index 0000000..a62bd09 --- /dev/null +++ b/include/boost/flyweight/detail/not_placeholder_expr.hpp @@ -0,0 +1,58 @@ +/* Copyright 2006-2008 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_DETAIL_NOT_PLACEHOLDER_EXPR_HPP +#define BOOST_FLYWEIGHT_DETAIL_NOT_PLACEHOLDER_EXPR_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +/* BOOST_FLYWEIGHT_NOT_A_PLACEHOLDER_EXPRESSION can be inserted at the end + * of a class template parameter declaration: + * template< + * typename X0,...,typename Xn + * BOOST_FLYWEIGHT_NOT_A_PLACEHOLDER_EXPRESSION + * > + * struct foo... + * to prevent instantiations from being treated as MPL placeholder + * expressions in the presence of placeholder arguments; this is useful + * to avoid masking of a metafunction class nested ::apply during + * MPL invocation. + */ + +#include /* keep it first to prevent nasty warns in MSVC */ +#include + +#if BOOST_WORKAROUND(__GNUC__, <4)||\ + BOOST_WORKAROUND(__GNUC__,==4)&&(__GNUC_MINOR__<2) +/* The default trick on which the macro is based, namely adding a int=0 + * defaulted template parameter, does not work in GCC prior to 4.2 due to + * an unfortunate compiler non-standard extension, as explained in + * http://lists.boost.org/boost-users/2007/07/29866.php + * We resort to an uglier technique, adding defaulted template parameters + * so as to exceed BOOST_MPL_LIMIT_METAFUNCTION_ARITY. + */ + +#include +#include +#include + +#define BOOST_FLYWEIGHT_NOT_A_PLACEHOLDER_EXPRESSION \ +BOOST_PP_ENUM_TRAILING_PARAMS( \ + BOOST_MPL_LIMIT_METAFUNCTION_ARITY,typename=int BOOST_PP_INTERCEPT) +#define BOOST_FLYWEIGHT_NOT_A_PLACEHOLDER_EXPRESSION_DEF \ +BOOST_PP_ENUM_TRAILING_PARAMS( \ + BOOST_MPL_LIMIT_METAFUNCTION_ARITY,typename BOOST_PP_INTERCEPT) + +#else +#define BOOST_FLYWEIGHT_NOT_A_PLACEHOLDER_EXPRESSION ,int=0 +#define BOOST_FLYWEIGHT_NOT_A_PLACEHOLDER_EXPRESSION_DEF ,int +#endif + +#endif diff --git a/include/boost/flyweight/detail/perfect_fwd.hpp b/include/boost/flyweight/detail/perfect_fwd.hpp new file mode 100644 index 0000000..05d670c --- /dev/null +++ b/include/boost/flyweight/detail/perfect_fwd.hpp @@ -0,0 +1,28 @@ +/* Copyright 2006-2008 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. + */ + +/* Brute force implementation of perfect forwarding overloads. + * Usage: include after having defined the argument macros: + * BOOST_FLYWEIGHT_PERFECT_FWD_NAME + * BOOST_FLYWEIGHT_PERFECT_FWD_BODY + */ + +/* This user_definable macro limits the maximum number of arguments to + * be perfect forwarded. Beware combinatorial explosion: manual perfect + * forwarding for n arguments produces 2^n distinct overloads. + */ + +#if !defined(BOOST_FLYWEIGHT_LIMIT_PERFECT_FWD_ARGS) +#define BOOST_FLYWEIGHT_LIMIT_PERFECT_FWD_ARGS 5 +#endif + +#if BOOST_FLYWEIGHT_LIMIT_PERFECT_FWD_ARGS<=5 +#include +#else +#include +#endif diff --git a/include/boost/flyweight/detail/pp_perfect_fwd.hpp b/include/boost/flyweight/detail/pp_perfect_fwd.hpp new file mode 100644 index 0000000..889d4c7 --- /dev/null +++ b/include/boost/flyweight/detail/pp_perfect_fwd.hpp @@ -0,0 +1,153 @@ +/* Copyright 2006-2008 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. + */ + +/* no include guards */ + +#if BOOST_FLYWEIGHT_LIMIT_PERFECT_FWD_ARGS>=1 +#define BOOST_FLYWEIGHT_PERFECT_FWDS_1 \ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(1)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(1) +#endif + +#if BOOST_FLYWEIGHT_LIMIT_PERFECT_FWD_ARGS>=2 +#define BOOST_FLYWEIGHT_PERFECT_FWDS_2 \ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,T1& t1)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(2)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,const T1& t1)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(2)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,T1& t1)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(2)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,const T1& t1)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(2) +#endif + +#if BOOST_FLYWEIGHT_LIMIT_PERFECT_FWD_ARGS>=3 +#define BOOST_FLYWEIGHT_PERFECT_FWDS_3 \ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,T1& t1,T2& t2)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(3)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,T1& t1,const T2& t2)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(3)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,const T1& t1,T2& t2)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(3)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,const T1& t1,const T2& t2)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(3)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,T1& t1,T2& t2)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(3)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,T1& t1,const T2& t2)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(3)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,const T1& t1,T2& t2)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(3)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,const T1& t1,const T2& t2)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(3) +#endif + +#if BOOST_FLYWEIGHT_LIMIT_PERFECT_FWD_ARGS>=4 +#define BOOST_FLYWEIGHT_PERFECT_FWDS_4 \ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,T1& t1,T2& t2,T3& t3)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(4)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,T1& t1,T2& t2,const T3& t3)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(4)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,T1& t1,const T2& t2,T3& t3)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(4)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,T1& t1,const T2& t2,const T3& t3)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(4)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,const T1& t1,T2& t2,T3& t3)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(4)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,const T1& t1,T2& t2,const T3& t3)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(4)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,const T1& t1,const T2& t2,T3& t3)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(4)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,const T1& t1,const T2& t2,const T3& t3)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(4)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,T1& t1,T2& t2,T3& t3)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(4)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,T1& t1,T2& t2,const T3& t3)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(4)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,T1& t1,const T2& t2,T3& t3)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(4)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,T1& t1,const T2& t2,const T3& t3)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(4)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,const T1& t1,T2& t2,T3& t3)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(4)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,const T1& t1,T2& t2,const T3& t3)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(4)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,const T1& t1,const T2& t2,T3& t3)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(4)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,const T1& t1,const T2& t2,const T3& t3)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(4) +#endif + +#if BOOST_FLYWEIGHT_LIMIT_PERFECT_FWD_ARGS>=5 +#define BOOST_FLYWEIGHT_PERFECT_FWDS_5 \ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,T1& t1,T2& t2,T3& t3,T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,T1& t1,T2& t2,T3& t3,const T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,T1& t1,T2& t2,const T3& t3,T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,T1& t1,T2& t2,const T3& t3,const T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,T1& t1,const T2& t2,T3& t3,T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,T1& t1,const T2& t2,T3& t3,const T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,T1& t1,const T2& t2,const T3& t3,T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,T1& t1,const T2& t2,const T3& t3,const T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,const T1& t1,T2& t2,T3& t3,T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,const T1& t1,T2& t2,T3& t3,const T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,const T1& t1,T2& t2,const T3& t3,T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,const T1& t1,T2& t2,const T3& t3,const T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,const T1& t1,const T2& t2,T3& t3,T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,const T1& t1,const T2& t2,T3& t3,const T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,const T1& t1,const T2& t2,const T3& t3,T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(T0& t0,const T1& t1,const T2& t2,const T3& t3,const T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,T1& t1,T2& t2,T3& t3,T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,T1& t1,T2& t2,T3& t3,const T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,T1& t1,T2& t2,const T3& t3,T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,T1& t1,T2& t2,const T3& t3,const T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,T1& t1,const T2& t2,T3& t3,T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,T1& t1,const T2& t2,T3& t3,const T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,T1& t1,const T2& t2,const T3& t3,T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,T1& t1,const T2& t2,const T3& t3,const T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,const T1& t1,T2& t2,T3& t3,T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,const T1& t1,T2& t2,T3& t3,const T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,const T1& t1,T2& t2,const T3& t3,T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,const T1& t1,T2& t2,const T3& t3,const T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,const T1& t1,const T2& t2,T3& t3,T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,const T1& t1,const T2& t2,T3& t3,const T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,const T1& t1,const T2& t2,const T3& t3,T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5)\ +template BOOST_FLYWEIGHT_PERFECT_FWD_NAME(const T0& t0,const T1& t1,const T2& t2,const T3& t3,const T4& t4)BOOST_FLYWEIGHT_PERFECT_FWD_BODY(5) +#endif + +#if BOOST_FLYWEIGHT_LIMIT_PERFECT_FWD_ARGS==0 +#define BOOST_FLYWEIGHT_PERFECT_FWD_OVERLOADS +#elif BOOST_FLYWEIGHT_LIMIT_PERFECT_FWD_ARGS==1 +#define BOOST_FLYWEIGHT_PERFECT_FWD_OVERLOADS \ +BOOST_FLYWEIGHT_PERFECT_FWDS_1 +#elif BOOST_FLYWEIGHT_LIMIT_PERFECT_FWD_ARGS==2 +#define BOOST_FLYWEIGHT_PERFECT_FWD_OVERLOADS \ +BOOST_FLYWEIGHT_PERFECT_FWDS_1 \ +BOOST_FLYWEIGHT_PERFECT_FWDS_2 +#elif BOOST_FLYWEIGHT_LIMIT_PERFECT_FWD_ARGS==3 +#define BOOST_FLYWEIGHT_PERFECT_FWD_OVERLOADS \ +BOOST_FLYWEIGHT_PERFECT_FWDS_1 \ +BOOST_FLYWEIGHT_PERFECT_FWDS_2 \ +BOOST_FLYWEIGHT_PERFECT_FWDS_3 +#elif BOOST_FLYWEIGHT_LIMIT_PERFECT_FWD_ARGS==4 +#define BOOST_FLYWEIGHT_PERFECT_FWD_OVERLOADS \ +BOOST_FLYWEIGHT_PERFECT_FWDS_1 \ +BOOST_FLYWEIGHT_PERFECT_FWDS_2 \ +BOOST_FLYWEIGHT_PERFECT_FWDS_3 \ +BOOST_FLYWEIGHT_PERFECT_FWDS_4 +#else /* BOOST_FLYWEIGHT_LIMIT_PERFECT_FWD_ARGS==5 */ +#define BOOST_FLYWEIGHT_PERFECT_FWD_OVERLOADS \ +BOOST_FLYWEIGHT_PERFECT_FWDS_1 \ +BOOST_FLYWEIGHT_PERFECT_FWDS_2 \ +BOOST_FLYWEIGHT_PERFECT_FWDS_3 \ +BOOST_FLYWEIGHT_PERFECT_FWDS_4 \ +BOOST_FLYWEIGHT_PERFECT_FWDS_5 +#endif + +/* generate the overloads */ + +BOOST_FLYWEIGHT_PERFECT_FWD_OVERLOADS + +/* clean up */ + +#undef BOOST_FLYWEIGHT_PERFECT_FWD_OVERLOADS + +#if BOOST_FLYWEIGHT_LIMIT_PERFECT_FWD_ARGS>=1 +#undef BOOST_FLYWEIGHT_PERFECT_FWDS_1 +#endif + +#if BOOST_FLYWEIGHT_LIMIT_PERFECT_FWD_ARGS>=2 +#undef BOOST_FLYWEIGHT_PERFECT_FWDS_2 +#endif + +#if BOOST_FLYWEIGHT_LIMIT_PERFECT_FWD_ARGS>=3 +#undef BOOST_FLYWEIGHT_PERFECT_FWDS_3 +#endif + +#if BOOST_FLYWEIGHT_LIMIT_PERFECT_FWD_ARGS>=4 +#undef BOOST_FLYWEIGHT_PERFECT_FWDS_4 +#endif + +#if BOOST_FLYWEIGHT_LIMIT_PERFECT_FWD_ARGS>=5 +#undef BOOST_FLYWEIGHT_PERFECT_FWDS_5 +#endif + +/* user supplied argument macros */ + +#undef BOOST_FLYWEIGHT_PERFECT_FWD_NAME +#undef BOOST_FLYWEIGHT_PERFECT_FWD_BODY diff --git a/include/boost/flyweight/detail/process_id.hpp b/include/boost/flyweight/detail/process_id.hpp new file mode 100644 index 0000000..b52ce35 --- /dev/null +++ b/include/boost/flyweight/detail/process_id.hpp @@ -0,0 +1,81 @@ +/* Copyright 2006-2008 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_DETAIL_PROCESS_ID_HPP +#define BOOST_FLYWEIGHT_DETAIL_PROCESS_ID_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include + +#if defined(BOOST_WINDOWS)&&!defined(BOOST_DISABLE_WIN32) + +#if defined(BOOST_USE_WINDOWS_H) +#include +#else +namespace boost{ +namespace flyweights{ +namespace detail{ + +extern "C" __declspec(dllimport) +unsigned long __stdcall GetCurrentProcessId(void); + +} /* namespace flyweights::detail */ +} /* namespace flyweights */ +} /* namespace boost */ +#endif + +namespace boost{ + +namespace flyweights{ + +namespace detail{ + +typedef unsigned long process_id_t; + +inline process_id_t process_id() +{ + return GetCurrentProcessId(); +} + +} /* namespace flyweights::detail */ + +} /* namespace flyweights */ + +} /* namespace boost */ + +#elif defined(BOOST_HAS_UNISTD_H) + +#include + +namespace boost{ + +namespace flyweights{ + +namespace detail{ + +typedef pid_t process_id_t; + +inline process_id_t process_id() +{ + return ::getpid(); +} + +} /* namespace flyweights::detail */ + +} /* namespace flyweights */ + +} /* namespace boost */ + +#else +#error Unknown platform +#endif + +#endif diff --git a/include/boost/flyweight/detail/recursive_lw_mutex.hpp b/include/boost/flyweight/detail/recursive_lw_mutex.hpp new file mode 100644 index 0000000..5bb2082 --- /dev/null +++ b/include/boost/flyweight/detail/recursive_lw_mutex.hpp @@ -0,0 +1,91 @@ +/* Copyright 2006-2008 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_DETAIL_RECURSIVE_LW_MUTEX_HPP +#define BOOST_FLYWEIGHT_DETAIL_RECURSIVE_LW_MUTEX_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +/* Recursive lightweight mutex. Relies entirely on + * boost::detail::lightweight_mutex, except in Pthreads, where we + * explicitly use the PTHREAD_MUTEX_RECURSIVE attribute + * (lightweight_mutex uses the default mutex type instead). + */ + +#include + +#if !defined(BOOST_HAS_PTHREADS) +#include +namespace boost{ + +namespace flyweights{ + +namespace detail{ + +typedef boost::detail::lightweight_mutex recursive_lightweight_mutex; + +} /* namespace flyweights::detail */ + +} /* namespace flyweights */ + +} /* namespace boost */ +#else +/* code shamelessly ripped from */ + +#include +#include + +namespace boost{ + +namespace flyweights{ + +namespace detail{ + +struct recursive_lightweight_mutex:noncopyable +{ + recursive_lightweight_mutex() + { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&m_,&attr); + pthread_mutexattr_destroy(&attr); + } + + ~recursive_lightweight_mutex(){pthread_mutex_destroy(&m_);} + + struct scoped_lock; + friend struct scoped_lock; + struct scoped_lock:noncopyable + { + public: + scoped_lock(recursive_lightweight_mutex& m):m_(m.m_) + { + pthread_mutex_lock(&m_); + } + + ~scoped_lock(){pthread_mutex_unlock(&m_);} + + private: + pthread_mutex_t& m_; + }; + +private: + pthread_mutex_t m_; +}; + +} /* namespace flyweights::detail */ + +} /* namespace flyweights */ + +} /* namespace boost */ +#endif + +#endif diff --git a/include/boost/flyweight/detail/value_tag.hpp b/include/boost/flyweight/detail/value_tag.hpp new file mode 100644 index 0000000..cf4b572 --- /dev/null +++ b/include/boost/flyweight/detail/value_tag.hpp @@ -0,0 +1,50 @@ +/* Copyright 2006-2008 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_DETAIL_VALUE_TAG_HPP +#define BOOST_FLYWEIGHT_DETAIL_VALUE_TAG_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include + +namespace boost{ + +namespace flyweights{ + +namespace detail{ + +/* Three ways to indicate that a given class T is a value policy: + * 1. Make it derived from value_marker. + * 2. Specialize is_value to evaluate to boost::mpl::true_. + * 3. Pass it as value when defining a flyweight type. + * + * For the time being the interface of value policies is not public. + */ + +struct value_marker{}; + +template +struct is_value:is_base_and_derived +{}; + +template +struct value:parameter::template_keyword,T> +{}; + +} /* namespace flyweights::detail */ + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/factory_tag.hpp b/include/boost/flyweight/factory_tag.hpp new file mode 100644 index 0000000..ddb7473 --- /dev/null +++ b/include/boost/flyweight/factory_tag.hpp @@ -0,0 +1,44 @@ +/* Copyright 2006-2008 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_FACTORY_TAG_HPP +#define BOOST_FLYWEIGHT_FACTORY_TAG_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include + +namespace boost{ + +namespace flyweights{ + +/* Three ways to indicate that a given class T is a factory specifier: + * 1. Make it derived from factory_marker. + * 2. Specialize is_factory to evaluate to boost::mpl::true_. + * 3. Pass it as factory when defining a flyweight type. + */ + +struct factory_marker{}; + +template +struct is_factory:is_base_and_derived +{}; + +template +struct factory:parameter::template_keyword,T> +{}; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/flyweight.hpp b/include/boost/flyweight/flyweight.hpp new file mode 100644 index 0000000..0b4ee33 --- /dev/null +++ b/include/boost/flyweight/flyweight.hpp @@ -0,0 +1,407 @@ +/* Flyweight class. + * + * Copyright 2006-2008 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_FLYWEIGHT_HPP +#define BOOST_FLYWEIGHT_FLYWEIGHT_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1400)) +#pragma warning(push) +#pragma warning(disable:4521) /* multiple copy ctors */ +#endif + +namespace boost{ + +namespace flyweights{ + +namespace detail{ + +/* Used for the detection of unmatched template args in a + * flyweight instantiation. + */ + +struct unmatched_arg; + +/* Boost.Parameter structures for use in flyweight. + * NB: these types are derived from instead of typedef'd to force their + * instantiation, which solves http://bugs.sun.com/view_bug.do?bug_id=6782987 + * as found out by Simon Atanasyan. + */ + +struct flyweight_signature: + parameter::parameters< + parameter::optional< + parameter::deduced >, + detail::is_tag + >, + parameter::optional< + parameter::deduced >, + is_tracking + >, + parameter::optional< + parameter::deduced >, + is_factory + >, + parameter::optional< + parameter::deduced >, + is_locking + >, + parameter::optional< + parameter::deduced >, + is_holder + > + > +{}; + +struct flyweight_unmatched_signature: + parameter::parameters< + parameter::optional< + parameter::deduced< + detail::unmatched_arg + >, + mpl::not_< + mpl::or_< + detail::is_tag, + is_tracking, + is_factory, + is_locking, + is_holder + > + > + > + > +{}; + +} /* namespace flyweights::detail */ + +template< + typename T, + typename Arg1,typename Arg2,typename Arg3,typename Arg4,typename Arg5 +> +class flyweight +{ +private: + typedef typename mpl::if_< + detail::is_value, + T, + detail::default_value_policy + >::type value_policy; + typedef typename detail:: + flyweight_signature::bind< + Arg1,Arg2,Arg3,Arg4,Arg5 + >::type args; + typedef typename parameter::binding< + args,tag<>,mpl::na + >::type tag_type; + typedef typename parameter::binding< + args,tracking<>,refcounted + >::type tracking_policy; + typedef typename parameter::binding< + args,factory<>,hashed_factory<> + >::type factory_specifier; + typedef typename parameter::binding< + args,locking<>,simple_locking + >::type locking_policy; + typedef typename parameter::binding< + args,holder<>,static_holder + >::type holder_specifier; + + typedef typename detail:: + flyweight_unmatched_signature::bind< + Arg1,Arg2,Arg3,Arg4,Arg5 + >::type unmatched_args; + typedef typename parameter::binding< + unmatched_args,detail::unmatched_arg, + detail::unmatched_arg + >::type unmatched_arg_detected; + + /* You have passed a type in the specification of a flyweight type that + * could not be interpreted as a valid argument. + */ + BOOST_MPL_ASSERT_MSG( + (is_same::value), + INVALID_ARGUMENT_TO_FLYWEIGHT, + (flyweight)); + + typedef detail::flyweight_core< + value_policy,tag_type,tracking_policy, + factory_specifier,locking_policy, + holder_specifier + > core; + typedef typename core::handle_type handle_type; + +public: + typedef typename value_policy::key_type key_type; + typedef typename value_policy::value_type value_type; + + /* static data initialization */ + + static bool init(){return core::init();} + + class initializer + { + public: + initializer():b(init()){} + private: + bool b; + }; + + /* construct/copy/destroy */ + + flyweight():h(core::insert(key_type())){} + flyweight(const flyweight& x):h(x.h){} + flyweight(flyweight& x):h(x.h){} + + /* template ctors */ + +#define BOOST_FLYWEIGHT_PERFECT_FWD_NAME explicit flyweight +#define BOOST_FLYWEIGHT_PERFECT_FWD_BODY(n) \ + :h(core::insert(BOOST_PP_ENUM_PARAMS(n,t))){} +#include + + flyweight& operator=(const flyweight x){h=x.h;return *this;} + flyweight& operator=(const value_type& x){return operator=(flyweight(x));} + + /* convertibility to underlying type */ + + const key_type& get_key()const{return core::key(h);} + const value_type& get()const{return core::value(h);} + operator const value_type&()const{return get();} + + /* exact type equality */ + + friend bool operator==(const flyweight& x,const flyweight& y) + { + return &x.get()==&y.get(); + } + + /* modifiers */ + + void swap(flyweight& x){boost::swap(h,x.h);} + +private: + handle_type h; +}; + +#define BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(n) \ +typename Arg##n##1,typename Arg##n##2,typename Arg##n##3, \ +typename Arg##n##4,typename Arg##n##5 +#define BOOST_FLYWEIGHT_TEMPL_ARGS(n) \ +Arg##n##1,Arg##n##2,Arg##n##3,Arg##n##4,Arg##n##5 + +/* Comparison. Unlike exact type comparison defined above, intertype + * comparison just forwards to the underlying objects. + */ + +template< + typename T1,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1), + typename T2,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2) +> +bool operator==( + const flyweight& x, + const flyweight& y) +{ + return x.get()==y.get(); +} + +template< + typename T1,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1), + typename T2,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2) +> +bool operator<( + const flyweight& x, + const flyweight& y) +{ + return x.get() +bool operator==( + const flyweight& x,const T2& y) +{ + return x.get()==y; +} + +template< + typename T1, + typename T2,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2) +> +bool operator==( + const T1& x,const flyweight& y) +{ + return x==y.get(); +} + +template< + typename T1,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1), + typename T2 +> +bool operator<( + const flyweight& x,const T2& y) +{ + return x.get() +bool operator<( + const T1& x,const flyweight& y) +{ + return x \ +inline bool operator!=(const a1& x,const a2& y) \ +{ \ + return !(x==y); \ +} \ + \ +template \ +inline bool operator>(const a1& x,const a2& y) \ +{ \ + return y \ +inline bool operator>=(const a1& x,const a2& y) \ +{ \ + return !(x \ +inline bool operator<=(const a1& x,const a2& y) \ +{ \ + return !(y, + flyweight< + T2 BOOST_PP_COMMA() BOOST_FLYWEIGHT_TEMPL_ARGS(2) + >) + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) +BOOST_FLYWEIGHT_COMPLETE_COMP_OPS( + typename T1 BOOST_PP_COMMA() + BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1) BOOST_PP_COMMA() + typename T2, + flyweight< + T1 BOOST_PP_COMMA() BOOST_FLYWEIGHT_TEMPL_ARGS(1) + >, + T2) + +BOOST_FLYWEIGHT_COMPLETE_COMP_OPS( + typename T1 BOOST_PP_COMMA() + typename T2 BOOST_PP_COMMA() + BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2), + T1, + flyweight< + T2 BOOST_PP_COMMA() BOOST_FLYWEIGHT_TEMPL_ARGS(2) + >) +#endif /* !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) */ + +/* specialized algorithms */ + +template +void swap( + flyweight& x, + flyweight& y) +{ + x.swap(y); +} + +template< + BOOST_TEMPLATED_STREAM_ARGS(ElemType,Traits) + BOOST_TEMPLATED_STREAM_COMMA + typename T,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(_) +> +BOOST_TEMPLATED_STREAM(ostream,ElemType,Traits)& operator<<( + BOOST_TEMPLATED_STREAM(ostream,ElemType,Traits)& out, + const flyweight& x) +{ + return out< +BOOST_TEMPLATED_STREAM(istream,ElemType,Traits)& operator>>( + BOOST_TEMPLATED_STREAM(istream,ElemType,Traits)& in, + flyweight& x) +{ + typedef typename flyweight< + T,BOOST_FLYWEIGHT_TEMPL_ARGS(_) + >::value_type value_type; + + /* value_type need not be default ctble but must be copy ctble */ + value_type t(x.get()); + in>>t; + x=t; + return in; +} + +} /* namespace flyweights */ + +} /* namespace boost */ + +#undef BOOST_FLYWEIGHT_COMPLETE_COMP_OPS +#undef BOOST_FLYWEIGHT_TEMPL_ARGS +#undef BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS + +#if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1400)) +#pragma warning(pop) +#endif + +#endif diff --git a/include/boost/flyweight/flyweight_fwd.hpp b/include/boost/flyweight/flyweight_fwd.hpp new file mode 100644 index 0000000..6295a8d --- /dev/null +++ b/include/boost/flyweight/flyweight_fwd.hpp @@ -0,0 +1,166 @@ +/* Copyright 2006-2008 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_FLYWEIGHT_FWD_HPP +#define BOOST_FLYWEIGHT_FLYWEIGHT_FWD_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include + +namespace boost{ + +namespace flyweights{ + +template< + typename T, + typename Arg1=parameter::void_, + typename Arg2=parameter::void_, + typename Arg3=parameter::void_, + typename Arg4=parameter::void_, + typename Arg5=parameter::void_ +> +class flyweight; + +#define BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(n) \ +typename Arg##n##1,typename Arg##n##2,typename Arg##n##3, \ +typename Arg##n##4,typename Arg##n##5 +#define BOOST_FLYWEIGHT_TEMPL_ARGS(n) \ +Arg##n##1,Arg##n##2,Arg##n##3,Arg##n##4,Arg##n##5 + +template< + typename T1,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1), + typename T2,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2) +> +bool operator==( + const flyweight& x, + const flyweight& y); + +template< + typename T1,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1), + typename T2,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2) +> +bool operator<( + const flyweight& x, + const flyweight& y); + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) +template< + typename T1,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1), + typename T2 +> +bool operator==( + const flyweight& x,const T2& y); + +template< + typename T1, + typename T2,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2) +> +bool operator==( + const T1& x,const flyweight& y); + +template< + typename T1,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1), + typename T2 +> +bool operator<( + const flyweight& x,const T2& y); + +template< + typename T1, + typename T2,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2) +> +bool operator<( + const T1& x,const flyweight& y); +#endif /* !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) */ + +#define BOOST_FLYWEIGHT_COMPLETE_COMP_OPS_DECL(t,a1,a2) \ +template \ +inline bool operator!=(const a1& x,const a2& y); \ + \ +template \ +inline bool operator>(const a1& x,const a2& y); \ + \ +template \ +inline bool operator>=(const a1& x,const a2& y); \ + \ +template \ +inline bool operator<=(const a1& x,const a2& y); \ + +BOOST_FLYWEIGHT_COMPLETE_COMP_OPS_DECL( + typename T1 BOOST_PP_COMMA() + BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1) BOOST_PP_COMMA() + typename T2 BOOST_PP_COMMA() + BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2), + flyweight< + T1 BOOST_PP_COMMA() BOOST_FLYWEIGHT_TEMPL_ARGS(1) + >, + flyweight< + T2 BOOST_PP_COMMA() BOOST_FLYWEIGHT_TEMPL_ARGS(2) + >) + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) +BOOST_FLYWEIGHT_COMPLETE_COMP_OPS_DECL( + typename T1 BOOST_PP_COMMA() + BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1) BOOST_PP_COMMA() + typename T2, + flyweight< + T1 BOOST_PP_COMMA() BOOST_FLYWEIGHT_TEMPL_ARGS(1) + >, + T2) + +BOOST_FLYWEIGHT_COMPLETE_COMP_OPS_DECL( + typename T1 BOOST_PP_COMMA() + typename T2 BOOST_PP_COMMA() + BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2), + T1, + flyweight< + T2 BOOST_PP_COMMA() BOOST_FLYWEIGHT_TEMPL_ARGS(2) + >) +#endif /* !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) */ + +template +inline void swap( + flyweight& x, + flyweight& y); + +template< + BOOST_TEMPLATED_STREAM_ARGS(ElemType,Traits) + BOOST_TEMPLATED_STREAM_COMMA + typename T,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(_) +> +inline BOOST_TEMPLATED_STREAM(ostream,ElemType,Traits)& operator<<( + BOOST_TEMPLATED_STREAM(ostream,ElemType,Traits)& out, + const flyweight& x); + +template< + BOOST_TEMPLATED_STREAM_ARGS(ElemType,Traits) + BOOST_TEMPLATED_STREAM_COMMA + typename T,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(_) +> +inline BOOST_TEMPLATED_STREAM(istream,ElemType,Traits)& operator>>( + BOOST_TEMPLATED_STREAM(istream,ElemType,Traits)& in, + flyweight& x); + +} /* namespace flyweights */ + +using flyweights::flyweight; + +} /* namespace boost */ + +#undef BOOST_FLYWEIGHT_COMPLETE_COMP_OPS_DECL +#undef BOOST_FLYWEIGHT_TEMPL_ARGS +#undef BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS + +#endif diff --git a/include/boost/flyweight/hashed_factory.hpp b/include/boost/flyweight/hashed_factory.hpp new file mode 100644 index 0000000..70cada7 --- /dev/null +++ b/include/boost/flyweight/hashed_factory.hpp @@ -0,0 +1,128 @@ +/* Copyright 2006-2008 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_HASHED_FACTORY_HPP +#define BOOST_FLYWEIGHT_HASHED_FACTORY_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include +#include + +/* Flyweight factory based on a hashed container implemented + * with Boost.MultiIndex. + */ + +namespace boost{ + +namespace flyweights{ + +template< + typename Entry,typename Key, + typename Hash,typename Pred,typename Allocator +> +class hashed_factory_class:public factory_marker +{ + struct index_list: + boost::mpl::vector1< + multi_index::hashed_unique< + multi_index::identity, + typename boost::mpl::if_< + mpl::is_na, + hash, + Hash + >::type, + typename boost::mpl::if_< + mpl::is_na, + std::equal_to, + Pred + >::type + > + > + {}; + + typedef multi_index::multi_index_container< + Entry, + index_list, + typename boost::mpl::if_< + mpl::is_na, + std::allocator, + Allocator + >::type + > container_type; + +public: + typedef const Entry* handle_type; + + handle_type insert(const Entry& x) + { + return &*cont.insert(x).first; + } + + void erase(handle_type h) + { + cont.erase(cont.iterator_to(*h)); + } + + static const Entry& entry(handle_type h){return *h;} + +private: + container_type cont; + +public: + typedef hashed_factory_class type; + BOOST_MPL_AUX_LAMBDA_SUPPORT( + 5,hashed_factory_class,(Entry,Key,Hash,Pred,Allocator)) +}; + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) +/* This is preferred to deriving from factory_marker since checking for + * derivation forces the instantiation of the specifier, which is not + * needed when the specifier is a placeholder expression. + */ + +template< + typename Entry,typename Key, + typename Hash,typename Pred,typename Allocator +> +struct is_factory >: + boost::mpl::true_{}; +#endif + +/* hashed_factory_class specifier */ + +template< + typename Hash,typename Pred,typename Allocator + BOOST_FLYWEIGHT_NOT_A_PLACEHOLDER_EXPRESSION_DEF +> +struct hashed_factory:factory_marker +{ + template + struct apply: + mpl::apply2< + hashed_factory_class< + boost::mpl::_1,boost::mpl::_2,Hash,Pred,Allocator + >, + Entry,Key + > + {}; +}; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/hashed_factory_fwd.hpp b/include/boost/flyweight/hashed_factory_fwd.hpp new file mode 100644 index 0000000..1da6b21 --- /dev/null +++ b/include/boost/flyweight/hashed_factory_fwd.hpp @@ -0,0 +1,40 @@ +/* Copyright 2006-2008 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_HASHED_FACTORY_FWD_HPP +#define BOOST_FLYWEIGHT_HASHED_FACTORY_FWD_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include + +namespace boost{ + +namespace flyweights{ + +template< + typename Entry,typename Key, + typename Hash=mpl::na,typename Pred=mpl::na,typename Allocator=mpl::na +> +class hashed_factory_class; + +template< + typename Hash=mpl::na,typename Pred=mpl::na,typename Allocator=mpl::na + BOOST_FLYWEIGHT_NOT_A_PLACEHOLDER_EXPRESSION +> +struct hashed_factory; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/holder_tag.hpp b/include/boost/flyweight/holder_tag.hpp new file mode 100644 index 0000000..745f132 --- /dev/null +++ b/include/boost/flyweight/holder_tag.hpp @@ -0,0 +1,44 @@ +/* Copyright 2006-2008 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_HOLDER_TAG_HPP +#define BOOST_FLYWEIGHT_HOLDER_TAG_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include + +namespace boost{ + +namespace flyweights{ + +/* Three ways to indicate that a given class T is a holder specifier: + * 1. Make it derived from holder_marker. + * 2. Specialize is_holder to evaluate to boost::mpl::true_. + * 3. Pass it as holder when defining a flyweight type. + */ + +struct holder_marker{}; + +template +struct is_holder:is_base_and_derived +{}; + +template +struct holder:parameter::template_keyword,T> +{}; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/intermodule_holder.hpp b/include/boost/flyweight/intermodule_holder.hpp new file mode 100644 index 0000000..46d4870 --- /dev/null +++ b/include/boost/flyweight/intermodule_holder.hpp @@ -0,0 +1,202 @@ +/* Copyright 2006-2008 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_INTERMODULE_HOLDER_HPP +#define BOOST_FLYWEIGHT_INTERMODULE_HOLDER_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* intermodule_holder_class guarantees a unique instance across all dynamic + * modules of a program. + */ + +namespace boost{ + +namespace flyweights{ + +template +struct intermodule_holder_class:holder_marker +{ + static C& get() + { + static instantiator instance; + return instance.get(); + } + +private: + struct instantiator + { + instantiator(): + mutex(interprocess::open_or_create,compute_mutex_name()), + seg(interprocess::open_or_create,compute_segment_name(),16384), + ppref(0), + pc(0) + { + /* Instance creation is done according to a two-phase protocol so + * that we call "new" in an unlocked situation, thus minimizing the + * chance of leaving dangling locks due to catastrophic failure. + */ + + { + interprocess::scoped_lock lock(mutex); + ppref=seg.find_or_construct( + typeid(C).name())((referenced_instance*)0); + if(*ppref){ + /* As in some OSes Boost.Interprocess memory segments can outlive + * their associated processes, there is a possibility that we + * retrieve a dangling pointer (coming from a previous aborted run, + * for instance). Try to protect against this by checking that + * the contents of the pointed object are consistent. + */ + if(std::strcmp(segment_name,(*ppref)->segment_name)!=0){ + *ppref=0; /* dangling pointer! */ + } + else ++((*ppref)->ref); + } + } + if(!*ppref){ + std::auto_ptr apc( + new referenced_instance(segment_name)); + interprocess::scoped_lock lock(mutex); + ppref=seg.find_or_construct( + typeid(C).name())((referenced_instance*)0); + if(!*ppref)*ppref=apc.release(); + ++((*ppref)->ref); + } + pc=&(*ppref)->c; + } + + ~instantiator() + { + /* As in construction time, actual deletion is performed outside the + * lock to avoid leaving the lock dangling in case of crash. + */ + + referenced_instance* pref=0; + { + interprocess::scoped_lock lock(mutex); + if(--((*ppref)->ref)==0){ + pref=*ppref; + *ppref=0; + } + } + if(pref)delete pref; + } + + C& get()const{return *pc;} + + private: + /* Although mutex and seg are system-wide, their names intend to + * make them specific for the current process and type, hence their + * containing process id and type id info. + */ + + char mutex_name[128]; + char segment_name[128]; + + const char* compute_mutex_name() + { + std::sprintf( + mutex_name, + "boost_flyweight_intermodule_holder_mutex_" + "%ld_%u_%u_%u_%u", + (long)detail::process_id(), + (unsigned)compute_hash(typeid(C).name(),0), + (unsigned)compute_hash(typeid(C).name(),1), + (unsigned)compute_hash(typeid(C).name(),2), + (unsigned)compute_hash(typeid(C).name(),3)); + + return mutex_name; + } + + const char* compute_segment_name() + { + std::sprintf( + segment_name, + "boost_flyweight_intermodule_holder_segment_" + "%ld_%u_%u_%u_%u", + (long)detail::process_id(), + (unsigned)compute_hash(typeid(C).name(),0), + (unsigned)compute_hash(typeid(C).name(),1), + (unsigned)compute_hash(typeid(C).name(),2), + (unsigned)compute_hash(typeid(C).name(),3)); + + return segment_name; + } + + static std::size_t compute_hash(const char* str,std::size_t off) + { + std::size_t len=std::strlen(str); + if(off>len)off=len; + return hash_range(str+off,str+len); + } + + interprocess::named_mutex mutex; + interprocess::managed_shared_memory seg; + struct referenced_instance + { + referenced_instance(const char* segment_name_):ref(0) + { + strcpy(segment_name,segment_name_); + } + + ~referenced_instance(){segment_name[0]='\0';} + + char segment_name[128]; /* used to detect dangling pointers */ + mutable long ref; + C c; + }** ppref; + C* pc; + }; + +public: + typedef intermodule_holder_class type; + BOOST_MPL_AUX_LAMBDA_SUPPORT(1,intermodule_holder_class,(C)) +}; + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) +/* This is preferred to deriving from holder_marker since checking for + * derivation forces the instantiation of the specifier, which is not + * needed when the specifier is a placeholder expression. + */ + +template +struct is_holder >:boost::mpl::true_{}; +#endif + +/* intermodule_holder_class specifier */ + +struct intermodule_holder:holder_marker +{ + template + struct apply + { + typedef intermodule_holder_class type; + }; +}; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/intermodule_holder_fwd.hpp b/include/boost/flyweight/intermodule_holder_fwd.hpp new file mode 100644 index 0000000..8acc0ce --- /dev/null +++ b/include/boost/flyweight/intermodule_holder_fwd.hpp @@ -0,0 +1,29 @@ +/* Copyright 2006-2008 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_INTERMODULE_HOLDER_FWD_HPP +#define BOOST_FLYWEIGHT_INTERMODULE_HOLDER_FWD_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +namespace boost{ + +namespace flyweights{ + +template +struct intermodule_holder_class; + +struct intermodule_holder; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/key_value.hpp b/include/boost/flyweight/key_value.hpp new file mode 100644 index 0000000..5ac1c0d --- /dev/null +++ b/include/boost/flyweight/key_value.hpp @@ -0,0 +1,238 @@ +/* Copyright 2006-2008 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_KEY_VALUE_HPP +#define BOOST_FLYWEIGHT_KEY_VALUE_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +/* key-value policy: flywewight lookup is based on Key, which also serves + * to construct Value only when needed (new factory entry). key_value is + * used to avoid the construction of temporary values when such construction + * is expensive. + * Optionally, KeyFromValue extracts the key from a value, which + * is needed in expressions like this: + * + * typedef flyweight > fw_t; + * fw_t fw; + * Value v; + * fw=v; // no key explicitly given + * + * If no KeyFromValue is provided, this latter expression fails to compile. + */ + +namespace boost{ + +namespace flyweights{ + +namespace detail{ + +template +struct optimized_key_value:value_marker +{ + typedef Key key_type; + typedef Value value_type; + + class rep_type + { + public: + /* template ctors */ + +#define BOOST_FLYWEIGHT_PERFECT_FWD_NAME explicit rep_type +#define BOOST_FLYWEIGHT_PERFECT_FWD_BODY(n) \ + :value_ptr(0) \ +{ \ + new(spc_ptr())key_type(BOOST_PP_ENUM_PARAMS(n,t)); \ +} +#include + + rep_type(const value_type& x):value_ptr(&x){} + + rep_type(const rep_type& x):value_ptr(x.value_ptr) + { + if(!x.value_ptr)new(key_ptr())key_type(*x.key_ptr()); + } + + ~rep_type() + { + if(!value_ptr) key_ptr()->~key_type(); + else if(value_cted())value_ptr->~value_type(); + } + + operator const key_type&()const + { + if(value_ptr)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(spc_ptr()); + } + + private: + friend struct optimized_key_value; + + void* spc_ptr()const{return static_cast(&spc);} + bool value_cted()const{return value_ptr==spc_ptr();} + + key_type* key_ptr()const + { + return static_cast(static_cast(&spc)); + } + + static const key_type& key_from_value(const value_type& x) + { + KeyFromValue k; + return k(x); + } + + void construct_value()const + { + if(!value_cted()){ + /* value_ptr must be ==0, oherwise copy_value would have been called */ + + key_type k(*key_ptr()); + key_ptr()->~key_type(); + value_ptr= /* guarantees key won't be re-dted at ~rep_type if the */ + static_cast(spc_ptr())+1; /* next statement throws */ + value_ptr=new(spc_ptr())value_type(k); + } + } + + void copy_value()const + { + if(!value_cted())value_ptr=new(spc_ptr())value_type(*value_ptr); + } + + mutable typename boost::aligned_storage< + (sizeof(key_type)>sizeof(value_type))? + sizeof(key_type):sizeof(value_type), + (boost::alignment_of::value > + boost::alignment_of::value)? + boost::alignment_of::value: + boost::alignment_of::value + >::type spc; + mutable const value_type* value_ptr; + }; + + static void construct_value(const rep_type& r) + { + r.construct_value(); + } + + static void copy_value(const rep_type& r) + { + r.copy_value(); + } +}; + +template +struct regular_key_value:value_marker +{ + typedef Key key_type; + typedef Value value_type; + + class rep_type + { + public: + /* template ctors */ + +#define BOOST_FLYWEIGHT_PERFECT_FWD_NAME explicit rep_type +#define BOOST_FLYWEIGHT_PERFECT_FWD_BODY(n) \ + :key(BOOST_PP_ENUM_PARAMS(n,t)),value_ptr(0){} +#include + + rep_type(const value_type& x):key(no_key_from_value_failure()){} + + rep_type(const rep_type& x):key(x.key),value_ptr(0){} + + ~rep_type() + { + if(value_ptr)value_ptr->~value_type(); + } + + operator const key_type&()const{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(spc_ptr()); + } + + private: + friend struct regular_key_value; + + void* spc_ptr()const{return static_cast(&spc);} + + struct no_key_from_value_failure + { + BOOST_MPL_ASSERT_MSG( + false, + NO_KEY_FROM_VALUE_CONVERSION_PROVIDED, + (key_type,value_type)); + + operator const key_type&()const; + }; + + void construct_value()const + { + if(!value_ptr)value_ptr=new(spc_ptr())value_type(key); + } + + key_type key; + mutable typename boost::aligned_storage< + sizeof(value_type), + boost::alignment_of::value + >::type spc; + mutable const value_type* value_ptr; + }; + + static void construct_value(const rep_type& r) + { + r.construct_value(); + } + + static void copy_value(const rep_type&){} +}; + +} /* namespace flyweights::detail */ + +template +struct key_value: + mpl::if_< + is_same, + detail::regular_key_value, + detail::optimized_key_value + >::type +{}; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/key_value_fwd.hpp b/include/boost/flyweight/key_value_fwd.hpp new file mode 100644 index 0000000..d20d71e --- /dev/null +++ b/include/boost/flyweight/key_value_fwd.hpp @@ -0,0 +1,29 @@ +/* Copyright 2006-2008 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_KEY_VALUE_FWD_HPP +#define BOOST_FLYWEIGHT_KEY_VALUE_FWD_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +namespace boost{ + +namespace flyweights{ + +struct no_key_from_value; + +template +struct key_value; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/locking_tag.hpp b/include/boost/flyweight/locking_tag.hpp new file mode 100644 index 0000000..c467a4a --- /dev/null +++ b/include/boost/flyweight/locking_tag.hpp @@ -0,0 +1,44 @@ +/* Copyright 2006-2008 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_LOCKING_TAG_HPP +#define BOOST_FLYWEIGHT_LOCKING_TAG_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include + +namespace boost{ + +namespace flyweights{ + +/* Three ways to indicate that a given class T is a locking policy: + * 1. Make it derived from locking_marker. + * 2. Specialize is_locking to evaluate to boost::mpl::true_. + * 3. Pass it as locking when defining a flyweight type. + */ + +struct locking_marker{}; + +template +struct is_locking:is_base_and_derived +{}; + +template +struct locking:parameter::template_keyword,T> +{}; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/no_locking.hpp b/include/boost/flyweight/no_locking.hpp new file mode 100644 index 0000000..fa0031a --- /dev/null +++ b/include/boost/flyweight/no_locking.hpp @@ -0,0 +1,36 @@ +/* Copyright 2006-2008 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_NO_LOCKING_HPP +#define BOOST_FLYWEIGHT_NO_LOCKING_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include + +/* null locking policy */ + +namespace boost{ + +namespace flyweights{ + +struct no_locking:locking_marker +{ + struct mutex_type{}; + typedef mutex_type lock_type; +}; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/no_locking_fwd.hpp b/include/boost/flyweight/no_locking_fwd.hpp new file mode 100644 index 0000000..95177e9 --- /dev/null +++ b/include/boost/flyweight/no_locking_fwd.hpp @@ -0,0 +1,26 @@ +/* Copyright 2006-2008 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_NO_LOCKING_FWD_HPP +#define BOOST_FLYWEIGHT_NO_LOCKING_FWD_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +namespace boost{ + +namespace flyweights{ + +struct no_locking; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/no_tracking.hpp b/include/boost/flyweight/no_tracking.hpp new file mode 100644 index 0000000..1433d6d --- /dev/null +++ b/include/boost/flyweight/no_tracking.hpp @@ -0,0 +1,46 @@ +/* Copyright 2006-2008 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_NO_TRACKING_HPP +#define BOOST_FLYWEIGHT_NO_TRACKING_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include + +/* Null tracking policy: elements are never erased from the factory. + */ + +namespace boost{ + +namespace flyweights{ + +struct no_tracking:tracking_marker +{ + struct entry_type + { + template + struct apply{typedef Value type;}; + }; + + struct handle_type + { + template + struct apply{typedef Handle type;}; + }; +}; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/no_tracking_fwd.hpp b/include/boost/flyweight/no_tracking_fwd.hpp new file mode 100644 index 0000000..dd6b446 --- /dev/null +++ b/include/boost/flyweight/no_tracking_fwd.hpp @@ -0,0 +1,26 @@ +/* Copyright 2006-2008 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_NO_TRACKING_FWD_HPP +#define BOOST_FLYWEIGHT_NO_TRACKING_FWD_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +namespace boost{ + +namespace flyweights{ + +struct no_tracking; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/refcounted.hpp b/include/boost/flyweight/refcounted.hpp new file mode 100644 index 0000000..5694a60 --- /dev/null +++ b/include/boost/flyweight/refcounted.hpp @@ -0,0 +1,152 @@ +/* Copyright 2006-2008 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_REFCOUNTED_HPP +#define BOOST_FLYWEIGHT_REFCOUNTED_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include +#include + +/* Refcounting tracking policy: values have an embedded ref count, + * when this goes down to zero the element is erased from the + * factory. + */ + +namespace boost{ + +namespace flyweights{ + +namespace detail{ + +template +class refcounted_value +{ +public: + explicit refcounted_value(const Value& x_): + x(x_),ref(0) + {} + + refcounted_value(const refcounted_value& r): + x(r.x),ref(0) + {} + + ~refcounted_value() + { + /* count()!=0 most likely indicates that the flyweight factory + * has been destructed before some of the flyweight objects using + * it. Check for static initialization order problems with this + * flyweight type. + */ + + BOOST_ASSERT(count()==0); + } + + refcounted_value& operator=(const refcounted_value& r) + { + x=r.x; + return *this; + } + + operator const Value&()const{return x;} + operator const Key&()const{return x;} + +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) +private: + template friend class refcounted_handle; +#endif + + long count()const{return ref;} + void add_ref()const{++ref;} + bool release()const{return (--ref==0);} + +private: + Value x; + mutable boost::detail::atomic_count ref; +}; + +template +class refcounted_handle +{ +public: + explicit refcounted_handle(const Handle& h_):h(h_) + { + TrackingHelper::entry(*this).add_ref(); + } + + refcounted_handle(const refcounted_handle& x):h(x.h) + { + TrackingHelper::entry(*this).add_ref(); + } + + refcounted_handle& operator=(refcounted_handle x) + { + swap(*this,x); + return *this; + } + + ~refcounted_handle() + { + if(TrackingHelper::entry(*this).release()){ + TrackingHelper::erase(*this,check_erase); + } + } + + operator const Handle&()const{return h;} + + friend void swap(refcounted_handle& x, refcounted_handle& y) + { + boost::swap(x.h,y.h); + } + +private: + static bool check_erase(const refcounted_handle& x) + { + return TrackingHelper::entry(x).count()==0; + } + + Handle h; +}; + +} /* namespace flyweights::detail */ + +struct refcounted:tracking_marker +{ + struct entry_type + { + template + struct apply + { + typedef detail::refcounted_value type; + }; + }; + + struct handle_type + { + template + struct apply + { + typedef detail::refcounted_handle type; + }; + }; +}; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/refcounted_fwd.hpp b/include/boost/flyweight/refcounted_fwd.hpp new file mode 100644 index 0000000..cb0e727 --- /dev/null +++ b/include/boost/flyweight/refcounted_fwd.hpp @@ -0,0 +1,26 @@ +/* Copyright 2006-2008 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_REFCOUNTED_FWD_HPP +#define BOOST_FLYWEIGHT_REFCOUNTED_FWD_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +namespace boost{ + +namespace flyweights{ + +struct refcounted; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/set_factory.hpp b/include/boost/flyweight/set_factory.hpp new file mode 100644 index 0000000..e4ca0ae --- /dev/null +++ b/include/boost/flyweight/set_factory.hpp @@ -0,0 +1,96 @@ +/* Copyright 2006-2008 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_SET_FACTORY_HPP +#define BOOST_FLYWEIGHT_SET_FACTORY_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include +#include + +/* Particularization of assoc_container_factory_class using a set. + */ + +namespace boost{ + +namespace flyweights{ + +template< + typename Entry,typename Key, + typename Compare,typename Allocator +> +class set_factory_class: + public assoc_container_factory_class< + std::set< + Entry, + typename boost::mpl::if_< + mpl::is_na, + std::less, + Compare + >::type, + typename boost::mpl::if_< + mpl::is_na, + std::allocator, + Allocator + >::type + > + > +{ +public: + typedef set_factory_class type; + BOOST_MPL_AUX_LAMBDA_SUPPORT( + 4,set_factory_class,(Entry,Key,Compare,Allocator)) +}; + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) +/* This is preferred to deriving from factory_marker since checking for + * derivation forces the instantiation of the specifier, which is not + * needed when the specifier is a placeholder expression. + */ + +template< + typename Entry,typename Key, + typename Compare,typename Allocator +> +struct is_factory >: + boost::mpl::true_{}; +#endif + +/* set_factory_class specifier */ + +template< + typename Compare,typename Allocator + BOOST_FLYWEIGHT_NOT_A_PLACEHOLDER_EXPRESSION_DEF +> +struct set_factory:factory_marker +{ + template + struct apply: + mpl::apply2< + set_factory_class< + boost::mpl::_1,boost::mpl::_2,Compare,Allocator + >, + Entry,Key + > + {}; +}; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/set_factory_fwd.hpp b/include/boost/flyweight/set_factory_fwd.hpp new file mode 100644 index 0000000..07cd0ea --- /dev/null +++ b/include/boost/flyweight/set_factory_fwd.hpp @@ -0,0 +1,40 @@ +/* Copyright 2006-2008 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_SET_FACTORY_FWD_HPP +#define BOOST_FLYWEIGHT_SET_FACTORY_FWD_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include + +namespace boost{ + +namespace flyweights{ + +template< + typename Entry,typename Key, + typename Compare=mpl::na,typename Allocator=mpl::na +> +class set_factory_class; + +template< + typename Compare=mpl::na,typename Allocator=mpl::na + BOOST_FLYWEIGHT_NOT_A_PLACEHOLDER_EXPRESSION +> +struct set_factory; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/simple_locking.hpp b/include/boost/flyweight/simple_locking.hpp new file mode 100644 index 0000000..5034133 --- /dev/null +++ b/include/boost/flyweight/simple_locking.hpp @@ -0,0 +1,37 @@ +/* Copyright 2006-2008 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_SIMPLE_LOCKING_HPP +#define BOOST_FLYWEIGHT_SIMPLE_LOCKING_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include + +/* simple locking policy based on native recursive mutexes */ + +namespace boost{ + +namespace flyweights{ + +struct simple_locking:locking_marker +{ + typedef detail::recursive_lightweight_mutex mutex_type; + typedef mutex_type::scoped_lock lock_type; +}; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/simple_locking_fwd.hpp b/include/boost/flyweight/simple_locking_fwd.hpp new file mode 100644 index 0000000..c810860 --- /dev/null +++ b/include/boost/flyweight/simple_locking_fwd.hpp @@ -0,0 +1,26 @@ +/* Copyright 2006-2008 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_SIMPLE_LOCKING_FWD_HPP +#define BOOST_FLYWEIGHT_SIMPLE_LOCKING_FWD_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +namespace boost{ + +namespace flyweights{ + +struct simple_locking; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/static_holder.hpp b/include/boost/flyweight/static_holder.hpp new file mode 100644 index 0000000..67fa70a --- /dev/null +++ b/include/boost/flyweight/static_holder.hpp @@ -0,0 +1,66 @@ +/* Copyright 2006-2008 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_STATIC_HOLDER_HPP +#define BOOST_FLYWEIGHT_STATIC_HOLDER_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include + +/* Simplest holder storing the T object as a local static variable. + */ + +namespace boost{ + +namespace flyweights{ + +template +struct static_holder_class:holder_marker +{ + static C& get() + { + static C c; + return c; + } + + typedef static_holder_class type; + BOOST_MPL_AUX_LAMBDA_SUPPORT(1,static_holder_class,(C)) +}; + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) +/* This is preferred to deriving from holder_marker since checking for + * derivation forces the instantiation of the specifier, which is not + * needed when the specifier is a placeholder expression. + */ + +template +struct is_holder >:boost::mpl::true_{}; +#endif + +/* static_holder_class specifier */ + +struct static_holder:holder_marker +{ + template + struct apply + { + typedef static_holder_class type; + }; +}; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/static_holder_fwd.hpp b/include/boost/flyweight/static_holder_fwd.hpp new file mode 100644 index 0000000..5f6f437 --- /dev/null +++ b/include/boost/flyweight/static_holder_fwd.hpp @@ -0,0 +1,29 @@ +/* Copyright 2006-2008 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_STATIC_HOLDER_FWD_HPP +#define BOOST_FLYWEIGHT_STATIC_HOLDER_FWD_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +namespace boost{ + +namespace flyweights{ + +template +struct static_holder_class; + +struct static_holder; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/tag.hpp b/include/boost/flyweight/tag.hpp new file mode 100644 index 0000000..62efc36 --- /dev/null +++ b/include/boost/flyweight/tag.hpp @@ -0,0 +1,46 @@ +/* Copyright 2006-2008 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_TAG_HPP +#define BOOST_FLYWEIGHT_TAG_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include + +/* A type T can be used as a tag in the specification of a flyweight + * by passing it wrapped in the form tag. + */ + +namespace boost{ + +namespace flyweights{ + +namespace detail{ + +struct tag_marker{}; + +template +struct is_tag:is_base_and_derived +{}; + +} /* namespace flyweights::detail */ + +template +struct tag:parameter::template_keyword,T>,detail::tag_marker +{}; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/flyweight/tracking_tag.hpp b/include/boost/flyweight/tracking_tag.hpp new file mode 100644 index 0000000..efc7bce --- /dev/null +++ b/include/boost/flyweight/tracking_tag.hpp @@ -0,0 +1,44 @@ +/* Copyright 2006-2008 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_TRACKING_TAG_HPP +#define BOOST_FLYWEIGHT_TRACKING_TAG_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include + +namespace boost{ + +namespace flyweights{ + +/* Three ways to indicate that a given class T is a tracking policy: + * 1. Make it derived from tracking_marker. + * 2. Specialize is_tracking to evaluate to boost::mpl::true_. + * 3. Pass it as tracking when defining a flyweight type. + */ + +struct tracking_marker{}; + +template +struct is_tracking:is_base_and_derived +{}; + +template +struct tracking:parameter::template_keyword,T> +{}; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif diff --git a/index.html b/index.html new file mode 100644 index 0000000..1a861cf --- /dev/null +++ b/index.html @@ -0,0 +1,20 @@ + + + + + + +Boost.Flyweight Documentation + + + + +Automatic redirection failed, please go to +doc/index.html + + diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 new file mode 100644 index 0000000..62a5b44 --- /dev/null +++ b/test/Jamfile.v2 @@ -0,0 +1,34 @@ +# Boost.Flyweight tests Jamfile +# +# Copyright 2006-2008 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) +# +# See http://www.boost.org/libs/flyweight for library home page. + +project + : requirements + LINUX:multi + ; + +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_intermod_holder.cpp test_intermod_holder_main.cpp + intermod_holder_dll + : # command line + : # input files + : # requirements + 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_set_factory.cpp test_set_factory_main.cpp ] + ; + +lib intermod_holder_dll : intermod_holder_dll.cpp : + shared + BOOST_FLYWEIGHT_TEST_INTERMOD_HOLDER_DLL_SOURCE=1 ; diff --git a/test/heavy_objects.hpp b/test/heavy_objects.hpp new file mode 100644 index 0000000..8fc10c2 --- /dev/null +++ b/test/heavy_objects.hpp @@ -0,0 +1,87 @@ +/* Boost.Flyweight basic test template. + * + * Copyright 2006-2008 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_TEST_HEAVY_OBJECTS_HPP +#define BOOST_FLYWEIGHT_TEST_HEAVY_OBJECTS_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include +#include +#include + +struct texture +{ + texture(const std::string& str=""):str(str){} + + friend bool operator==( + const texture& x,const texture& y){return x.str==y.str;} + friend bool operator< ( + const texture& x,const texture& y){return x.str< y.str;} + friend bool operator!=( + const texture& x,const texture& y){return x.str!=y.str;} + friend bool operator> ( + const texture& x,const texture& y){return x.str> y.str;} + friend bool operator>=( + const texture& x,const texture& y){return x.str>=y.str;} + friend bool operator<=( + const texture& x,const texture& y){return x.str<=y.str;} + + friend std::ostream& operator<<(std::ostream& os,const texture& x) + { + return os<>(std::istream& is,texture& x) + { + return is>>x.str; + } + + std::string str; +}; + +struct from_texture_to_string +{ + const std::string& operator()(const texture& x)const{return x.str;} +}; + +struct factorization:private boost::noncopyable +{ + factorization(int n=0):n(n){} + + friend bool operator==( + const factorization& x,const factorization& y){return x.n==y.n;} + friend bool operator< ( + const factorization& x,const factorization& y){return x.n< y.n;} + friend bool operator!=( + const factorization& x,const factorization& y){return x.n!=y.n;} + friend bool operator> ( + const factorization& x,const factorization& y){return x.n> y.n;} + friend bool operator>=( + const factorization& x,const factorization& y){return x.n>=y.n;} + friend bool operator<=( + const factorization& x,const factorization& y){return x.n<=y.n;} + + friend std::ostream& operator<<(std::ostream& os,const factorization& x) + { + return os<>(std::istream& is,factorization& x) + { + return is>>x.n; + } + + int n; +}; + +#endif diff --git a/test/intermod_holder_dll.cpp b/test/intermod_holder_dll.cpp new file mode 100644 index 0000000..098bca3 --- /dev/null +++ b/test/intermod_holder_dll.cpp @@ -0,0 +1,17 @@ +/* Boost.Flyweight test of intermodule_holder. + * + * Copyright 2006-2008 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 "intermod_holder_dll.hpp" + +intermodule_flyweight_string create_intermodule_flyweight_string( + const std::string& str) +{ + return intermodule_flyweight_string(str); +} diff --git a/test/intermod_holder_dll.hpp b/test/intermod_holder_dll.hpp new file mode 100644 index 0000000..b48edc7 --- /dev/null +++ b/test/intermod_holder_dll.hpp @@ -0,0 +1,45 @@ +/* Boost.Flyweight test of intermodule_holder. + * + * Copyright 2006-2008 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_TEST_INTERMOD_HOLDER_DLL_HPP +#define BOOST_FLYWEIGHT_TEST_INTERMOD_HOLDER_DLL_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_DECLSPEC +#ifdef BOOST_FLYWEIGHT_TEST_INTERMOD_HOLDER_DLL_SOURCE +#define BOOST_FLYWEIGHT_DLL_DECL __declspec(dllexport) +#else +#define BOOST_FLYWEIGHT_DLL_DECL __declspec(dllimport) +#endif +#else +#define BOOST_FLYWEIGHT_DLL_DECL +#endif + +typedef boost::flyweights::flyweight< + std::string, + boost::flyweights::intermodule_holder> intermodule_flyweight_string; + +BOOST_FLYWEIGHT_DLL_DECL intermodule_flyweight_string +create_intermodule_flyweight_string(const std::string&); + +#undef BOOST_FLYWEIGHT_DLL_DECL + +#endif diff --git a/test/test_all_main.cpp b/test/test_all_main.cpp new file mode 100644 index 0000000..709a8b3 --- /dev/null +++ b/test/test_all_main.cpp @@ -0,0 +1,36 @@ +/* Boost.Flyweight test suite. + * + * Copyright 2006-2008 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 /* keep it first to prevent nasty warns in MSVC */ +#include +#include "test_assoc_cont_factory.hpp" +#include "test_basic.hpp" +#include "test_custom_factory.hpp" +#include "test_intermod_holder.hpp" +#include "test_init.hpp" +#include "test_multictor.hpp" +#include "test_no_locking.hpp" +#include "test_no_tracking.hpp" +#include "test_set_factory.hpp" + +int main() +{ + test_assoc_container_factory(); + test_basic(); + test_custom_factory(); + test_init(); + test_intermodule_holder(); + test_multictor(); + test_no_locking(); + test_no_tracking(); + test_set_factory(); + + return boost::report_errors(); +} diff --git a/test/test_assoc_cont_fact_main.cpp b/test/test_assoc_cont_fact_main.cpp new file mode 100644 index 0000000..1b3e7b7 --- /dev/null +++ b/test/test_assoc_cont_fact_main.cpp @@ -0,0 +1,18 @@ +/* Boost.Flyweight test of assoc_container_factory. + * + * Copyright 2006-2008 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 +#include "test_assoc_cont_factory.hpp" + +int main() +{ + test_assoc_container_factory(); + return boost::report_errors(); +} diff --git a/test/test_assoc_cont_factory.cpp b/test/test_assoc_cont_factory.cpp new file mode 100644 index 0000000..cac11c9 --- /dev/null +++ b/test/test_assoc_cont_factory.cpp @@ -0,0 +1,68 @@ +/* Boost.Flyweight test of assoc_container_factory. + * + * Copyright 2006-2008 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_assoc_cont_factory.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include +#include +#include "test_basic_template.hpp" + +using namespace boost::flyweights; + +struct reverse_set_specifier +{ + template + struct apply + { + typedef std::set > type; + }; +}; + +struct assoc_container_factory_flyweight_specifier1 +{ + template + struct apply + { + typedef flyweight< + T, + assoc_container_factory + > type; + }; +}; + +struct assoc_container_factory_flyweight_specifier2 +{ + template + struct apply + { + typedef flyweight< + T, + assoc_container_factory_class< + std::set< + boost::mpl::_1, + std::greater, + std::allocator + > + > + > type; + }; +}; + +void test_assoc_container_factory() +{ + test_basic_template(); + test_basic_template(); +} diff --git a/test/test_assoc_cont_factory.hpp b/test/test_assoc_cont_factory.hpp new file mode 100644 index 0000000..e9aa931 --- /dev/null +++ b/test/test_assoc_cont_factory.hpp @@ -0,0 +1,11 @@ +/* Boost.Flyweight test of assoc_container_factory. + * + * Copyright 2006-2008 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_assoc_container_factory(); diff --git a/test/test_basic.cpp b/test/test_basic.cpp new file mode 100644 index 0000000..53285ec --- /dev/null +++ b/test/test_basic.cpp @@ -0,0 +1,68 @@ +/* Boost.Flyweight basic test. + * + * Copyright 2006-2008 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_basic.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include "test_basic_template.hpp" + +using namespace boost::flyweights; + +struct basic_flyweight_specifier1 +{ + template + struct apply + { + typedef flyweight type; + }; +}; + +struct basic_flyweight_specifier2 +{ + template + struct apply + { + typedef flyweight< + T,tag, + static_holder_class, + hashed_factory_class< + boost::mpl::_1,boost::mpl::_2, + boost::hash,std::equal_to, + std::allocator + >, + simple_locking, + refcounted + > type; + }; +}; + +struct basic_flyweight_specifier3 +{ + template + struct apply + { + typedef flyweight< + T, + hashed_factory< + boost::hash,std::equal_to, + std::allocator + >, + tag + > type; + }; +}; + +void test_basic() +{ + test_basic_template(); + test_basic_template(); + test_basic_template(); +} diff --git a/test/test_basic.hpp b/test/test_basic.hpp new file mode 100644 index 0000000..d7d86d5 --- /dev/null +++ b/test/test_basic.hpp @@ -0,0 +1,11 @@ +/* Boost.Flyweight basic test. + * + * Copyright 2006-2008 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_basic(); diff --git a/test/test_basic_main.cpp b/test/test_basic_main.cpp new file mode 100644 index 0000000..b2508d8 --- /dev/null +++ b/test/test_basic_main.cpp @@ -0,0 +1,18 @@ +/* Boost.Flyweight basic test. + * + * Copyright 2006-2008 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 +#include "test_basic.hpp" + +int main() +{ + test_basic(); + return boost::report_errors(); +} diff --git a/test/test_basic_template.hpp b/test/test_basic_template.hpp new file mode 100644 index 0000000..9d57d08 --- /dev/null +++ b/test/test_basic_template.hpp @@ -0,0 +1,232 @@ +/* Boost.Flyweight basic test template. + * + * Copyright 2006-2008 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_TEST_BASIC_TEMPLATE_HPP +#define BOOST_FLYWEIGHT_TEST_BASIC_TEMPLATE_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include +#include "heavy_objects.hpp" + +#define LENGTHOF(array) (sizeof(array)/sizeof((array)[0])) + +template +void test_basic_template( + ForwardIterator first,ForwardIterator last + BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Flyweight)) +{ + typedef typename Flyweight::value_type value_type; + + ForwardIterator it; + + for(it=first;it!=last;++it){ + /* construct/copy/destroy */ + + Flyweight f1(*it); + Flyweight f2; + Flyweight c1(f1); + Flyweight c2(static_cast(f2)); + value_type v1(*it); + boost::value_initialized v2; + BOOST_TEST(f1.get_key()==*it); + BOOST_TEST((f1==f2)==(f1.get()==v2.data())); + BOOST_TEST(f1==c1); + BOOST_TEST(f2==c2); + + f1=f1; + BOOST_TEST(f1==f1); + + c1=f2; + BOOST_TEST(c1==f2); + + c1=f1; + BOOST_TEST(c1==f1); + + /* convertibility to underlying type */ + + BOOST_TEST(f1.get()==v1); + + /* identity of reference */ + + BOOST_TEST(&f1.get()==&c1.get()); + + /* modifiers */ + + f1.swap(f1); + BOOST_TEST(f1==c1); + + f1.swap(f2); + BOOST_TEST(f1==c2); + BOOST_TEST(f2==c1); + + boost::flyweights::swap(f1,f2); + BOOST_TEST(f1==c1); + BOOST_TEST(f2==c2); + + /* specialized algorithms */ + + std::ostringstream oss1; + oss1< +void test_basic_with_assign_template( + ForwardIterator first,ForwardIterator last + BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Flyweight)) +{ + typedef typename Flyweight::value_type value_type; + + ForwardIterator it; + + test_basic_template(first,last); + + for(it=first;it!=last;++it){ + /* value construction */ + + value_type v(*it); + Flyweight f1(v); + Flyweight f2(f1.get()); + BOOST_TEST(f1.get()==v); + BOOST_TEST(f2.get()==v); + BOOST_TEST(f1==f2); + + /* value assignment */ + + Flyweight f3,f4; + f3=v; + f4=f1.get(); + BOOST_TEST(f2.get()==v); + BOOST_TEST(f3.get()==v); + BOOST_TEST(f2==f3); + + /* specialized algorithms */ + + std::ostringstream oss1; + oss1<>f5; + BOOST_TEST(f5==f1); + } +} + +template< + typename Flyweight1,typename Flyweight2, + typename ForwardIterator1,typename ForwardIterator2 +> +void test_basic_comparison_template( + ForwardIterator1 first1,ForwardIterator1 last1, + ForwardIterator2 first2 + BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Flyweight1) + BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Flyweight2)) +{ + typedef typename Flyweight1::value_type value_type1; + typedef typename Flyweight2::value_type value_type2; + + for(;first1!=last1;++first1,++first2){ + value_type1 v1=value_type1(*first1); + value_type2 v2=value_type2(*first2); + Flyweight1 f1(v1); + Flyweight2 f2(v2); + + BOOST_TEST((f1==f2)==(f1.get()==v2)); + BOOST_TEST((f1< f2)==(f1.get()< v2)); + BOOST_TEST((f1!=f2)==(f1.get()!=v2)); + BOOST_TEST((f1> f2)==(f1.get()> v2)); + BOOST_TEST((f1>=f2)==(f1.get()>=v2)); + BOOST_TEST((f1<=f2)==(f1.get()<=v2)); + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) + BOOST_TEST((f1==v2)==(f1.get()==v2)); + BOOST_TEST((f1< v2)==(f1.get()< v2)); + BOOST_TEST((f1!=v2)==(f1.get()!=v2)); + BOOST_TEST((f1> v2)==(f1.get()> v2)); + BOOST_TEST((f1>=v2)==(f1.get()>=v2)); + BOOST_TEST((f1<=v2)==(f1.get()<=v2)); + + BOOST_TEST((v1==f2)==(f1.get()==v2)); + BOOST_TEST((v1< f2)==(f1.get()< v2)); + BOOST_TEST((v1!=f2)==(f1.get()!=v2)); + BOOST_TEST((v1> f2)==(f1.get()> v2)); + BOOST_TEST((v1>=f2)==(f1.get()>=v2)); + BOOST_TEST((v1<=f2)==(f1.get()<=v2)); +#endif + + } +} + +template +void test_basic_template(BOOST_EXPLICIT_TEMPLATE_TYPE(FlyweightSpecifier)) +{ + typedef typename boost::mpl::apply1< + FlyweightSpecifier,int + >::type int_flyweight; + + typedef typename boost::mpl::apply1< + FlyweightSpecifier,std::string + >::type string_flyweight; + + typedef typename boost::mpl::apply1< + FlyweightSpecifier,char + >::type char_flyweight; + + typedef typename boost::mpl::apply1< + FlyweightSpecifier, + boost::flyweights::key_value + >::type texture_flyweight; + + typedef typename boost::mpl::apply1< + FlyweightSpecifier, + boost::flyweights::key_value + >::type factorization_flyweight; + + int ints[]={0,1,1,0,1,2,3,4,3,4,0,0}; + test_basic_with_assign_template( + &ints[0],&ints[0]+LENGTHOF(ints)); + + const char* words[]={"hello","boost","flyweight","boost","bye","c++","c++"}; + test_basic_with_assign_template( + &words[0],&words[0]+LENGTHOF(words)); + + const char* textures[]={"wood","grass","sand","granite","terracotta"}; + test_basic_with_assign_template( + &textures[0],&textures[0]+LENGTHOF(textures)); + + int factorizations[]={1098,102387,90846,2223978}; + test_basic_template( + &factorizations[0],&factorizations[0]+LENGTHOF(factorizations)); + + char chars[]={0,2,4,5,1,1,1,3,4,1,1,0}; + test_basic_comparison_template( + &ints[0],&ints[0]+LENGTHOF(ints),&chars[0]); + + test_basic_comparison_template( + &words[0],&words[0]+LENGTHOF(words)-1,&words[1]); + + test_basic_comparison_template( + &textures[0],&textures[0]+LENGTHOF(textures)-1,&textures[1]); +} + +#undef LENGTHOF + +#endif diff --git a/test/test_custom_factory.cpp b/test/test_custom_factory.cpp new file mode 100644 index 0000000..9fec1b4 --- /dev/null +++ b/test/test_custom_factory.cpp @@ -0,0 +1,111 @@ +/* Boost.Flyweight test of a custom factory. + * + * Copyright 2006-2008 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_custom_factory.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include +#include "test_basic_template.hpp" + +using namespace boost::flyweights; + +/* Info on list-update containers: + * http://gcc.gnu.org/onlinedocs/libstdc++/ext/pb_ds/lu_based_containers.html + */ + +template +class lu_factory_class:public factory_marker +{ + struct entry_type + { + entry_type(const Entry& x_):x(x_),count(0){} + + Entry x; + std::size_t count; + }; + + typedef std::list container_type; + +public: + typedef typename container_type::iterator handle_type; + + handle_type insert(const Entry& x) + { + handle_type h; + for(h=cont.begin();h!=cont.end();++h){ + if(static_cast(h->x)==static_cast(x)){ + if(++(h->count)==10){ + h->count=0; + cont.splice(cont.begin(),cont,h); /* move to front */ + } + return h; + } + } + cont.push_back(entry_type(x)); + h=cont.end(); + --h; + return h; + } + + void erase(handle_type h) + { + cont.erase(h); + } + + const Entry& entry(handle_type h){return h->x;} + +private: + container_type cont; + +public: + typedef lu_factory_class type; + BOOST_MPL_AUX_LAMBDA_SUPPORT(2,lu_factory_class,(Entry,Key)) +}; + +struct lu_factory:factory_marker +{ + template + struct apply + { + typedef lu_factory_class type; + }; +}; + +struct custom_factory_flyweight_specifier1 +{ + template + struct apply + { + typedef flyweight type; + }; +}; + +struct custom_factory_flyweight_specifier2 +{ + template + struct apply + { + typedef flyweight< + T, + lu_factory_class + > type; + }; +}; + +void test_custom_factory() +{ + test_basic_template(); + test_basic_template(); +} diff --git a/test/test_custom_factory.hpp b/test/test_custom_factory.hpp new file mode 100644 index 0000000..5b17deb --- /dev/null +++ b/test/test_custom_factory.hpp @@ -0,0 +1,11 @@ +/* Boost.Flyweight test of a custom factory. + * + * Copyright 2006-2008 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_custom_factory(); diff --git a/test/test_custom_factory_main.cpp b/test/test_custom_factory_main.cpp new file mode 100644 index 0000000..9506703 --- /dev/null +++ b/test/test_custom_factory_main.cpp @@ -0,0 +1,18 @@ +/* Boost.Flyweight test of a custom factory. + * + * Copyright 2006-2008 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 +#include "test_custom_factory.hpp" + +int main() +{ + test_custom_factory(); + return boost::report_errors(); +} diff --git a/test/test_init.cpp b/test/test_init.cpp new file mode 100644 index 0000000..118e51b --- /dev/null +++ b/test/test_init.cpp @@ -0,0 +1,47 @@ +/* Boost.Flyweight test of static data initialization facilities. + * + * Copyright 2006-2008 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_init.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include + +using namespace boost::flyweights; + +template +struct marked_hashed_factory_class:hashed_factory_class +{ + marked_hashed_factory_class(){*pmark=true;} +}; + +template +struct marked_hashed_factory:factory_marker +{ + template + struct apply + { + typedef marked_hashed_factory_class type; + }; +}; + +namespace{ +bool mark1=false; +bool init1=flyweight >::init(); + +bool mark2=false; +flyweight >::initializer init2; +} + +void test_init() +{ + BOOST_TEST(mark1); + BOOST_TEST(mark2); +} diff --git a/test/test_init.hpp b/test/test_init.hpp new file mode 100644 index 0000000..4e869f5 --- /dev/null +++ b/test/test_init.hpp @@ -0,0 +1,11 @@ +/* Boost.Flyweight test of static data initialization facilities. + * + * Copyright 2006-2008 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_init(); diff --git a/test/test_init_main.cpp b/test/test_init_main.cpp new file mode 100644 index 0000000..213e505 --- /dev/null +++ b/test/test_init_main.cpp @@ -0,0 +1,18 @@ +/* Boost.Flyweight test of static data initialization facilities. + * + * Copyright 2006-2008 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 +#include "test_init.hpp" + +int main() +{ + test_init(); + return boost::report_errors(); +} diff --git a/test/test_intermod_holder.cpp b/test/test_intermod_holder.cpp new file mode 100644 index 0000000..65ca1c1 --- /dev/null +++ b/test/test_intermod_holder.cpp @@ -0,0 +1,34 @@ +/* Boost.Flyweight test of intermodule_holder. + * + * Copyright 2006-2008 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_intermod_holder.hpp" + +#include "intermod_holder_dll.hpp" +#include "test_basic_template.hpp" + +using namespace boost::flyweights; + +struct intermodule_holder_flyweight_specifier1 +{ + template + struct apply + { + typedef flyweight type; + }; +}; + +void test_intermodule_holder() +{ + test_basic_template(); + + intermodule_flyweight_string str= + create_intermodule_flyweight_string("boost"); + BOOST_TEST(str==intermodule_flyweight_string("boost")); +} diff --git a/test/test_intermod_holder.hpp b/test/test_intermod_holder.hpp new file mode 100644 index 0000000..01495b3 --- /dev/null +++ b/test/test_intermod_holder.hpp @@ -0,0 +1,11 @@ +/* Boost.Flyweight test of intermodule_holder. + * + * Copyright 2006-2008 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_intermodule_holder(); diff --git a/test/test_intermod_holder_main.cpp b/test/test_intermod_holder_main.cpp new file mode 100644 index 0000000..11519cd --- /dev/null +++ b/test/test_intermod_holder_main.cpp @@ -0,0 +1,18 @@ +/* Boost.Flyweight test of intermodule_holder. + * + * Copyright 2006-2008 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 +#include "test_intermod_holder.hpp" + +int main() +{ + test_intermodule_holder(); + return boost::report_errors(); +} diff --git a/test/test_multictor.cpp b/test/test_multictor.cpp new file mode 100644 index 0000000..6f326f2 --- /dev/null +++ b/test/test_multictor.cpp @@ -0,0 +1,105 @@ +/* Boost.Flyweight test of flyweight forwarding ctors. + * + * Copyright 2006-2008 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_multictor.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include "test_basic_template.hpp" + +using boost::flyweight; + +#if BOOST_WORKAROUND(BOOST_MSVC,<1300) +#define NONCONST const +#else +#define NONCONST +#endif + +struct multictor +{ + typedef multictor type; + + multictor(): + t(0,0,0.0,"",false){} + multictor(NONCONST int& x0): + t(x0,0,0.0,"",false){} + multictor(int x0,NONCONST char& x1): + t(x0,x1,0.0,"",false){} + multictor(int x0,char x1,NONCONST double& x2): + t(x0,x1,x2,"",false){} + multictor(int x0,char x1,double x2,NONCONST std::string& x3): + t(x0,x1,x2,x3,false){} + multictor(int x0,char x1,double x2,const std::string& x3,NONCONST bool& x4): + t(x0,x1,x2,x3,x4){} + + friend bool operator==(const type& x,const type& y){return x.t==y.t;} + friend bool operator< (const type& x,const type& y){return x.t< y.t;} + friend bool operator!=(const type& x,const type& y){return x.t!=y.t;} + friend bool operator> (const type& x,const type& y){return x.t> y.t;} + friend bool operator>=(const type& x,const type& y){return x.t>=y.t;} + friend bool operator<=(const type& x,const type& y){return x.t<=y.t;} + + boost::tuples::tuple t; +}; + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) +namespace boost{ +#endif + +inline std::size_t hash_value(const multictor& x) +{ + std::size_t res=0; + boost::hash_combine(res,boost::tuples::get<0>(x.t)); + boost::hash_combine(res,boost::tuples::get<1>(x.t)); + boost::hash_combine(res,boost::tuples::get<2>(x.t)); + boost::hash_combine(res,boost::tuples::get<3>(x.t)); + boost::hash_combine(res,boost::tuples::get<4>(x.t)); + return res; +} + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) +} /* namespace boost */ +#endif + +void test_multictor() +{ + flyweight f; + multictor m; + BOOST_TEST(f==m); + + int x0=1; + flyweight f0(x0); + multictor m0(x0); + BOOST_TEST(f0==m0); + + char x1='a'; + flyweight f1(1,x1); + multictor m1(1,x1); + BOOST_TEST(f1==m1); + + double x2=3.1416; + flyweight f2(1,'a',x2); + multictor m2(1,'a',x2); + BOOST_TEST(f2==m2); + + std::string x3("boost"); + flyweight f3(1,'a',3.1416,x3); + multictor m3(1,'a',3.1416,x3); + BOOST_TEST(f3==m3); + + bool x4=true; + flyweight f4(1,'a',3.1416,"boost",x4); + multictor m4(1,'a',3.1416,"boost",x4); + BOOST_TEST(f4==m4); +} diff --git a/test/test_multictor.hpp b/test/test_multictor.hpp new file mode 100644 index 0000000..125cc92 --- /dev/null +++ b/test/test_multictor.hpp @@ -0,0 +1,11 @@ +/* Boost.Flyweight test of flyweight forwarding ctors. + * + * Copyright 2006-2008 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_multictor(); diff --git a/test/test_multictor_main.cpp b/test/test_multictor_main.cpp new file mode 100644 index 0000000..090aa3e --- /dev/null +++ b/test/test_multictor_main.cpp @@ -0,0 +1,18 @@ +/* Boost.Flyweight test of flyweight forwarding ctors. + * + * Copyright 2006-2008 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 +#include "test_multictor.hpp" + +int main() +{ + test_multictor(); + return boost::report_errors(); +} diff --git a/test/test_no_locking.cpp b/test/test_no_locking.cpp new file mode 100644 index 0000000..a9b493c --- /dev/null +++ b/test/test_no_locking.cpp @@ -0,0 +1,35 @@ +/* Boost.Flyweight test of no_locking. + * + * Copyright 2006-2008 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_no_locking.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include "test_basic_template.hpp" + +using namespace boost::flyweights; + +struct no_locking_flyweight_specifier +{ + template + struct apply + { + typedef flyweight type; + }; +}; + +void test_no_locking() +{ + test_basic_template(); +} diff --git a/test/test_no_locking.hpp b/test/test_no_locking.hpp new file mode 100644 index 0000000..a18470d --- /dev/null +++ b/test/test_no_locking.hpp @@ -0,0 +1,11 @@ +/* Boost.Flyweight test of no_locking. + * + * Copyright 2006-2008 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_no_locking(); diff --git a/test/test_no_locking_main.cpp b/test/test_no_locking_main.cpp new file mode 100644 index 0000000..85d2b09 --- /dev/null +++ b/test/test_no_locking_main.cpp @@ -0,0 +1,18 @@ +/* Boost.Flyweight test of no_locking. + * + * Copyright 2006-2008 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 +#include "test_no_locking.hpp" + +int main() +{ + test_no_locking(); + return boost::report_errors(); +} diff --git a/test/test_no_tracking.cpp b/test/test_no_tracking.cpp new file mode 100644 index 0000000..8765781 --- /dev/null +++ b/test/test_no_tracking.cpp @@ -0,0 +1,35 @@ +/* Boost.Flyweight test of no_tracking. + * + * Copyright 2006-2008 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_no_tracking.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include "test_basic_template.hpp" + +using namespace boost::flyweights; + +struct no_tracking_flyweight_specifier +{ + template + struct apply + { + typedef flyweight type; + }; +}; + +void test_no_tracking() +{ + test_basic_template(); +} diff --git a/test/test_no_tracking.hpp b/test/test_no_tracking.hpp new file mode 100644 index 0000000..9961373 --- /dev/null +++ b/test/test_no_tracking.hpp @@ -0,0 +1,11 @@ +/* Boost.Flyweight test of no_tracking. + * + * Copyright 2006-2008 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_no_tracking(); diff --git a/test/test_no_tracking_main.cpp b/test/test_no_tracking_main.cpp new file mode 100644 index 0000000..1cc9dec --- /dev/null +++ b/test/test_no_tracking_main.cpp @@ -0,0 +1,18 @@ +/* Boost.Flyweight test of no_tracking. + * + * Copyright 2006-2008 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 +#include "test_no_tracking.hpp" + +int main() +{ + test_no_tracking(); + return boost::report_errors(); +} diff --git a/test/test_set_factory.cpp b/test/test_set_factory.cpp new file mode 100644 index 0000000..eff0b9c --- /dev/null +++ b/test/test_set_factory.cpp @@ -0,0 +1,71 @@ +/* Boost.Flyweight test of set_factory. + * + * Copyright 2006-2008 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_set_factory.hpp" + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include "test_basic_template.hpp" + +using namespace boost::flyweights; + +struct set_factory_flyweight_specifier1 +{ + template + struct apply + { + typedef flyweight > type; + }; +}; + +struct set_factory_flyweight_specifier2 +{ + template + struct apply + { + typedef flyweight< + T, + static_holder_class, + set_factory_class< + boost::mpl::_1,boost::mpl::_2, + std::greater, + std::allocator + > + > type; + }; +}; + +struct set_factory_flyweight_specifier3 +{ + template + struct apply + { + typedef flyweight< + T, + set_factory< + std::greater, + std::allocator + >, + static_holder_class, + tag + > type; + }; +}; + +void test_set_factory() +{ + test_basic_template(); + test_basic_template(); + test_basic_template(); +} diff --git a/test/test_set_factory.hpp b/test/test_set_factory.hpp new file mode 100644 index 0000000..6e783e3 --- /dev/null +++ b/test/test_set_factory.hpp @@ -0,0 +1,11 @@ +/* Boost.Flyweight test of set_factory. + * + * Copyright 2006-2008 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_set_factory(); diff --git a/test/test_set_factory_main.cpp b/test/test_set_factory_main.cpp new file mode 100644 index 0000000..c0e5885 --- /dev/null +++ b/test/test_set_factory_main.cpp @@ -0,0 +1,18 @@ +/* Boost.Flyweight test of set_factory. + * + * Copyright 2006-2008 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 +#include "test_set_factory.hpp" + +int main() +{ + test_set_factory(); + return boost::report_errors(); +}