commit a5665e6ee1daacd1e692a79be71cb09f6f87edde
Author: JoaquÃn M López Muñoz
+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
+
+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)
+
+See source code.
+
+Dummy program showing the basic capabilities of
+See source code.
+
+The program simulates the scenario described at the tutorial section on
+key-value flyweights: The class
+
+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
+
+the resulting data structure implicitly detects the duplicated
+occurrences of
+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.
+
+
+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. "©" for ©) are not properly
+handled. Improving the parsing code is left as an exercise to the reader.
+
+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
+The
+See source code.
+
+This program measures the time and space performances of a simple
+string type against several differently configured
+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)
+
+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.
+
+Currently there is no way to access the internal components of a
+
+When constructing a
+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
+
+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)
+
+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
+
+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:
+
+
+
+
+
Boost.Flyweight Acknowledgements
+
+
+
+intermodule_holder
+component.
+
+
+
+
+
+
+
+
+
+
+
+
+
Boost.Flyweight Examples
+
+
+
+
+Contents
+
+
+
+
+Example 1: basic usage
+
+flyweight
+explained at the tutorial.
+Example 2: key-value flyweights
+
+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
+
+(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)))))
+
+, x, y,
+tan, (tan x) and (tan y).
+Example 4: formatted text processing
+
+
+Fig. 1: Formatting contexts of characters in an HTML document.
+Example 5: flyweight-based memoization
+
+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;
+};
+
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
+
+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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Boost.Flyweight Future work
+
+
+
+
+Contents
+
+
+
+
+Introspection API
+
+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
+
+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
+
+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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Boost Flyweight Library
+
+
+
+flyweight<T>, which acts as a drop-in replacement for
+const T.
+
+
+
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 Performance
+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.
+
+As we saw in the tutorial rationale, +the flyweight pattern is based on two types of objects: +
+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.
+
+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: +
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.
+
+
++
| component | +overhead (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 | +|
sizeof(Key)<=sizeof(Value).std::set this overhead reduces to 3.
+For instance, for the default configuration parameters of flyweight,
+overhead is typically 2.5(hashed_factory) + 1(refcounted)
+= 3 words.
+
+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.
+
+
+Fig. 1: Relative memory consumption of Boost.Flyweight as a function of value diversity.
+
+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. +
+ +
+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 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.
+
+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.
+
+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.
+
+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:
+
std::string.flyweight<std::string> with default configuration aspects
+ (hashed_factory,
+ refcounted tracking,
+ simple_locking).
+ flyweight<std::string,no_tracking>.flyweight<std::string,set_factory>.flyweight<std::string,set_factory,no_tracking>.+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). +
+ +
+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.
+
+
+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.
+
+
+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.
+
+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.
+
+
+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.
+
+
+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).
+
+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
+Factories reference"boost/flyweight/factory_tag.hpp" synopsis
+
+ "boost/flyweight/hashed_factory_fwd.hpp" synopsis
+ "boost/flyweight/hashed_factory.hpp" synopsis
+
+ "boost/flyweight/set_factory_fwd.hpp" synopsis
+ "boost/flyweight/set_factory.hpp" synopsis
+
+ "boost/flyweight/assoc_container_factory_fwd.hpp" synopsis
+ "boost/flyweight/assoc_container_factory.hpp" synopsis
+
+
+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.
+
+
| expression | +return type | +assertion/note pre/post-condition |
+
|---|---|---|
Factory::handle_type |
+ handle 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_type |
+ Inserts a copy of x if there is no equivalent entry in f;+ returns a handle to the inserted or equivalent element. + |
+
f.erase(h); |
+ void |
+ Erases 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:
+
is_factory<S>::type is
+ boost::mpl::true_,S is of the form factory<S'>.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).
+ "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 +
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.
+
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.
+
"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.
+
"boost/flyweight/hashed_factory.hpp" synopsishashed_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.
+
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.
+
"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.
+
"boost/flyweight/set_factory.hpp" synopsisset_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.
+
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.
+
"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.
+
"boost/flyweight/assoc_container_factory.hpp" synopsisassoc_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
+
Container::key_type is the same as
+ Container::value_type (which is the entry type associated to
+ the factory).
+ Container is stable, i.e. its iterators are not
+ invalidated upon insert or erase operations.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.
+
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
+flyweight reference"boost/flyweight/flyweight_fwd.hpp" synopsis"boost/flyweight/flyweight.hpp" synopsis
+
+ "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.
+
"boost/flyweight/flyweight.hpp"
+synopsis
+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:
+
value_type object).
+ sizeof(value_type).
+ flyweight
+for value_type results in a reduction in memory usage.
+
+
+
+flyweight is parameterized according to some aspects:
+
key_value and value_type
+ (possibly equal), where key_type serves as a
+ key type to lookup and construct internal shared instances of
+ objects of value_type.
+ flyweight
+ class template.
+ flyweight instantiation in the following manner:
+flyweight internally owns
+ a unique factory object and a unique synchronization
+ mutex object, both of which
+ are created through the use of an associated holder type.
+ Entry that is implicitly convertible to
+ const key_type& and also stores a subobject of
+ value_type. Every flyweight object is associated
+ to a value_type subobject of some Entry
+ stored in the factory.
+ Handle. Handle and
+ the Entry type referred to above are obtained
+ from invocations to the associated tracking policy, in the
+ manner described for this concept.
+ 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); +}; +
+T can be either:
+
key_value<Key,Value[,KeyFromValue]>.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:
+
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:
+hashed_factory<>,static_holder,simple_locking,refcounted tracking policy.
+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+ +flyweightis guaranteed to be +constructed.
+Note: Concurrent execution of this function is not thread safe. +
initializer::initializer();
+
+
+Effects: Executes init().
+
+
+flyweight();
+
++Requires:+ +key_typeis +Default +Constructible.
+Effects: Constructs aflyweightobject associated +with valuevalue_type(key_type()). +
flyweight(const flyweight& x);
+flyweight(flyweight& x);
+
++Effects: Constructs a+ + +flyweightobject 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+ +flyweightobject 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+ +flyweightobject with the same value +asx.
+Returns:*this.
+Exception safety:nothrow. +
flyweight& operator=(const value_type& x);
+
++Requires: If+ +flyweightis key-value, +value_typeis +Assignable+and the +Key Extractor+KeyFromValuemust have been supplied as part of the +key_value<>construct.
+Effects: Associates theflyweightobject with a +copy ofxor with avalue_typeconstructed +from a key equivalent to that associated tox. For non-key-value +flyweights,xis its own key; for key-value flyweights, +the key is extracted through use of an object of typeKeyFromValue.
+Returns:*this.
+
const key_type& get_key()const;
+
++Return: A copy of the key used to construct the ++ +value_typeassociated to theflyweight+object.
+Exception safety: Ifflyweightis not key-value or +ifKeyFromValuewas not provided,nothrow. +
const value_type& get()const;
+ operator const value_type&()const;
+
++Return: The value associated to the+ +flyweight+object.
+Exception safety:nothrow. +
void swap(flyweight& x);
+
++Effects: Swaps the associations to+ +value_types each +flyweight object has. No swapping ofkey_typeor +value_typeobjects is done.
+Exception safety:nothrow. +
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+ +xandyare of the same type, returns +trueif and only if they are associated to the same value; if +xandyhave different types, returns +x.get()==y.get().
+Exception safety: Ifxandyare 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:+ +trueif and only if +++!(x==y)(OPis!=),
+y< x(OPis>),
+!(x< y)(OPis>=),
+!(y< x)(OPis<=). +
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+ +flyweightis key-value, +value_typeis +Assignable+and the +Key Extractor+KeyFromValuemust have been supplied as part of the +key_value<>construct.
+Effects: Reads an object of typevalue_typefromin+and assigns it tox.
+Returns:in. +
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
+Holders reference"boost/flyweight/holder_tag.hpp" synopsis
+
+ "boost/flyweight/static_holder_fwd.hpp" synopsis
+ "boost/flyweight/static_holder.hpp" synopsis
+
+ "boost/flyweight/intermodule_holder_fwd.hpp" synopsis
+ "boost/flyweight/intermodule_holder.hpp" synopsis
+
+
+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:
+
is_holder<S>::type is
+ boost::mpl::true_,S is of the form holder<S'>.S, or S' if (b) applies, is an
+ MPL Lambda
+ Expression such that invoking it with type C resolves to
+ a holder of C.
+ "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 +
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.
+
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.
+
"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.
+
"boost/flyweight/static_holder.hpp" synopsisstatic_holder_class
+static_holder_class<C> keeps its unique instance of C as a
+local static object.
+
static_holder
+Holder Specifier for static_holder_class.
+
"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.
+
"boost/flyweight/intermodule_holder.hpp" synopsisintermodule_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.
+
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 Reference"boost/flyweight.hpp" synopsisflyweight+Boost.Flyweight comprises the following public headers: +
"boost/flyweight.hpp"flyweight
+
+ +Boost.Flyweight is a header-only library, requiring no additional +object modules. +
+ +"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 @@ + + + + + +
Key-value flyweights reference"boost/flyweight/key_value_fwd.hpp" synopsis
+ "boost/flyweight/key_value.hpp" synopsis
+
+
+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
+
kfv(cv) is defined and have type const Key&,kfv(cv) is equivalent to kfv(Value(cv)),kfv(Value(k)) is equivalent to k,kfv of type const KeyFromValue,
+cv of type const Value and
+k of type Key.
+
+
+"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 +
"boost/flyweight/key_value.hpp" synopsiskey_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
+Locking policies reference"boost/flyweight/locking_tag.hpp" synopsis
+
+ "boost/flyweight/simple_locking_fwd.hpp" synopsis
+ "boost/flyweight/simple_locking.hpp" synopsis
+
+ "boost/flyweight/no_locking_fwd.hpp" synopsis
+ "boost/flyweight/no_locking.hpp" synopsis
+ no_locking
+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.
+
+
+
| expression | +return type | +assertion/note pre/post-condition |
+
|---|---|---|
Mutex m; |
+ + | Post: m is unlocked.
+ |
+
(&m)->~Mutex(); |
+ void |
+ Pre: m is unlocked. |
+
Lock lk(m); |
+ + | Associates m to lk and locks m. |
+
(&lk)->~Lock(); |
+ void |
+ Unlocks 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 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:
+
is_locking<Locking>::type is
+ boost::mpl::true_,Locking is of the form
+ locking<Locking'>.Locking::mutex_type (or
+ Locking'::mutex_type if (b) applies) is a
+ model of Mutex
+ and supports recursive locking.
+ Locking::lock_type (or
+ Locking'::lock_type if (b) applies) is a
+ Scoped Lock of
+ the mutex referred to above.
+ "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 +
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.
+
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.
+
"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.
+
"boost/flyweight/simple_locking.hpp" synopsissimple_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.
+
"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.
+
"boost/flyweight/no_locking.hpp" synopsisno_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
+Tags reference
+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.
+
"boost/flyweight/tag.hpp" synopsis+ ++namespace boost{ + +namespace flyweights{ + +template<typename T> +struct tag; + +} // namespace boost::flyweights + +} // namespace boost +
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
+Tracking policies reference"boost/flyweight/tracking_tag.hpp" synopsis
+
+ "boost/flyweight/refcounted_fwd.hpp" synopsis
+ "boost/flyweight/refcounted.hpp" synopsis
+ refcounted"boost/flyweight/no_tracking_fwd.hpp" synopsis
+ "boost/flyweight/no_tracking.hpp" synopsis
+
+
+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.
+
+
| expression | +return type | +assertion/note pre/post-condition |
+
|---|---|---|
TrackingHelper::entry(h); |
+ const Entry& |
+ Returns f.entry(h). |
+
TrackingHelper::erase(h,check); |
+ void |
+ If 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.
+
+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:
+
is_tracking<Tracking>::type is
+ boost::mpl::true_,Tracking is of the form
+ tracking<Tracking'>.Tracking::entry_type (or
+ Tracking'::entry_type if (b) applies) is an
+ MPL Lambda
+ Expression that resolves, when invoked with different types
+ (Value,Key) such that Value is
+ Assignable
+ and implicitly convertible to const Key&, to an
+ Assignable
+ type Entry implicitly convertible to both const Value&
+ and const Key&.
+ Tracking::handle_type (or
+ Tracking'::handle_type if (b) applies) is an
+ MPL Lambda
+ Expression; this expression, when invoked with types
+ (InternalHandle,TrackingHelper),
+ with InternalHandle being
+ Assignable
+ and providing the nothrow guarantee for copy and assignment,
+ resolves to an
+ Assignable
+ type Handle which also provides the nothrow guarantee for
+ copy and assignment and is constructible from and implicitly
+ convertible to InternalHandle.
+ TrackingHelper is an incomplete type at the time of
+ invocation of Tracking::handle_type.
+ Tracking::handle_type is parameterized by a helper that provides
+access to some of the functionality of the factory associated to the
+tracking policy. This factory's associated entry and handle types are the types
+Entry and Handle defined above, respectively.
+
+
+"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 +
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.
+
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.
+
"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.
+
"boost/flyweight/refcounted.hpp" synopsisrefcounted
+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.
+
"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.
+
"boost/flyweight/no_tracking.hpp" synopsisno_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 Release notes+
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 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. +
+ ++
| Program | +Description | +
|---|---|
test_assoc_cont_factory.cpp |
+ assoc_container_factory
+ factory specifier. |
+
test_basic.cpp |
+ Exercises the default components of flyweight. |
+
test_custom_factory.cpp |
+ Creates a user-defined factory class and specifier. | +
test_init.cpp |
+ Boost.Flyweight static + data initialization facilities. | +
test_intermod_holder.cpp+ intermod_holder_dll.cpp |
+ Exercises intermodule_holder. |
+
test_multictor.cpp |
+ Tests flyweight multiple
+ argument constructors. |
+
test_no_locking.cpp |
+ no_locking policy. |
+
test_no_tracking.cpp |
+ no_tracking policy. |
+
test_set_factory.cpp |
+ set_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 Tutorial: Basics+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.
+
+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 Tutorial: Configuring Boost.Flyweightsimple_lockingno_lockingrefcountedno_tracking
+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:
+
flyweight objects refer to.
+
+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.
+
+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. +
+ ++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.
+
+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.
+
+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:
+
Unique
+ Associative Container where equivalence of Entrys
+ is determined by the key_type values the entries are convertible
+ to .
+ +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; +
+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.
+
+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.
+
+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:
+
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 Tutorial: Extending Boost.Flyweight
+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: +
flyweight
+ instantiation.
+ 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.
+
+
+
+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: +
Entry
+ and Key, as these types are provided internally by Boost.Flyweight
+ when the factory is instantiated as part of the machinery of flyeight;
+ but there is nothing to prevent us from having more template parameters for
+ finer configuration of the factory type: for instance, we could extend
+ verbose_factory_class to accept some comparison predicate rather than
+ the default std::less<Key>, or to specify the allocator
+ used by the internal std::set.
+ Entry is convertible to const Key&
+ (which is about the only property known about Entry) is
+ exploited in the specification of std::less<Key> as
+ the comparison predicate for the std::set of Entrys
+ used as the internal repository.
+ handle_type we are simply using an iterator to the
+ internal std::set.
+
+In order to plug a custom factory into the specification of a flyweight
+type, we need an associated construct called the factory specifier.
+A factory specifier is a
+Lambda
+Expression accepting the two argument types Entry
+and Key and returning the corresponding factory class:
+
+ ++// Factory specifier (metafunction class version) + +struct custom_factory_specifier +{ + template<typename Entry,Key> + struct apply + { + typedef custom_factory_class<Entry,Key> type; + } +}; + +// Factory specifier (placeholder version) + +typedef custom_factory_class< + boost::mpl::_1, + boost::mpl::_2 +> custom_factory_specifier; +
+There is one last detail: in order to implement flyweight
+free-order template
+parameter interface, it is necessary to explicitly tag a
+factory specifier as such, so that it can be distinguised from other
+types of specifiers. Boost.Flyweight provides three different mechanisms
+to do this tagging:
+
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; + } +}; +
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_{}; + +} +} +
factory
+ construct:
+++#include <boost/flyweight/factory_tag.hpp> + +typedef flyweight< + std::string, + factory<custom_factory_specifier> +> flyweight_string; +
+Example 7 in the examples section develops
+in full the verbose_factory_class case sketched above.
+
+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; +
+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. +
+ +
+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:
+
Tracking::entry_type.Tracking::handle_type.Tracking::entry_type is a
+ Lambda
+ Expression accepting two different types named
+ Value and Key such that
+ Value is implicitly convertible to
+ const Key&. The expression is expected
+ to return
+ a type implicitly convertible to both const Value&
+ and const Key&.
+ Tracking::entry_type corresponds to the actual
+ type of the entries stored into the
+ flyweight factory:
+ by allowing the tracking policy to take part on the definition
+ of this type it is possible for the policy to add internal
+ tracking information to the entry data in case this is needed.
+ If no additional information is required,
+ the tracking policy can simply return Value as its
+ Tracking::entry_type type.
+ Lambda
+ Expression Tracking::handle_type is invoked
+ with types InternalHandle and TrackingHandler
+ to produce a type Handle, which will be used as the handle
+ type of the flyweight factory.
+ TrackingHandler
+ is passed as a template argument to Tracking::handle_type
+ to offer functionality supporting the implementation of the tracking
+ code.
+ 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 Tutorial
+
+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. +
+ +
+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; +
+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 Tutorial: 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.
+
+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. +
+ +
+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 Tutorial Annex: MPL lambda expressionsThis 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
+
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; + }; +}; +
MPL
+ Placeholder Expression, a class template instantiated with one or
+ more placeholders:
++ Note that, in this case,+typedef foo<boost::mpl::_1,boost::mpl::_2> foo_specifier; +
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.
+ 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 Tutorial: Technical issues
+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 +