commit a5665e6ee1daacd1e692a79be71cb09f6f87edde Author: Joaquín M López Muñoz Date: Thu Dec 18 22:18:11 2008 +0000 added flyweight from trunk [SVN r50320] 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 0000000..d06799f Binary files /dev/null and b/doc/html.png differ diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000..ad252b2 --- /dev/null +++ b/doc/index.html @@ -0,0 +1,82 @@ + + + + + +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: +

+

+ +

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 0000000..703878d Binary files /dev/null and b/doc/memory.png differ diff --git a/doc/memory_gcc_344.png b/doc/memory_gcc_344.png new file mode 100644 index 0000000..0870c13 Binary files /dev/null and b/doc/memory_gcc_344.png differ diff --git a/doc/memory_msvc_80.png b/doc/memory_msvc_80.png new file mode 100644 index 0000000..e3fcdbc Binary files /dev/null and b/doc/memory_msvc_80.png differ diff --git a/doc/next.gif b/doc/next.gif new file mode 100644 index 0000000..d6c18a5 Binary files /dev/null and b/doc/next.gif differ 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 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 0000000..c35dfee Binary files /dev/null and b/doc/prev.gif differ diff --git a/doc/reference/factories.html b/doc/reference/factories.html new file mode 100644 index 0000000..e047b60 --- /dev/null +++ b/doc/reference/factories.html @@ -0,0 +1,583 @@ + + + + + +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: +

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

+These aspects impact the internal structure and behavior +of the flyweight instantiation in the following manner: + +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: +

+

+ +

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

+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

+ +

+

+

+ +
+ + + +
+
+ +
+ +

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 0000000..86f878a Binary files /dev/null and b/doc/time_gcc_344.png differ diff --git a/doc/time_msvc_80.png b/doc/time_msvc_80.png new file mode 100644 index 0000000..8689dad Binary files /dev/null and b/doc/time_msvc_80.png differ diff --git a/doc/tutorial/basics.html b/doc/tutorial/basics.html new file mode 100644 index 0000000..2af6057 --- /dev/null +++ b/doc/tutorial/basics.html @@ -0,0 +1,227 @@ + + + + + +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: +

+whereas potential drawbacks of using no_tracking include: + +

+ +
+ + + +
+ +
+ +

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

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

+

+ +

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

+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: + +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 0000000..860728a Binary files /dev/null and b/doc/tutorial/flyweight_rep.png differ 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 0000000..acb3777 Binary files /dev/null and b/doc/up.gif differ 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(); +}