Initial commit

[SVN r9503]
This commit is contained in:
Beman Dawes
2001-03-08 20:44:22 +00:00
commit 0a122496e1
52 changed files with 7072 additions and 0 deletions
+96
View File
@@ -0,0 +1,96 @@
* text=auto !eol svneol=native#text/plain
*.gitattributes text svneol=native#text/plain
# Scriptish formats
*.bat text svneol=native#text/plain
*.bsh text svneol=native#text/x-beanshell
*.cgi text svneol=native#text/plain
*.cmd text svneol=native#text/plain
*.js text svneol=native#text/javascript
*.php text svneol=native#text/x-php
*.pl text svneol=native#text/x-perl
*.pm text svneol=native#text/x-perl
*.py text svneol=native#text/x-python
*.sh eol=lf svneol=LF#text/x-sh
configure eol=lf svneol=LF#text/x-sh
# Image formats
*.bmp binary svneol=unset#image/bmp
*.gif binary svneol=unset#image/gif
*.ico binary svneol=unset#image/ico
*.jpeg binary svneol=unset#image/jpeg
*.jpg binary svneol=unset#image/jpeg
*.png binary svneol=unset#image/png
*.tif binary svneol=unset#image/tiff
*.tiff binary svneol=unset#image/tiff
*.svg text svneol=native#image/svg%2Bxml
# Data formats
*.pdf binary svneol=unset#application/pdf
*.avi binary svneol=unset#video/avi
*.doc binary svneol=unset#application/msword
*.dsp text svneol=crlf#text/plain
*.dsw text svneol=crlf#text/plain
*.eps binary svneol=unset#application/postscript
*.gz binary svneol=unset#application/gzip
*.mov binary svneol=unset#video/quicktime
*.mp3 binary svneol=unset#audio/mpeg
*.ppt binary svneol=unset#application/vnd.ms-powerpoint
*.ps binary svneol=unset#application/postscript
*.psd binary svneol=unset#application/photoshop
*.rdf binary svneol=unset#text/rdf
*.rss text svneol=unset#text/xml
*.rtf binary svneol=unset#text/rtf
*.sln text svneol=native#text/plain
*.swf binary svneol=unset#application/x-shockwave-flash
*.tgz binary svneol=unset#application/gzip
*.vcproj text svneol=native#text/xml
*.vcxproj text svneol=native#text/xml
*.vsprops text svneol=native#text/xml
*.wav binary svneol=unset#audio/wav
*.xls binary svneol=unset#application/vnd.ms-excel
*.zip binary svneol=unset#application/zip
# Text formats
.htaccess text svneol=native#text/plain
*.bbk text svneol=native#text/xml
*.cmake text svneol=native#text/plain
*.css text svneol=native#text/css
*.dtd text svneol=native#text/xml
*.htm text svneol=native#text/html
*.html text svneol=native#text/html
*.ini text svneol=native#text/plain
*.log text svneol=native#text/plain
*.mak text svneol=native#text/plain
*.qbk text svneol=native#text/plain
*.rst text svneol=native#text/plain
*.sql text svneol=native#text/x-sql
*.txt text svneol=native#text/plain
*.xhtml text svneol=native#text/xhtml%2Bxml
*.xml text svneol=native#text/xml
*.xsd text svneol=native#text/xml
*.xsl text svneol=native#text/xml
*.xslt text svneol=native#text/xml
*.xul text svneol=native#text/xul
*.yml text svneol=native#text/plain
boost-no-inspect text svneol=native#text/plain
CHANGES text svneol=native#text/plain
COPYING text svneol=native#text/plain
INSTALL text svneol=native#text/plain
Jamfile text svneol=native#text/plain
Jamroot text svneol=native#text/plain
Jamfile.v2 text svneol=native#text/plain
Jamrules text svneol=native#text/plain
Makefile* text svneol=native#text/plain
README text svneol=native#text/plain
TODO text svneol=native#text/plain
# Code formats
*.c text svneol=native#text/plain
*.cpp text svneol=native#text/plain
*.h text svneol=native#text/plain
*.hpp text svneol=native#text/plain
*.ipp text svneol=native#text/plain
*.tpp text svneol=native#text/plain
*.jam text svneol=native#text/plain
*.java text svneol=native#text/plain
+5
View File
@@ -0,0 +1,5 @@
Here's a list of things TODO on the Pool library; these things will be done on an "as-I-get-around-to-it" basis:
. Evaluate changes necessary for MSVC 6sp4 (Could use some help from people who own MSVC...)
. Create more exhaustive test/example files, possibly other timing tests; convert to the new Boost testing harness
. Add overloaded new/delete (pool_base) as Yet Another Interface.
. Add a "grow" function (similar to std::realloc) to pool for attempting reallocation of contiguous memory; if it fails to find contiguous chunks, it should return 0.
+176
View File
@@ -0,0 +1,176 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>Pool Concepts</TITLE>
<LINK HREF="pool.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY>
<IMG SRC="../../../c++boost.gif" WIDTH=276 HEIGHT=86 ALT="C++ Boost">
<H1 ALIGN=CENTER>Pool Concepts</H1>
<P>
<BLOCKQUOTE>
&quot;Dynamic memory allocation has been a fundamental part of most computer systems since roughly 1960...&quot;<SUP><A HREF="#ref1">1</A></SUP>
</BLOCKQUOTE>
<p>
Everyone uses dynamic memory allocation. If you have ever called <SPAN CLASS="code">malloc</SPAN> or <SPAN CLASS="code">new</SPAN>, then you have used dynamic memory allocation. Most programmers have a tendency to treat the heap as a &quot;magic bag&quot;: we ask it for memory, and it magically creates some for us. Sometimes we run into problems because the heap is <EM>not</EM> magic.
<p>
The heap is limited. Even on large systems (i.e., not embedded) with huge amounts of virtual memory available, there is a limit. Everyone is aware of the physical limit, but there is a more subtle, &quot;virtual&quot; limit, that limit at which your program (or the entire system) slows down due to the use of virtual memory. This virtual limit is much closer to your program than the physical limit, especially if you are running on a multitasking system. Therefore, when running on a large system, it is considered &quot;nice&quot; to make your program use as few resources as necessary, and release them as soon as possible. When using an embedded system, programmers usually have no memory to waste.
<P>
The heap is complicated. It has to satisfy any type of memory request, for any size, and do it <EM>fast</EM>. The common approaches to memory management have to do with splitting the memory up into portions, and keeping them ordered by size in some sort of a tree or list structure. Add in other factors, such as locality and estimating lifetime, and heaps quickly become very complicated. So complicated, in fact, that there is no known &quot;perfect&quot; answer to the problem of how to do dynamic memory allocation. The diagrams below illustrate how most common memory managers work: for each chunk of memory, it uses part of that memory to maintain its internal tree or list structure. Even when a chunk is <SPAN CLASS="code">malloc</SPAN>'ed out to a program, the memory manager must &quot;save&quot; some information in it &mdash; usually just its size. Then, when the block is <SPAN CLASS="code">free</SPAN>'d, the memory manager can easily tell how large it is.
<TABLE CELLSPACING="0" BORDER="3" RULES="none" STYLE="float: left; clear: both;">
<CAPTION><EM>Memory block, not allocated</EM></CAPTION>
<TR><TD STYLE="background-color: red; text-align: center;">Memory not belonging to process</TD></TR>
<TR><TD STYLE="padding: 1em 0em; background-color: silver; text-align: center;">Memory used internally by memory allocator algorithm (usually 8-12 bytes)</TD></TR>
<TR><TD STYLE="padding: 2em 0em; background-color: gray; text-align: center">Unused memory</TD></TR>
<TR><TD STYLE="background-color: red; text-align: center;">Memory not belonging to process</TD></TR>
</TABLE>
<TABLE CELLSPACING="0" BORDER="3" RULES="none" STYLE="float: right; clear: both;">
<CAPTION><EM>Memory block, allocated (used by program)</EM></CAPTION>
<TR><TD STYLE="background-color: red; text-align: center;">Memory not belonging to process</TD></TR>
<TR><TD STYLE="background-color: silver; text-align: center;">Memory used internally by memory allocator algorithm (usually 4 bytes)</TD></TR>
<TR><TD STYLE="padding: 3em 0em; background-color: yellow; text-align: center">Memory usable by program</TD></TR>
<TR><TD STYLE="background-color: red; text-align: center;">Memory not belonging to process</TD></TR>
</TABLE>
<P>
Because of the complication of dynamic memory allocation, it is often inefficient in terms of time and/or space. Most memory allocation algorithms store some form of information with each memory block, either the block size or some relational information, such as its position in the internal tree or list structure. It is common for such &quot;header fields&quot; to take up one machine word in a block that is being used by the program. The obvious problem, then, is when small objects are dynamically allocated. For example, if <SPAN CLASS="code">int</SPAN>s were dynamically allocated, then automatically the algorithm will reserve space for the header fields as well, and we end up with a 50% waste of memory. Of course, this is a worst-case scenario. However, more modern programs are making use of small objects on the heap; and that is making this problem more and more apparent. Wison <EM>et. al.</EM> state that an average-case memory overhead is about ten to twenty percent<SUP><A HREF="#ref2">2</A></SUP>. This memory overhead will grow higher as more programs use more smaller objects. It is this memory overhead that brings programs closer to the virtual limit.
<P>
In larger systems, the memory overhead is not as big of a problem (compared to the amount of time it would take to work around it), and thus is often ignored. However, there are situations where many allocations and/or deallocations of smaller objects are taking place as part of a time-critical algorithm, and in these situations, the system-supplied memory allocator is often too slow.
<P>
Simple segregated storage addresses both of these issues. Almost all memory overhead is done away with, and all allocations can take place in a small amount of (amortized) constant time. However, this is done at the loss of generality; simple segregated storage only can allocate memory chunks of a single size.
<P>
<HR>
<P>
<H1 ALIGN=CENTER>Simple Segregated Storage</H1>
<P>
Simple Segregated Storage is the basic idea behind the Boost Pool library. Simple Segregated Storage is the simplest, and probably the fastest, memory allocation/deallocation algorithm. It begins by <EM>partitioning</EM> a memory <EM>block</EM> into fixed-size <EM>chunks</EM>. Where the block comes from is not important until implementation time. A <EM>Pool</EM> is some object that uses Simple Segregated Storage in this fashion. To illustrate:
<TABLE CELLSPACING="0" BORDER="3" RULES="none" ALIGN=CENTER STYLE="clear: both;">
<CAPTION><EM>Memory block, split into chunks</EM></CAPTION>
<TR><TD STYLE="background-color: red; text-align: center;">Memory not belonging to process</TD></TR>
<TR><TD STYLE="padding: 1em 0em; background-color: gray; text-align: center;">Chunk 0</TD></TR>
<TR><TD STYLE="padding: 1em 0em; background-color: gray; text-align: center;">Chunk 1</TD></TR>
<TR><TD STYLE="padding: 1em 0em; background-color: gray; text-align: center;">Chunk 2</TD></TR>
<TR><TD STYLE="padding: 1em 0em; background-color: gray; text-align: center;">Chunk 3</TD></TR>
<TR><TD STYLE="background-color: red; text-align: center;">Memory not belonging to process</TD></TR>
</TABLE>
<P>
Each of the chunks in any given block are <STRONG>always</STRONG> the same size. This is the fundamental restriction of Simple Segregated Storage: you cannot ask for chunks of different sizes. For example, you cannot ask a Pool of integers for a character, or a Pool of characters for an integer (assuming that characters and integers are different sizes).
<P>
Simple Segregated Storage works by interleaving a <EM>free list</EM> within the unused chunks. For example:
<TABLE CELLSPACING="0" BORDER="3" RULES="none" STYLE="float: left; clear: both;">
<CAPTION><EM>Memory block, with no chunks allocated</EM></CAPTION>
<TR><TD STYLE="background-color: red; text-align: center;">Memory not belonging to process</TD></TR>
<TR><TD STYLE="padding: 1em 0em; background-color: gray; text-align: center;">Chunk 0; points to Chunk 1</TD></TR>
<TR><TD STYLE="padding: 1em 0em; background-color: gray; text-align: center;">Chunk 1; points to Chunk 2</TD></TR>
<TR><TD STYLE="padding: 1em 0em; background-color: gray; text-align: center;">Chunk 2; points to Chunk 3</TD></TR>
<TR><TD STYLE="padding: 1em 0em; background-color: gray; text-align: center;">Chunk 3; end-of-list</TD></TR>
<TR><TD STYLE="background-color: red; text-align: center;">Memory not belonging to process</TD></TR>
</TABLE>
<TABLE CELLSPACING="0" BORDER="3" RULES="none" STYLE="float: right; clear: both;">
<CAPTION><EM>Memory block, with two chunks allocated</EM></CAPTION>
<TR><TD STYLE="background-color: red; text-align: center;">Memory not belonging to process</TD></TR>
<TR><TD STYLE="padding: 1em 0em; background-color: gray; text-align: center;">Chunk 0; points to Chunk 2</TD></TR>
<TR><TD STYLE="padding: 1em 0em; background-color: silver; text-align: center;">Chunk 1 (in use by process)</TD></TR>
<TR><TD STYLE="padding: 1em 0em; background-color: gray; text-align: center;">Chunk 2; end-of-list</TD></TR>
<TR><TD STYLE="padding: 1em 0em; background-color: silver; text-align: center;">Chunk 3 (in use by process)</TD></TR>
<TR><TD STYLE="background-color: red; text-align: center;">Memory not belonging to process</TD></TR>
</TABLE>
<P>
By interleaving the free list inside the chunks, each Simple Segregated Storage only has the overhead of a single pointer (the pointer to the first element in the list). It has <EM>no</EM> memory overhead for chunks that are in use by the process.
<P>
Simple Segregated Storage is also extremely fast. In the simplest case, memory allocation is merely removing the first chunk from the free list, a O(1) operation. In the case where the free list is empty, another block may have to be acquired and partitioned, which would result in an amortized O(1) time. Memory deallocation may be as simple as adding that chunk to the front of the free list, a O(1) operation. However, more complicated uses of Simple Segregated Storage may require a sorted free list, which makes deallocation O(N).
<P>
Simple Segregated Storage gives faster execution and less memory overhead than a system-supplied allocator, but at the loss of generality. A good place to use a Pool is in situations where many (noncontiguous) small objects may be allocated on the heap, or if allocation and deallocation of the same-sized objects happens repeatedly.
<P>
<HR>
<P>
<H2>References</H2>
<P>
<OL>
<LI><A NAME="ref1">Doug Lea, <EM>A Memory Allocator</EM>.</A> Available on the web at <A HREF="http://gee.cs.oswego.edu/dl/html/malloc.html">http://gee.cs.oswego.edu/dl/html/malloc.html</A></LI>
<LI><A NAME="ref2">Paul R. Wilson, Mark S. Johnstone, Michael Neely, and David Boles, &quot;Dynamic Storage Allocation: A Survey and Critical Review&quot; in <EM>International Workshop on Memory Management</EM>, September 1995, pg. 28, 36.</A> Available on the web at <A HREF="ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps">ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps</A></LI>
</OL>
<P>
<H2>Other Implementations</H2>
<P>
Pool allocators are found in many programming languages, and in many variations. The beginnings of many implementations may be found in common programming literature; some of these are given below. Note that none of these are complete implementations of a Pool; most of these leave some aspects of a Pool as a user exercise. However, in each case, even though some aspects are missing, these examples use the same underlying concept of a Simple Segregated Storage described in this document.
<P>
<UL>
<LI>
&quot;The C++ Programming Language&quot;, 3rd ed., by Bjarne Stroustrup, Section 19.4.2. Missing aspects:
<OL>
<LI>Not portable</LI>
<LI>Cannot handle allocations of arbitrary numbers of objects (this was left as an exercise)</LI>
<LI>Not thread-safe</LI>
<LI>Suffers from the static initialization problem</LI>
</OL>
</LI>
<LI>
&quot;MicroC/OS-II: The Real-Time Kernel&quot;, by Jean J. Labrosse, Chapter 7 and Appendix B.04. This is an example of the Simple Segregated Storage scheme at work in the internals of an actual OS. Missing aspects:
<OL>
<LI>Not portable (though this is OK, since it's part of its own OS)</LI>
<LI>Cannot handle allocations of arbitrary numbers of blocks (which is also OK, since this feature is not needed)</LI>
<LI>Requires non-intuitive user code to create and destroy the Pool</LI>
</OL>
</LI>
<LI>
&quot;Efficient C++: Performance Programming Techniques&quot;, by Dov Bulka and David Mayhew, Chapters 6 and 7. This is a good example of iteratively developing a Pool solution; however, their premise (that the system-supplied allocation mechanism is hopelessly inefficient) is flawed on every system I've tested on. Run their timings on your system before you accept their conclusions. Missing aspects:
<OL>
<LI>Requires non-intuitive user code to create and destroy the Pool</LI>
</OL>
</LI>
<LI>
&quot;Advanced C++: Programming Styles and Idioms&quot;, by James O. Coplien, Section 3.6. This has examples of both static and dynamic pooling. Missing aspects:
<OL>
<LI>Not thread-safe</LI>
<LI>The static pooling example is not portable</LI>
</OL>
</LI>
</UL>
<P>
<HR>
<P>
Copyright &copy; 2000, 2001 Stephen Cleary (<A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>)
<P>
This file can be redistributed and/or modified under the terms found in <A HREF="copyright.html">copyright.html</A>
<P>
This software and its documentation is provided &quot;as is&quot; without express or implied warranty, and with no claim as to its suitability for any purpose.
</BODY>
</HTML>
+25
View File
@@ -0,0 +1,25 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>Pool Copyright</TITLE>
</HEAD>
<BODY>
<IMG SRC="../../../c++boost.gif" WIDTH=276 HEIGHT=86 ALT="C++ Boost">
<H1 ALIGN="CENTER">Pool Copyright</H1>
<P>
Copyright &copy; 2000 Stephen Cleary (<A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>)
<P>
Permission to copy, use, and distribute this software and its documentation is granted, provided that the above copyright notice appears in all copies and that that copyright notice appear in supporting documentation.
<P>
Permission to modify the software and its documentation, and to distribute modified software and documentation is granted, provided that: the above copyright notice appears in all copies <STRONG>AND</STRONG> that copyright notice appears in supporting documentation, <STRONG>AND</STRONG> a notice that the software was modified appears with the copyright notice.
<P>
This software and its documentation is provided &quot;as is&quot; without express or implied warranty, and with no claim as to its suitability for any purpose.
</BODY>
</HTML>
+383
View File
@@ -0,0 +1,383 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>Guaranteeing Alignment</TITLE>
<LINK HREF="../pool.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY>
<IMG SRC="../../../../c++boost.gif" WIDTH=276 HEIGHT=86 ALT="C++ Boost">
<H1 ALIGN=CENTER>Guaranteeing Alignment</H1>
<P>
<H2>Terminology</H2>
<P>
Review the <A HREF="../concepts.html">concepts document</A> if you are not already familiar with it. Remember that <EM>block</EM> is a contiguous section of memory, which is <EM>partitioned</EM> or <EM>segregated</EM> into fixed-size <EM>chunks</EM>. These <EM>chunks</EM> are what are allocated and deallocated by the user.
<P>
<H2>Overview</H2>
<P>
Each <SPAN CLASS="code">Pool</SPAN> has a single free list that can extend over a number of memory blocks. Thus, <SPAN CLASS="code">Pool</SPAN> also has a linked list of allocated memory blocks. Each memory block, by default, is allocated using <SPAN CLASS="code">new[]</SPAN>, and all memory blocks are freed on destruction. It is the use of <SPAN CLASS="code">new[]</SPAN> that allows us to guarantee alignment.
<P>
<H2>Proof of Concept: Guaranteeing Alignment</H2>
<P>
Each block of memory is allocated as a POD type (specifically, an array of characters) through <SPAN CLASS="code">operator new[]</SPAN>. Let <EM>POD_size</EM> be the number of characters allocated.
<P>
<H3>Predicate 1: Arrays may not have padding</H3>
<P>
This follows from the following quote:
<P>
[5.3.3/2] (Expressions::Unary expressions::Sizeof) &quot;... When applied to an array, the result is the total number of bytes in the array. This implies that the size of an array of <EM>n</EM> elements is <EM>n</EM> times the size of an element.&quot;
<P>
Therefore, arrays cannot contain padding, though the elements within the arrays may contain padding.
<P>
<H3>Predicate 2: Any block of memory allocated as an array of characters through <SPAN CLASS="code">operator new[]</SPAN> (hereafter referred to as <EM>the block</EM>) is properly aligned for any object of that size or smaller</H3>
<P>
This follows from:
<UL>
<LI>[3.7.3.1/2] (Basic concepts::Storage duration::Dynamic storage duration::Allocation functions) &quot;... The pointer returned shall be suitably aligned so that it can be converted to a pointer of any complete object type and then used to access the object or array in the storage allocated ...&quot;</LI>
<LI>[5.3.4/10] (Expressions::Unary expressions::New) &quot;... For arrays of <SPAN CLASS="code">char</SPAN> and <SPAN CLASS="code">unsigned char</SPAN>, the difference between the result of the <EM>new-expression</EM> and the address returned by the allocation function shall be an integral multiple of the most stringent alignment requirement (3.9) of any object type whose size is no greater than the size of the array being created. [<EM>Note:</EM> Because allocation functions are assumed to return pointers to storage that is appropriately aligned for objects of any type, this constraint on array allocation overhead permits the common idiom of allocating character arrays into which objects of other types will later be placed. ]&quot;</LI>
</UL>
<P>
<H3>Consider: imaginary object type <EM>Element</EM> of a size which is a multiple of some actual object size; assume sizeof(Element) &gt; POD_size</H3>
<P>
Note that an object of that size <EM>can</EM> exist. One object of that size is an array of the &quot;actual&quot; objects.
<P>
Note that the block is properly aligned for an Element. This directly follows from Predicate 2.
<P>
<H3>Corollary 1: The block is properly aligned for an array of Elements</H3>
<P>
This follows from Predicates 1 and 2, and the following quote:
<P>
[3.9/9] (Basic concepts::Types) &quot;An <EM>object type</EM> is a (possibly cv-qualified) type that is not a function type, not a reference type, and not a void type.&quot; (Specifically, array types are object types.)
<P>
<H3>Corollary 2: For any pointer <EM>p</EM> and integer <EM>i</EM>, if p is properly aligned for the type it points to, then p + i (when well-defined) is properly aligned for that type; in other words, if an array is properly aligned, then each element in that array is properly aligned</H3>
<P>
There are no quotes from the Standard to directly support this argument, but it fits the common conception of the meaning of &quot;alignment&quot;.
<P>
Note that the conditions for p + i being well-defined are outlined in [5.7/5]. We do not quote that here, but only make note that it is well-defined if p and p + i both point into or one past the same array.
<P>
<H3>Let: sizeof(Element) be the least common multiple of sizes of several actual objects (T<SUB>1</SUB>, T<SUB>2</SUB>, T<SUB>3</SUB>, ...)</H3>
<P>
<H3>Let: <EM>block</EM> be a pointer to the memory block, <EM>pe</EM> be (Element *) block, and <EM>p<SUB>n</SUB></EM> be (T<SUB>n</SUB> *) block</H3>
<P>
<H3>Corollary 3: For each integer <EM>i</EM>, such that pe + i is well-defined, then for each <EM>n</EM>, there exists some integer <EM>j<SUB>n</SUB></EM> such that p<SUB>n</SUB> + j<SUB>n</SUB> is well-defined and refers to the same memory address as pe + i</H3>
<P>
This follows naturally, since the memory block is an array of Elements, and for each n, sizeof(Element) % sizeof(T<SUB>n</SUB>) == 0; thus, the boundary of each element in the array of Elements is also a boundary of each element in each array of T<SUB>n</SUB>.
<P>
<H3>Theorem: For each integer <EM>i</EM>, such that pe + i is well-defined, that address (pe + i) is properly aligned for each type T<SUB>n</SUB></H3>
<P>
Since pe + i is well-defined, then by Corollary 3, p<SUB>n</SUB> + j<SUB>n</SUB> is well-defined. It is properly aligned from Predicate 2 and Corollaries 1 and 2.
<P>
<H2>Use of the Theorem</H2>
<P>
The proof above covers alignment requirements for cutting chunks out of a block. The implementation uses actual object sizes of:
<UL>
<LI>The requested object size (requested_size); this is the size of chunks requested by the user</LI>
<LI>void * (pointer to void); this is because we interleave our free list through the chunks</LI>
<LI>size_type; this is because we store the size of the next block within each memory block</LI>
</UL>
<P>
Each block also contains a pointer to the next block; but that is stored as a pointer to void and cast when necessary, to simplify alignment requirements to the three types above.
<P>
Therefore, <SPAN CLASS="code">alloc_size</SPAN> is defined to be the lcm of the sizes of the three types above.
<P>
<H2>A Look at the Memory Block</H2>
<P>
Each memory block consists of three main sections. The first section is the part that chunks are cut out of, and contains the interleaved free list. The second section is the pointer to the next block, and the third section is the size of the next block.
<P>
Each of these sections may contain padding as necessary to guarantee alignment for each of the next sections. The size of the first section is number_of_chunks * lcm(requested_size, sizeof(void *), sizeof(size_type)); the size of the second section is lcm(sizeof(void *), sizeof(size_type); and the size of the third section is sizeof(size_type).
<P>
Here's an example memory block, where requested_size == sizeof(void *) == sizeof(size_type) == 4:
<TABLE CELLSPACING="0" CELLPADDING="0" BORDER="3" STYLE="clear: both;" ALIGN=CENTER>
<CAPTION><EM>Memory block containing 4 chunks, showing overlying array structures; FLP = Interleaved Free List Pointer</EM></CAPTION>
<TR><TH>Sections<TH>size_type alignment<TH>void * alignment<TH>requested_size alignment
<TR><TD STYLE="background-color: red; text-align: center;" COLSPAN="4">Memory not belonging to process
<TR><TD STYLE="background-color: gray; text-align: center;" ROWSPAN="4">Chunks section (16 bytes)
<TD STYLE="background-color: gray; text-align: center;">(4 bytes)
<TD STYLE="background-color: gray; text-align: center;">FLP for Chunk 1 (4 bytes)
<TD STYLE="background-color: gray; text-align: center;">Chunk 1 (4 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(4 bytes)
<TD STYLE="background-color: silver; text-align: center;">FLP for Chunk 2 (4 bytes)
<TD STYLE="background-color: silver; text-align: center;">Chunk 2 (4 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(4 bytes)
<TD STYLE="background-color: gray; text-align: center;">FLP for Chunk 3 (4 bytes)
<TD STYLE="background-color: gray; text-align: center;">Chunk 3 (4 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(4 bytes)
<TD STYLE="background-color: silver; text-align: center;">FLP for Chunk 4 (4 bytes)
<TD STYLE="background-color: silver; text-align: center;">Chunk 4 (4 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">Pointer to next Block (4 bytes)
<TD STYLE="background-color: gray; text-align: center;">(4 bytes)
<TD STYLE="background-color: gray; text-align: center;">Pointer to next Block (4 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">Size of next Block (4 bytes)
<TD STYLE="background-color: silver; text-align: center;">Size of next Block (4 bytes)
<TR><TD STYLE="background-color: red; text-align: center;" COLSPAN="4">Memory not belonging to process
</TABLE>
<P>
To show a visual example of possible padding, here's an example memory block where requested_size == 8 and sizeof(void *) == sizeof(size_type) == 4:
<TABLE CELLSPACING="0" CELLPADDING="0" BORDER="3" STYLE="clear: both;" ALIGN=CENTER>
<CAPTION><EM>Memory block containing 4 chunks, showing overlying array structures; FLP = Interleaved Free List Pointer</EM></CAPTION>
<TR><TH>Sections<TH>size_type alignment<TH>void * alignment<TH>requested_size alignment
<TR><TD STYLE="background-color: red; text-align: center;" COLSPAN="4">Memory not belonging to process
<TR><TD STYLE="background-color: gray; text-align: center;" ROWSPAN="8">Chunks section (32 bytes)
<TD STYLE="background-color: gray; text-align: center;">(4 bytes)
<TD STYLE="background-color: gray; text-align: center;">FLP for Chunk 1 (4 bytes)
<TD STYLE="background-color: gray; text-align: center;" ROWSPAN="2">Chunk 1 (8 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(4 bytes)
<TD STYLE="background-color: silver; text-align: center;">(4 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(4 bytes)
<TD STYLE="background-color: gray; text-align: center;">FLP for Chunk 2 (4 bytes)
<TD STYLE="background-color: silver; text-align: center;" ROWSPAN="2">Chunk 2 (8 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(4 bytes)
<TD STYLE="background-color: silver; text-align: center;">(4 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(4 bytes)
<TD STYLE="background-color: gray; text-align: center;">FLP for Chunk 3 (4 bytes)
<TD STYLE="background-color: gray; text-align: center;" ROWSPAN="2">Chunk 3 (8 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(4 bytes)
<TD STYLE="background-color: silver; text-align: center;">(4 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(4 bytes)
<TD STYLE="background-color: gray; text-align: center;">FLP for Chunk 4 (4 bytes)
<TD STYLE="background-color: silver; text-align: center;" ROWSPAN="2">Chunk 4 (8 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(4 bytes)
<TD STYLE="background-color: silver; text-align: center;">(4 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">Pointer to next Block (4 bytes)
<TD STYLE="background-color: gray; text-align: center;">(4 bytes)
<TD STYLE="background-color: gray; text-align: center;">Pointer to next Block (4 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">Size of next Block (4 bytes)
<TD STYLE="background-color: silver; text-align: center;">Size of next Block (4 bytes)
<TR><TD STYLE="background-color: red; text-align: center;" COLSPAN="4">Memory not belonging to process
</TABLE>
<P>
Finally, here is a convoluted example where the requested_size is 7, sizeof(void *) == 3, and sizeof(size_type) == 5, showing how the least common multiple guarantees alignment requirements even in the oddest of circumstances:
<TABLE CELLSPACING="0" CELLPADDING="0" BORDER="3" STYLE="clear: both;" ALIGN=CENTER>
<CAPTION><EM>Memory block containing 2 chunks, showing overlying array structures</EM></CAPTION>
<TR><TH>Sections<TH>size_type alignment<TH>void * alignment<TH>requested_size alignment
<TR><TD STYLE="background-color: red; text-align: center;" COLSPAN="4">Memory not belonging to process
<!-- First Section -->
<TR><TD STYLE="background-color: gray; text-align: center;" ROWSPAN="42">Chunks section (210 bytes)
<TD STYLE="background-color: gray; text-align: center;">(5 bytes)
<TD STYLE="background-color: gray; text-align: center;" ROWSPAN="3">Interleaved free list pointer for Chunk 1 (15 bytes; 3 used)
<TD STYLE="background-color: gray; text-align: center;" ROWSPAN="21">Chunk 1 (105 bytes; 7 used)
<TR><TD STYLE="background-color: silver; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(5 bytes)
<TD STYLE="background-color: silver; text-align: center;" ROWSPAN="3">(15 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(5 bytes)
<TD STYLE="background-color: gray; text-align: center;" ROWSPAN="3">(15 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(5 bytes)
<TD STYLE="background-color: silver; text-align: center;" ROWSPAN="3">(15 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(5 bytes)
<TD STYLE="background-color: gray; text-align: center;" ROWSPAN="3">(15 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(5 bytes)
<TD STYLE="background-color: silver; text-align: center;" ROWSPAN="3">(15 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(5 bytes)
<TD STYLE="background-color: gray; text-align: center;" ROWSPAN="3">(15 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(5 bytes)
<TD STYLE="background-color: silver; text-align: center;" ROWSPAN="3">Interleaved free list pointer for Chunk 2 (15 bytes; 3 used)
<TD STYLE="background-color: silver; text-align: center;" ROWSPAN="21">Chunk 2 (105 bytes; 7 used)
<TR><TD STYLE="background-color: gray; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(5 bytes)
<TD STYLE="background-color: gray; text-align: center;" ROWSPAN="3">(15 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(5 bytes)
<TD STYLE="background-color: silver; text-align: center;" ROWSPAN="3">(15 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(5 bytes)
<TD STYLE="background-color: gray; text-align: center;" ROWSPAN="3">(15 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(5 bytes)
<TD STYLE="background-color: silver; text-align: center;" ROWSPAN="3">(15 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(5 bytes)
<TD STYLE="background-color: gray; text-align: center;" ROWSPAN="3">(15 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(5 bytes)
<TD STYLE="background-color: silver; text-align: center;" ROWSPAN="3">(15 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(5 bytes)
<!-- Second Section -->
<TR><TD STYLE="background-color: silver; text-align: center;" ROWSPAN="3">Pointer to next Block (15 bytes; 3 used)
<TD STYLE="background-color: gray; text-align: center;">(5 bytes)
<TD STYLE="background-color: gray; text-align: center;" ROWSPAN="3">Pointer to next Block (15 bytes; 3 used)
<TR><TD STYLE="background-color: silver; text-align: center;">(5 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(5 bytes)
<!-- Third Section -->
<TR><TD STYLE="background-color: gray; text-align: center;">Size of next Block (5 bytes; 5 used)
<TD STYLE="background-color: silver; text-align: center;">Size of next Block (5 bytes; 5 used)
<TR><TD STYLE="background-color: red; text-align: center;" COLSPAN="4">Memory not belonging to process
</TABLE>
<P>
<H2>How Contiguous Chunks are Handled</H2>
<P>
The theorem above guarantees all alignment requirements for allocating chunks and also implementation details such as the interleaved free list. However, it does so by adding padding when necessary; therefore, we have to treat allocations of contiguous chunks in a different way.
<P>
Using array arguments similar to the above, we can translate any request for contiguous memory for <EM>n</EM> objects of requested_size into a request for <EM>m</EM> contiguous chunks. <EM>m</EM> is simply ceil(n * requested_size / alloc_size), where alloc_size is the actual size of the chunks. To illustrate:
<P>
Here's an example memory block, where requested_size == 1 and sizeof(void *) == sizeof(size_type) == 4:
<TABLE CELLSPACING="0" CELLPADDING="0" BORDER="3" STYLE="clear: both;" ALIGN=CENTER>
<CAPTION><EM>Memory block containing 4 chunks; requested_size is 1</EM></CAPTION>
<TR><TH>Sections<TH>size_type alignment<TH>void * alignment<TH>requested_size alignment
<TR><TD STYLE="background-color: red; text-align: center;" COLSPAN="4">Memory not belonging to process
<TR><TD STYLE="background-color: gray; text-align: center;" ROWSPAN="4">Chunks section (16 bytes)
<TD STYLE="background-color: gray; text-align: center;">(4 bytes)
<TD STYLE="background-color: gray; text-align: center;">FLP to Chunk 2 (4 bytes)
<TD STYLE="background-color: gray; text-align: center;">Chunk 1 (4 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(4 bytes)
<TD STYLE="background-color: silver; text-align: center;">FLP to Chunk 3 (4 bytes)
<TD STYLE="background-color: silver; text-align: center;">Chunk 2 (4 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">(4 bytes)
<TD STYLE="background-color: gray; text-align: center;">FLP to Chunk 4 (4 bytes)
<TD STYLE="background-color: gray; text-align: center;">Chunk 3 (4 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(4 bytes)
<TD STYLE="background-color: silver; text-align: center;">FLP to end-of-list (4 bytes)
<TD STYLE="background-color: silver; text-align: center;">Chunk 4 (4 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">Pointer to next Block (4 bytes)
<TD STYLE="background-color: gray; text-align: center;">(4 bytes)
<TD STYLE="background-color: gray; text-align: center;">Ptr to end-of-list (4 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">Size of next Block (4 bytes)
<TD STYLE="background-color: silver; text-align: center;">0 (4 bytes)
<TR><TD STYLE="background-color: red; text-align: center;" COLSPAN="4">Memory not belonging to process
</TABLE>
<TABLE CELLSPACING="0" CELLPADDING="0" BORDER="3" STYLE="clear: both;" ALIGN=CENTER>
<CAPTION><EM>After user requests 7 contiguous elements of requested_size</EM></CAPTION>
<TR><TH>Sections<TH>size_type alignment<TH>void * alignment<TH>requested_size alignment
<TR><TD STYLE="background-color: red; text-align: center;" COLSPAN="4">Memory not belonging to process
<TR><TD STYLE="background-color: gray; text-align: center;" ROWSPAN="4">Chunks section (16 bytes)
<TD STYLE="background-color: gray; text-align: center;">(4 bytes)
<TD STYLE="background-color: gray; text-align: center;">(4 bytes)
<TD STYLE="background-color: gray; text-align: center;">4 bytes in use by program
<TR><TD STYLE="background-color: silver; text-align: center;">(4 bytes)
<TD STYLE="background-color: silver; text-align: center;">(4 bytes)
<TD STYLE="background-color: silver; text-align: center;">3 bytes in use by program (1 byte unused)
<TR><TD STYLE="background-color: gray; text-align: center;">(4 bytes)
<TD STYLE="background-color: gray; text-align: center;">FLP to Chunk 4 (4 bytes)
<TD STYLE="background-color: gray; text-align: center;">Chunk 3 (4 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">(4 bytes)
<TD STYLE="background-color: silver; text-align: center;">FLP to end-of-list (4 bytes)
<TD STYLE="background-color: silver; text-align: center;">Chunk 4 (4 bytes)
<TR><TD STYLE="background-color: silver; text-align: center;">Pointer to next Block (4 bytes)
<TD STYLE="background-color: gray; text-align: center;">(4 bytes)
<TD STYLE="background-color: gray; text-align: center;">Ptr to end-of-list (4 bytes)
<TR><TD STYLE="background-color: gray; text-align: center;">Size of next Block (4 bytes)
<TD STYLE="background-color: silver; text-align: center;">0 (4 bytes)
<TR><TD STYLE="background-color: red; text-align: center;" COLSPAN="4">Memory not belonging to process
</TABLE>
<P>
Then, when the user deallocates the contiguous memory, we can split it up into chunks again.
<P>
Note that the implementation provided for allocating contiguous chunks uses a linear instead of quadratic algorithm. This means that it <STRONG>may not find</STRONG> contiguous free chunks if the free list is not ordered. Thus, it is recommended to always use an ordered free list when dealing with contiguous allocation of chunks. (In the example above, if Chunk 1 pointed to Chunk 3 pointed to Chunk 2 pointed to Chunk 4, instead of being in order, the contiguous allocation algorithm would have failed to find any of the contiguous chunks).
<P>
<HR>
<P>
Copyright &copy; 2000, 2001 Stephen Cleary (<A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>)
<P>
This file can be redistributed and/or modified under the terms found in <A HREF="../copyright.html">copyright.html</A>
<P>
This software and its documentation is provided &quot;as is&quot; without express or implied warranty, and with no claim as to its suitability for any purpose.
</BODY>
</HTML>
+93
View File
@@ -0,0 +1,93 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>ct_gcd_lcm - Compile-Time GCD and LCM</TITLE>
<LINK HREF="../pool.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY>
<IMG SRC="../../../../c++boost.gif" WIDTH=276 HEIGHT=86 ALT="C++ Boost">
<H1 ALIGN=CENTER>ct_gcd_lcm - Compile-Time GCD and LCM</H1>
<P>
<H2>Introduction</H2>
<P>
detail/ct_gcd_lcm.hpp provides two compile-time algorithms: greatest common divisor and least common multiple.
<P>
<H2>Synopsis</H2>
<PRE CLASS="code">namespace details {
namespace pool {
template &lt;unsigned A, unsigned B&gt;
struct ct_gcd
{
static const unsigned value = ...;
};
template &lt;unsigned A, unsigned B&gt;
struct ct_lcm
{
static const unsigned value = ...;
};
} // namespace pool
} // namespace details</PRE>
<P>
<H2>Semantics</H2>
<TABLE ALIGN=CENTER BORDER>
<CAPTION><EM>Symbol Table</EM></CAPTION>
<TR><TH>Symbol<TH>Meaning</TR>
<TR><TD CLASS="code">A, B<TD>compile-time unsigned integer constants<A HREF="#5.19/1"><SUP>[5.19/1]</SUP></A></TR>
</TABLE>
<TABLE ALIGN=CENTER BORDER>
<CAPTION><EM>Semantics</EM></CAPTION>
<TR><TH>Expression<TH>Result Type<TH>Value<TH>Precondition
<TR><TD CLASS="code">ct_gcd&lt;A, B&gt;::value<TD>compile-time unsigned integer constant<TD>The greatest common divisor of <SPAN CLASS="code">A</SPAN> and <SPAN CLASS="code">B</SPAN><TD CLASS="code">A != 0 &amp;&amp; B != 0
<TR><TD CLASS="code">ct_lcm&lt;A, B&gt;::value<TD>compile-time unsigned integer constant<TD>The least common multiple of <SPAN CLASS="code">A</SPAN> and <SPAN CLASS="code">B</SPAN><TD CLASS="code">A != 0 &amp;&amp; B != 0
</TABLE>
<P>
<H2>Notes</H2>
<P>
Since these are compile-time algorithms, violation of the preconditions will result in a compile-time error.
<P>
<H2>Dependencies</H2>
<UL>
<LI>&quot;detail/postulate.hpp&quot; (see <A HREF="postulate.html">postulate.html</A>), to ensure preconditions are met.</LI>
</UL>
<P>
<H2>Selected Quotations from the Standard</H2>
<P>
<A NAME="5.19/1">
<STRONG>5.19/1: Expressions: Constant Expressions:</STRONG> &quot;. . . An <EM>integral constant expression</EM> can involve only literals (2.13), enumerators, <SPAN CLASS="code">const</SPAN> variables or static data members of integral or enumeration types initialized with constant expressions (8.5), non-type template parameters of integral or enumeration types, and <SPAN CLASS="code">sizeof</SPAN> expressions. Floating literals (2.13.3) can appear only if they are cast to integral or enumeration types. Only type conversions to integral or enumeration types can be used. In particular, except in <SPAN CLASS="code">sizeof</SPAN> expressions, functions, class objects, pointers, or references shall not be used, and assignment, increment, decrement, function-call, or comma operators shall not be used.&quot;</A>
<P>
<H2>Future Directions</H2>
<P>
This header may be replaced by a Boost compile-time algorithms library.
<P>
<HR>
<P>
Copyright &copy; 2000, 2001 Stephen Cleary (<A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>)
<P>
This file can be redistributed and/or modified under the terms found in <A HREF="../copyright.html">copyright.html</A>
<P>
This software and its documentation is provided &quot;as is&quot; without express or implied warranty, and with no claim as to its suitability for any purpose.
</BODY>
</HTML>
+75
View File
@@ -0,0 +1,75 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>for - m4 FOR Macro</TITLE>
<LINK HREF="../pool.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY>
<IMG SRC="../../../../c++boost.gif" WIDTH=276 HEIGHT=86 ALT="C++ Boost">
<H1 ALIGN=CENTER>for - m4 FOR Macro</H1>
<P>
<H2>Introduction</H2>
<P>
detail/for.m4 provides <SPAN CLASS="code">BOOST_M4_FOR</SPAN>, an <STRONG>m4</STRONG> macro that provides the equivalent of a <SPAN CLASS="code">#for</SPAN> preprocessor instruction.
<P>
<H2>Usage</H2>
<P>
This macro must be used by an <STRONG>m4</STRONG> file. This file assumes that the option <SPAN CLASS="code">-P</SPAN> is used, to force an <SPAN CLASS="code">m4_</SPAN> prefix on all builtin symbols.
<P>
<H2>Arguments</H2>
<OL>
<LI>The name of a variable to hold the current value.</LI>
<LI>The starting value of the variable.</LI>
<LI>The ending value of the variable.</LI>
<LI>The text to repeat. This text may contain references to the variable, which will be replaced with the variable's current value.</LI>
<LI>The delimeter text (optional).</LI>
</OL>
<P>
If called with the wrong number of arguments (less than 4 or more than 5), <SPAN CLASS="code">BOOST_M4_FOR</SPAN> will exit with an error. If the starting value (<SPAN CLASS="code">$2</SPAN>) is greater than or equal to the ending value (<SPAN CLASS="code">$3</SPAN>), <SPAN CLASS="code">BOOST_M4_FOR</SPAN> will do nothing. Otherwise, it will repeat the text (<SPAN CLASS="code">$4</SPAN>), binding the variable (<SPAN CLASS="code">$1</SPAN>) to the values in the range [starting value (<SPAN CLASS="code">$2</SPAN>), ending value (<SPAN CLASS="code">$3</SPAN>)), and repeat the delimeter text (<SPAN CLASS="code">$5</SPAN>) in-between each occurrence of the repeat text (<SPAN CLASS="code">$4</SPAN>).
<P>
<H2>Examples</H2>
<P>
Note of the quotation marks (<SPAN CLASS="m4">&quot;</SPAN>) used in the table below are in the input or output; they are shown to delimit whitespace. All code within a pair of quotation marks is intended to be on one line.
<P>
<TABLE BORDER ALIGN="center">
<TR><TH>Input<TH>Output</TR>
<TR><TD CLASS="m4">&quot;BOOST_M4_FOR(i, 1, 3)&quot;<TD>Boost m4 script: BOOST_M4_FOR: Wrong number of arguments (3)</TR>
<TR><TD CLASS="m4">&quot;BOOST_M4_FOR(i, 1, 3, i, ` ', 13)&quot;<TD>Boost m4 script: BOOST_M4_FOR: Wrong number of arguments (6)</TR>
<TR><TD CLASS="m4">&quot;BOOST_M4_FOR(i, 7, 0, i )&quot;<TD>(nothing)</TR>
<TR><TD CLASS="m4">&quot;BOOST_M4_FOR(i, 0, 0, i )&quot;<TD>(nothing)</TR>
<TR><TD CLASS="m4">&quot;BOOST_M4_FOR(i, 0, 7, i )&quot;<TD CLASS="m4">&quot;0 1 2 3 4 5 6 &quot;</TR>
<TR><TD CLASS="m4">&quot;BOOST_M4_FOR(i, -13, -10, i )&quot;<TD CLASS="m4">&quot;-13 -12 -11 &quot;</TR>
<TR><TD CLASS="m4">&quot;BOOST_M4_FOR(i, 0, 8, BOOST_M4_FOR(j, 0, 4, (i, j) )&quot;<BR>&quot;)&quot;<TD CLASS="m4">&quot;(0, 0) (0, 1) (0, 2) (0, 3) &quot;<BR>&quot;(1, 0) (1, 1) (1, 2) (1, 3) &quot;<BR>&quot;(2, 0) (2, 1) (2, 2) (2, 3) &quot;<BR>&quot;(3, 0) (3, 1) (3, 2) (3, 3) &quot;<BR>&quot;(4, 0) (4, 1) (4, 2) (4, 3) &quot;<BR>&quot;(5, 0) (5, 1) (5, 2) (5, 3) &quot;<BR>&quot;(6, 0) (6, 1) (6, 2) (6, 3) &quot;<BR>&quot;(7, 0) (7, 1) (7, 2) (7, 3) &quot;<BR>&quot;&quot;</TR>
<TR><TD CLASS="m4">&quot;BOOST_M4_FOR(i, 7, 0, i, |)&quot;<TD>(nothing)</TR>
<TR><TD CLASS="m4">&quot;BOOST_M4_FOR(i, 0, 0, i, |)&quot;<TD>(nothing)</TR>
<TR><TD CLASS="m4">&quot;BOOST_M4_FOR(i, 0, 7, i, |)&quot;<TD CLASS="m4">&quot;0|1|2|3|4|5|6&quot;</TR>
<TR><TD CLASS="m4">&quot;BOOST_M4_FOR(i, -13, -10, i, `, ')&quot;<TD CLASS="m4">&quot;-13, -12, -11&quot;</TR>
<TR><TD CLASS="m4">&quot;BOOST_M4_FOR(i, 0, 8, `[BOOST_M4_FOR(j, 0, 4, (i, j), `, ')]', `,&quot;<BR>&quot;')&quot;<TD CLASS="m4">&quot;[(0, 0), (0, 1), (0, 2), (0, 3)],&quot;<BR>&quot;[(1, 0), (1, 1), (1, 2), (1, 3)],&quot;<BR>&quot;[(2, 0), (2, 1), (2, 2), (2, 3)],&quot;<BR>&quot;[(3, 0), (3, 1), (3, 2), (3, 3)],&quot;<BR>&quot;[(4, 0), (4, 1), (4, 2), (4, 3)],&quot;<BR>&quot;[(5, 0), (5, 1), (5, 2), (5, 3)],&quot;<BR>&quot;[(6, 0), (6, 1), (6, 2), (6, 3)],&quot;<BR>&quot;[(7, 0), (7, 1), (7, 2), (7, 3)]&quot;</TR>
</TABLE>
<P>
<HR>
<P>
Copyright &copy; 2000, 2001 Stephen Cleary (<A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>)
<P>
This file can be redistributed and/or modified under the terms found in <A HREF="../copyright.html">copyright.html</A>
<P>
This software and its documentation is provided &quot;as is&quot; without express or implied warranty, and with no claim as to its suitability for any purpose.
</BODY>
</HTML>
+81
View File
@@ -0,0 +1,81 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>gcd_lcm - GCD and LCM</TITLE>
<LINK HREF="../pool.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY>
<IMG SRC="../../../../c++boost.gif" WIDTH=276 HEIGHT=86 ALT="C++ Boost">
<H1 ALIGN=CENTER>gcd_lcm - GCD and LCM</H1>
<P>
<H2>Introduction</H2>
<P>
detail/gcd_lcm.hpp provides two generic integer algorithms: greatest common divisor and least common multiple.
<P>
<H2>Synopsis</H2>
<PRE CLASS="code">namespace details {
namespace pool {
template &lt;typename Integer&gt;
Integer gcd(Integer A, Integer B);
template &lt;typename Integer&gt;
Integer lcm(Integer A, Integer B);
} // namespace pool
} // namespace details</PRE>
<P>
<H2>Semantics</H2>
<TABLE ALIGN=CENTER BORDER>
<CAPTION><EM>Symbol Table</EM></CAPTION>
<TR><TH>Symbol<TH>Meaning</TR>
<TR><TD CLASS="code">Integer<TD>An integral type</TR>
<TR><TD CLASS="code">A, B<TD>Values of type <SPAN CLASS="code">Integer</SPAN></TR>
</TABLE>
<TABLE ALIGN=CENTER BORDER>
<CAPTION><EM>Semantics</EM></CAPTION>
<TR><TH>Expression<TH>Result Type<TH>Precondition<TH>Notes
<TR><TD CLASS="code">gcd(A, B)<TD>Integer<TD CLASS="code">A &gt; 0 &amp;&amp; B &gt; 0<TD>Returns the greatest common divisor of <SPAN CLASS="code">A</SPAN> and <SPAN CLASS="code">B</SPAN>
<TR><TD CLASS="code">lcm(A, B)<TD>Integer<TD CLASS="code">A &gt; 0 &amp;&amp; B &gt; 0<TD>Returns the least common multiple of <SPAN CLASS="code">A</SPAN> and <SPAN CLASS="code">B</SPAN>
</TABLE>
<P>
<H2>Implementation Notes</H2>
<P>
For faster results, ensure <SPAN CLASS="code">A &gt; B</SPAN>
<P>
<H2>Dependencies</H2>
<P>
None.
<P>
<H2>Future Directions</H2>
<P>
This header may be replaced by a Boost algorithms library.
<P>
<HR>
<P>
Copyright &copy; 2000, 2001 Stephen Cleary (<A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>)
<P>
This file can be redistributed and/or modified under the terms found in <A HREF="../copyright.html">copyright.html</A>
<P>
This software and its documentation is provided &quot;as is&quot; without express or implied warranty, and with no claim as to its suitability for any purpose.
</BODY>
</HTML>
+111
View File
@@ -0,0 +1,111 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>guard - Auto-lock/unlock-er</TITLE>
<LINK HREF="../pool.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY>
<IMG SRC="../../../../c++boost.gif" WIDTH=276 HEIGHT=86 ALT="C++ Boost">
<H1 ALIGN=CENTER>guard - Auto-lock/unlock-er</H1>
<P>
<H2>Introduction</H2>
<P>
detail/guard.hpp provides a type <SPAN CLASS="code">guard&lt;Mutex&gt;</SPAN> that allows scoped access to the <SPAN CLASS="code">Mutex</SPAN>'s locking and unlocking operations. It is used to ensure that a <SPAN CLASS="code">Mutex</SPAN> is unlocked, even if an exception is thrown.
<P>
<H2>Synopsis</H2>
<PRE CLASS="code">namespace details {
namespace pool {
template &lt;typename Mutex&gt;
class guard
{
private:
guard(const guard &amp;);
void operator=(const guard &amp;);
public:
explicit guard(Mutex &amp; mtx);
~guard();
};
} // namespace pool
} // namespace details</PRE>
<P>
<H2>Semantics</H2>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Symbol Table</EM></CAPTION>
<TR><TH>Symbol<TH>Meaning
<TR><TD CLASS="code">T<TD><SPAN CLASS="code">guard&lt;Mutex&gt;</SPAN>
<TR><TD CLASS="code">m<TD>value of type <SPAN CLASS="code">Mutex &amp;</SPAN>
<TR><TD CLASS="code">g<TD>value of type <SPAN CLASS="code">guard&lt;Mutex&gt;</SPAN>
</TABLE>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Requirements on <SPAN CLASS="code">Mutex</SPAN></EM></CAPTION>
<TR><TH>Expression<TH>Return Type<TH>Assertion/Note/Pre/Post-Condition
<TR><TD CLASS="code">m.lock()<TD>not used<TD>Locks the mutex referred to by <SPAN CLASS="code">m</SPAN>
<TR><TD CLASS="code">m.unlock()<TD>not used<TD>Unlocks the mutex referred to by <SPAN CLASS="code">m</SPAN>
</TABLE>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Requirements satisfied by <SPAN CLASS="code">guard</SPAN></EM></CAPTION>
<TR><TH>Expression<TH>Assertion/Note/Pre/Post-Condition
<TR><TD CLASS="code">T(m)<TD>Locks the mutex referred to by <SPAN CLASS="code">m</SPAN>; binds <SPAN CLASS="code">T(m)</SPAN> to <SPAN CLASS="code">m</SPAN>
<TR><TD CLASS="code">(&amp;g)->~T()<TD>Unlocks the mutex that <SPAN CLASS="code">g</SPAN> is bound to
</TABLE>
<P>
<H2>Example</H2>
<P>
Given a (platform-specific) <SPAN CLASS="code">mutex</SPAN> class, we can wrap code as follows:
<PRE CLASS="code">extern mutex global_lock;
static void f()
{
boost::details::pool::guard&lt;mutex&gt; g(global_lock);
// g's constructor locks &quot;global_lock&quot;
... // do anything:
// throw exceptions
// return
// or just fall through
} // g's destructor unlocks &quot;global_lock&quot;</PRE>
<P>
<H2>Dependencies</H2>
<P>
None.
<P>
<H2>Future Directions</H2>
<P>
This header will eventually be replaced by a Boost multithreading library.
<P>
<HR>
<P>
Copyright &copy; 2000, 2001 Stephen Cleary (<A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>)
<P>
This file can be redistributed and/or modified under the terms found in <A HREF="../copyright.html">copyright.html</A>
<P>
This software and its documentation is provided &quot;as is&quot; without express or implied warranty, and with no claim as to its suitability for any purpose.
</BODY>
</HTML>
+129
View File
@@ -0,0 +1,129 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>mutex - Mutex</TITLE>
<LINK HREF="../pool.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY>
<IMG SRC="../../../../c++boost.gif" WIDTH=276 HEIGHT=86 ALT="C++ Boost">
<H1 ALIGN=CENTER>mutex - Mutex</H1>
<P>
<H2>Introduction</H2>
<P>
detail/mutex.hpp provides several mutex types that provide a consistent interface for OS-supplied mutex types. These are all thread-level mutexes; interprocess mutexes are not supported.
<P>
<H2>Configuration</H2>
<P>
This header file will try to guess what kind of system it is on. It will auto-configure itself for Win32 or POSIX+pthread systems. To stub out all mutex code, bypassing the auto-configuration, <SPAN CLASS="code">#define BOOST_NO_MT</SPAN> before any inclusion of this header. To prevent ODR violations, this should be defined in <STRONG>every</STRONG> translation unit in your project, including any library files.
<P>
<H2>Synopsis</H2>
<PRE CLASS="code">namespace details {
namespace pool {
// Only present if on a Win32 system
class Win32_mutex
{
private:
Win32_mutex(const Win32_mutex &amp;);
void operator=(const Win32_mutex &amp;);
public:
Win32_mutex();
~Win32_mutex();
void lock();
void unlock();
};
// Only present if on a POSIX+pthread system
class pthread_mutex
{
private:
pthread_mutex(const pthread_mutex &amp;);
void operator=(const pthread_mutex &amp;);
public:
pthread_mutex();
~pthread_mutex();
void lock();
void unlock();
};
// Present on all systems
class null_mutex
{
private:
null_mutex(const null_mutex &amp;);
void operator=(const null_mutex &amp;);
public:
null_mutex();
~null_mutex();
static void lock();
static void unlock();
};
// This will be one of the types above
typedef ... default_mutex;
} // namespace pool
} // namespace details</PRE>
<P>
<H2>Semantics</H2>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Symbol Table</EM></CAPTION>
<TR><TH>Symbol<TH>Meaning
<TR><TD CLASS="code">Mutex<TD>Any type defined in this header
<TR><TD CLASS="code">t<TD>value of type <SPAN CLASS="code">Mutex</SPAN>
</TABLE>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Requirements satisfied by <SPAN CLASS="code">mutex</SPAN></EM></CAPTION>
<TR><TH>Expression<TH>Return Type<TH>Assertion/Note/Pre/Post-Condition
<TR><TD CLASS="code">m.lock()<TD>not used<TD>Locks the mutex
<TR><TD CLASS="code">m.unlock()<TD>not used<TD>Unlocks the mutex
</TABLE>
<P>
Each mutex is always either owned or unowned. If owned, then it is owned by a particular thread. To &quot;lock&quot; a mutex means to wait until the mutex is unowned, and then make it owned by the current thread. To &quot;unlock&quot; a mutex means to release ownership from the current thread (note that the current thread <STRONG>must</STRONG> own the mutex to release that ownership!). As a special case, the <SPAN CLASS="code">null_mutex</SPAN> never waits.
<P>
<H2>Dependencies</H2>
<P>
May include the system headers <SPAN CLASS="code">&lt;windows.h&gt;</SPAN>, <SPAN CLASS="code">&lt;unistd.h&gt;</SPAN>, and/or <SPAN CLASS="code">&lt;pthread.h&gt;</SPAN>.
<P>
<H2>Future Directions</H2>
<P>
This header will eventually be replaced by a Boost multithreading library.
<P>
<HR>
<P>
Copyright &copy; 2000, 2001 Stephen Cleary (<A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>)
<P>
This file can be redistributed and/or modified under the terms found in <A HREF="../copyright.html">copyright.html</A>
<P>
This software and its documentation is provided &quot;as is&quot; without express or implied warranty, and with no claim as to its suitability for any purpose.
</BODY>
</HTML>
+70
View File
@@ -0,0 +1,70 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>Object Pool Implementation</TITLE>
<LINK HREF="../pool.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY>
<IMG SRC="../../../../c++boost.gif" WIDTH=276 HEIGHT=86 ALT="C++ Boost">
<H1 ALIGN=CENTER>Object Pool Implementation</H1>
<P>
<H2>Dependencies</H2>
<P>
Includes the Boost header <SPAN CLASS="code">&quot;pool.hpp&quot;</SPAN> (see <A HREF="pool.html">pool.html</A>).
<P>
<H2>Extensions to Public Interface</H2>
<P>
Whenever an object of type <SPAN CLASS="code">ObjectPool</SPAN> needs memory from the system, it will request it from its <SPAN CLASS="code">UserAllocator</SPAN> template parameter. The amount requested is determined using a doubling algorithm; that is, each time more system memory is allocated, the amount of system memory requested is doubled. Users may control the doubling algorithm by using the following extensions.
<P>
<H3>Additional constructor parameter</H3>
<P>
Users may pass an additional constructor parameter to <SPAN CLASS="code">ObjectPool</SPAN>. This parameter is of type <SPAN CLASS="code">size_type</SPAN>, and is the number of chunks to request from the system the first time that object needs to allocate system memory. The default is 32. This parameter may not be 0.
<P>
<H3><SPAN CLASS="code">next_size</SPAN> accessor functions</H3>
<P>
The pair of functions <SPAN CLASS="code">size_type get_next_size() const;</SPAN> and <SPAN CLASS="code">void set_next_size(size_type);</SPAN> allow users to explicitly read and write the <SPAN CLASS="code">next_size</SPAN> value. This value is the number of chunks to request from the system the next time that object needs to allocate system memory. This value should never be set to 0.
<P>
<H2>Protected Interface</H2>
<P>
<H3>Synopsis</H3>
<PRE CLASS="code">template &lt;typename ElementType, typename UserAllocator = default_user_allocator_new_delete&gt;
class object_pool: protected pool&lt;UserAllocator&gt;
{
... // public interface
};</PRE>
<P>
<H3>Protected Derivation</H3>
ObjectPool derives from a simple segregated storage via protected derivation; this exposes all the <A HREF="pool.html">Pool implementation details</A> to all classes derived from ObjectPool as well.
<P>
<H2><A HREF="../interfaces/object_pool.html">Interface Description</A></H2>
<P>
<HR>
<P>
Copyright &copy; 2000, 2001 Stephen Cleary (<A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>)
<P>
This file can be redistributed and/or modified under the terms found in <A HREF="../copyright.html">copyright.html</A>
<P>
This software and its documentation is provided &quot;as is&quot; without express or implied warranty, and with no claim as to its suitability for any purpose.
</BODY>
</HTML>
+216
View File
@@ -0,0 +1,216 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>Pool Implementation</TITLE>
<LINK HREF="../pool.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY>
<IMG SRC="../../../../c++boost.gif" WIDTH=276 HEIGHT=86 ALT="C++ Boost">
<H1 ALIGN=CENTER>Pool Implementation</H1>
<P>
<H2>Dependencies</H2>
<P>
Includes the system headers <SPAN CLASS="code">&lt;functional&gt;</SPAN>, <SPAN CLASS="code">&lt;new&gt;</SPAN>, <SPAN CLASS="code">&lt;cstddef&gt;</SPAN>, <SPAN CLASS="code">&lt;cstdlib&gt;</SPAN>, and <SPAN CLASS="code">&lt;exception&gt;</SPAN>.
<P>
Includes the Boost headers <SPAN CLASS="code">&quot;detail/ct_gcd_lcm.hpp&quot;</SPAN> (see <A HREF="ct_gcd_lcm.html">ct_gcd_lcm.html</A>), <SPAN CLASS="code">&quot;detail/gcd_lcm.hpp&quot;</SPAN> (see <A HREF="gcd_lcm.html">gcd_lcm.html</A>), and <SPAN CLASS="code">&quot;simple_segregated_storage.hpp&quot;</SPAN> (see <A HREF="simple_segregated_storage.html">simple_segregated_storage.html</A>).
<P>
<H2>Synopsis</H2>
<PRE CLASS="code">namespace details {
template &lt;typename SizeType&gt;
class PODptr
{
public:
typedef SizeType size_type;
PODptr(char * ptr, size_type size);
PODptr();
// Copy constructor, assignment operator, and destructor allowed
bool valid() const;
void invalidate();
char * & begin();
char * begin() const;
char * end() const;
size_type total_size() const;
size_type element_size() const;
size_type & next_size() const;
char * & next_ptr() const;
PODptr next() const;
void next(const PODptr & arg) const;
};
} // namespace details
template &lt;typename UserAllocator = default_user_allocator_new_delete&gt;
class pool: protected simple_segregated_storage&lt;typename UserAllocator::size_type&gt;
{
... // public interface
protected:
details::PODptr&lt;size_type&gt; list;
simple_segregated_storage&lt;size_type&gt; & store();
const simple_segregated_storage&lt;size_type&gt; & store() const;
const size_type requested_size;
size_type next_size;
details::PODptr&lt;size_type&gt; find_POD(void * chunk) const;
static bool is_from(void * chunk, char * i, size_type sizeof_i);
size_type alloc_size() const;
public: // extensions to public interface
pool(size_type requested_size, size_type next_size);
size_type get_next_size() const;
void set_next_size(size_type);
};</PRE>
<P>
<H2>Extensions to Public Interface</H2>
<P>
Whenever an object of type <SPAN CLASS="code">pool</SPAN> needs memory from the system, it will request it from its <SPAN CLASS="code">UserAllocator</SPAN> template parameter. The amount requested is determined using a doubling algorithm; that is, each time more system memory is allocated, the amount of system memory requested is doubled. Users may control the doubling algorithm by using the following extensions.
<P>
<H3>Additional constructor parameter</H3>
<P>
Users may pass an additional constructor parameter to <SPAN CLASS="code">pool</SPAN>. This parameter is of type <SPAN CLASS="code">size_type</SPAN>, and is the number of chunks to request from the system the first time that object needs to allocate system memory. The default is 32. This parameter may not be 0.
<P>
<H3><SPAN CLASS="code">next_size</SPAN> accessor functions</H3>
<P>
The pair of functions <SPAN CLASS="code">size_type get_next_size() const;</SPAN> and <SPAN CLASS="code">void set_next_size(size_type);</SPAN> allow users to explicitly read and write the <SPAN CLASS="code">next_size</SPAN> value. This value is the number of chunks to request from the system the next time that object needs to allocate system memory. This value should never be set to 0.
<P>
<H2>Class <SPAN CLASS="code">PODptr</SPAN></H2>
<P>
<SPAN CLASS="code">PODptr</SPAN> is a class that pretends to be a &quot;pointer&quot; to different class types that don't really exist. It provides member functions to access the &quot;data&quot; of the &quot;object&quot; it points to. Since these &quot;class&quot; types are of differing sizes, and contain some information at the end of their memory (for alignment reasons), <SPAN CLASS="code">PODptr</SPAN> must contain the size of this &quot;class&quot; as well as the pointer to this &quot;object&quot;.
<P>
A <SPAN CLASS="code">PODptr</SPAN> holds the location and size of a memory block allocated from the system. Each memory block is split logically into three sections:
<OL>
<LI>Chunk area. This section may be different sizes. <SPAN CLASS="code">PODptr</SPAN> does not care what the size of the chunks is, but it does care (and keep track of) the total size of the chunk area.</LI>
<LI>Next pointer. This section is always the same size for a given <SPAN CLASS="code">SizeType</SPAN>. It holds a pointer to the location of the next memory block in the memory block list, or 0 if there is no such block.</LI>
<LI>Next size. This section is always the same size for a given <SPAN CLASS="code">SizeType</SPAN>. It holds the size of the next memory block in the memory block list.</LI>
</OL>
<P>
The <SPAN CLASS="code">PODptr</SPAN> class just provides cleaner ways of dealing with raw memory blocks.
<P>
<H3>Validity</H3>
<P>
A <SPAN CLASS="code">PODptr</SPAN> object is either <EM>valid</EM> or <EM>invalid</EM>. An invalid <SPAN CLASS="code">PODptr</SPAN> is analogous to a null pointer.
<P>
The default constructor for <SPAN CLASS="code">PODptr</SPAN> will result in an invalid object. Calling the member function <SPAN CLASS="code">invalidate</SPAN> will result in that object becoming invalid. The member function <SPAN CLASS="code">valid</SPAN> can be used to test for validity.
<P>
<H3>Getting <SPAN CLASS="code">PODptr</SPAN> objects</H3>
<P>
A <SPAN CLASS="code">PODptr</SPAN> may be created to point to a memory block by passing the address and size of that memory block into the constructor. A <SPAN CLASS="code">PODptr</SPAN> constructed in this way is valid.
<P>
A <SPAN CLASS="code">PODptr</SPAN> may also be created by a call to the member function <SPAN CLASS="code">next</SPAN>, which returns a <SPAN CLASS="code">PODptr</SPAN> which points to the next memory block in the memory block list, or an invalid <SPAN CLASS="code">PODptr</SPAN> if there is no such block.
<P>
<H3>Accessing the &quot;pointer&quot; data</H3>
<P>
Each <SPAN CLASS="code">PODptr</SPAN> keeps the address and size of its memory block. The address may be read or written by the member functions <SPAN CLASS="code">begin</SPAN>. The size of the memory block may only be read, and is done so by the member function <SPAN CLASS="code">total_size</SPAN>.
<P>
<H3>Accessing the sections of the memory block</H3>
<P>
The chunk area may be accessed by the member functions <SPAN CLASS="code">begin</SPAN> and <SPAN CLASS="code">end</SPAN>, in conjunction with <SPAN CLASS="code">element_size</SPAN>. The value returned by <SPAN CLASS="code">end</SPAN> is always the value returned by <SPAN CLASS="code">begin</SPAN> plus <SPAN CLASS="code">element_size</SPAN>. Only <SPAN CLASS="code">begin</SPAN> is writeable. <SPAN CLASS="code">end</SPAN> is a past-the-end value; using pointers beginning at <SPAN CLASS="code">begin</SPAN> and ending before <SPAN CLASS="code">end</SPAN> allows one to iterate through the chunks in a memory block.
<P>
The next pointer area may be accessed by the member function <SPAN CLASS="code">next_ptr</SPAN>. The next size area may be accessed by the member function <SPAN CLASS="code">next_size</SPAN>. Both of these are writeable. They may both be read or set at the same time through the member function <SPAN CLASS="code">next</SPAN>.
<P>
<H2>Protected Interface</H2>
<P>
<H3>Protected Derivation</H3>
Pool derives from a simple segregated storage via protected derivation; this exposes all the <A HREF="simple_segregated_storage.html">simple segregated storage implementation details</A> to all classes derived from Pool as well.
<P>
<H3 CLASS="code">details::PODptr&lt;size_type&gt; list;</H3>
<P>
This is the list of memory blocks that have been allocated by this Pool object. It is <STRONG>not</STRONG> the same as the list of free memory chunks (exposed by simple segregated storage as <SPAN CLASS="code">first</SPAN>).
<P>
<H3><SPAN CLASS="code">store</SPAN> functions</H3>
<P>
These are convenience functions, used to return the base simple segregated storage object.
<P>
<H3 CLASS="code">const size_type requested_size;</H3>
<P>
The first argument passed into the constructor. Represents the number of bytes in each chunk requested by the user. The actual size of the chunks may be different; see <SPAN CLASS="code">alloc_size</SPAN>, below.
<P>
<H3 CLASS="code">size_type next_size</H3>
<P>
The number of chunks to request from the <SPAN CLASS="code">UserAllocator</SPAN> the next time we need to allocate system memory. See the extensions descriptions, above.
<P>
<H3 CLASS="code">details::PODptr&lt;size_type&gt; find_POD(void * chunk) const;</H3>
<P>
Searches through the memory block list, looking for the block that <SPAN CLASS="code">chunk</SPAN> was allocated from or may be allocated from in the future. Returns that block if found, or an invalid value if <SPAN CLASS="code">chunk</SPAN> has been allocated from another Pool or may be allocated from another Pool in the future. Results for other values of <SPAN CLASS="code">chunk</SPAN> may be wrong.
<P>
<H3 CLASS="code">static bool is_from(void * chunk, char * i, size_type sizeof_i);</H3>
<P>
Tests <SPAN CLASS="code">chunk</SPAN> to see if it has been allocated from the memory chunk at <SPAN CLASS="code">i</SPAN> with an element size of <SPAN CLASS="code">sizeof_i</SPAN>. Note that <SPAN CLASS="code">sizeof_i</SPAN> is the size of the chunk area of that block, not the total size of that block.
<P>
Returns <SPAN CLASS="code">true</SPAN> if <SPAN CLASS="code">chunk</SPAN> has been allocated from that memory block or may be allocated from that block in the future. Returns <SPAN CLASS="code">false</SPAN> if <SPAN CLASS="code">chunk</SPAN> has been allocated from another block or may be allocated from another block in the future. Results for other values of <SPAN CLASS="code">chunk</SPAN> may be wrong.
<P>
<H3 CLASS="code">size_type alloc_size() const;</H3>
<P>
Returns the calculated size of the memory chunks that will be allocated by this Pool. For <A HREF="alignment.html">alignment reasons</A>, this is defined to be <SPAN CLASS="code">lcm(requested_size, sizeof(void *), sizeof(size_type))</SPAN>.
<P>
<H2><A HREF="../interfaces/pool.html">Interface Description</A></H2>
<P>
<HR>
<P>
Copyright &copy; 2000, 2001 Stephen Cleary (<A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>)
<P>
This file can be redistributed and/or modified under the terms found in <A HREF="../copyright.html">copyright.html</A>
<P>
This software and its documentation is provided &quot;as is&quot; without express or implied warranty, and with no claim as to its suitability for any purpose.
</BODY>
</HTML>
+127
View File
@@ -0,0 +1,127 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>pool_alloc - Boost Pool Standard Allocators Implementation</TITLE>
<LINK HREF="../pool.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY>
<IMG SRC="../../../../c++boost.gif" WIDTH=276 HEIGHT=86 ALT="C++ Boost">
<H1 ALIGN=CENTER>pool_alloc - Boost Pool Standard Allocators Implementation</H1>
<P>
<H2>Dependencies</H2>
<P>
Includes the system headers <SPAN CLASS="code">&lt;new&gt;</SPAN> and <SPAN CLASS="code">&lt;limits&gt;</SPAN>.
<P>
Includes the Boost headers <SPAN CLASS="code">&quot;singleton_pool.hpp&quot;</SPAN> (see <A HREF="singleton_pool.html">singleton_pool.html</A>) and <SPAN CLASS="code">&quot;detail/mutex.hpp&quot;</SPAN> (see <A HREF="mutex.html">mutex.html</A>).
<P>
<H2>Synopsis</H2>
<PRE CLASS="code">template &lt;typename T,
typename UserAllocator = default_user_allocator_new_delete,
typename Mutex = details::pool::default_mutex,
unsigned NextSize = 32&gt;
class pool_allocator
{
public:
... // public interface
public: // extensions to public interface
typedef Mutex mutex;
static const unsigned next_size = NextSize;
template &lt;typename U&gt;
struct rebind
{
typedef pool_allocator&lt;U, UserAllocator, Mutex, NextSize&gt; other;
};
};
template &lt;typename T,
typename UserAllocator = default_user_allocator_new_delete,
typename Mutex = details::pool::default_mutex,
unsigned NextSize = 32&gt;
class fast_pool_allocator
{
public:
... // public interface
public: // extensions to public interface
typedef Mutex mutex;
static const unsigned next_size = NextSize;
template &lt;typename U&gt;
struct rebind
{
typedef fast_pool_allocator&lt;U, UserAllocator, Mutex, NextSize&gt; other;
};
};</PRE>
<P>
<H2>Extensions to Public Interface</H2>
<P>
<H3>Additional template parameters</H3>
<P>
<H4 CLASS="code">Mutex</H4>
<P>
This parameter allows the user to determine the type of synchronization to be used on the underlying singleton pool. See the extensions to the public interface of <A HREF="singleton_pool.html">singleton pool</A> for more information.
<P>
<H4 CLASS="code">NextSize</H4>
<P>
The value of this parameter is passed to the underlying Pool when it is created. See the extensions to the public interface of <A HREF="pool.html">pool</A> for more information.
<P>
<H3>Modification of <SPAN CLASS="code">rebind</SPAN></H3>
<P>
The struct <SPAN CLASS="code">rebind</SPAN> has been redefined to preserve the values of the additional template parameters.
<P>
<H3>Additional members</H3>
<P>
The typedef <SPAN CLASS="code">mutex</SPAN> and the static const value <SPAN CLASS="code">next_size</SPAN> publish the values of the template parameters <SPAN CLASS="code">Mutex</SPAN> and <SPAN CLASS="code">NextSize</SPAN>, respectively.
<P>
<H2>Notes</H2>
<P>
A number of common STL libraries contain bugs in their using of allocators. Specifically, they pass null pointers to the <SPAN CLASS="code">deallocate</SPAN> function, which is explicitly forbidden by the Standard [20.1.5 Table 32]. PoolAlloc will work around these libraries if it detects them; currently, workarounds are in place for:
<UL>
<LI>Borland C++ (Builder and command-line compiler) with default (RogueWave) library, ver. 5 and earlier</LI>
<LI>STLport (with any compiler), ver. 4.0 and earlier</LI>
</UL>
<P>
<H2>Future Directions</H2>
<P>
When the Boost multithreading library is completed, the <SPAN CLASS="code">Mutex</SPAN> parameter will be replaced by something from that library providing the same flexibility and will move from an implementation detail into the interface specification.
<P>
<H2><A HREF="../interfaces/pool_alloc.html">Interface Description</A></H2>
<P>
<HR>
<P>
Copyright &copy; 2000, 2001 Stephen Cleary (<A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>)
<P>
This file can be redistributed and/or modified under the terms found in <A HREF="../copyright.html">copyright.html</A>
<P>
This software and its documentation is provided &quot;as is&quot; without express or implied warranty, and with no claim as to its suitability for any purpose.
</BODY>
</HTML>
+62
View File
@@ -0,0 +1,62 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>Object Pool Constructors Generator</TITLE>
<LINK HREF="../pool.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY>
<IMG SRC="../../../../c++boost.gif" WIDTH=276 HEIGHT=86 ALT="C++ Boost">
<H1 ALIGN=CENTER>Object Pool Constructors Generator</H1>
<P>
<H2>Description</H2>
<P>
The template class <SPAN CLASS="code">object_pool</SPAN> (see <A HREF="object_pool.html">object_pool.html</A>) contains a number of functions <SPAN CLASS="code">construct(..)</SPAN>, which both allocate and construct an object in a single operation.
<P>
Since the number and type of arguments to this function is totally arbitrary, a simple system has been set up to automatically generate template <SPAN CLASS="code">construct</SPAN> functions. This system is based on the macro preprocessor <STRONG>m4</STRONG>, which is standard on UNIX systems and also available for Win32 systems.
<P>
detail/pool_construct.m4, when run with <STRONG>m4</STRONG>, will create the file detail/pool_construct.inc, which only defines the <SPAN CLASS="code">construct</SPAN> functions for the proper number of arguments. The number of arguments may be passed into the file as an m4 macro, <SPAN CLASS="code">NumberOfArguments</SPAN>; if not provided, it will default to <SPAN CLASS="code">3</SPAN>.
<P>
For each different number of arguments (<SPAN CLASS="code">1</SPAN> to <SPAN CLASS="code">NumberOfArguments</SPAN>), a template function is generated. There are the same number of template parameters as there are arguments, and each argument's type is a reference to that (possibly cv-qualified) template argument. Each possible permutation of the cv-qualifications is also generated.
<P>
Because each permutation is generated for each possible number of arguments, the included file size grows exponentially in terms of the number of constructor arguments, not linearly. For the sake of rational compile times, only use as many arguments as you need.
<P>
detail/pool_construct.bat and detail/pool_construct.sh are also provided to call <STRONG>m4</STRONG>, defining <SPAN CLASS="code">NumberOfArguments</SPAN> to be their command-line parameter. See these files for more details.
<P>
<H2>Dependencies</H2>
<P>
Dependent on for.m4 (see <A HREF="for.html">for.html</A>).
<P>
<H2>Future Directions</H2>
<P>
This system may be complemented by or replaced by a Python (or some other language) script.
<P>
<H2><A HREF="../interfaces/object_pool.html">Interface Description</A></H2>
<P>
<HR>
<P>
Copyright &copy; 2000, 2001 Stephen Cleary (<A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>)
<P>
This file can be redistributed and/or modified under the terms found in <A HREF="../copyright.html">copyright.html</A>
<P>
This software and its documentation is provided &quot;as is&quot; without express or implied warranty, and with no claim as to its suitability for any purpose.
</BODY>
</HTML>
+129
View File
@@ -0,0 +1,129 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>postulate - Compile-Time Assertion</TITLE>
<LINK HREF="../pool.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY>
<IMG SRC="../../../../c++boost.gif" WIDTH=276 HEIGHT=86 ALT="C++ Boost">
<H1 ALIGN=CENTER>postulate - Compile-Time Assertion</H1>
<P>
<H2>Introduction</H2>
<P>
detail/postulate.hpp provides a macro that can be used to test compile-time boolean conditions. This macro, <SPAN CLASS="code">BOOST_POOL_POSTULATE</SPAN>, takes one parameter, which is the condition to test. It will fail to compile if that condition is false. Any integral constant expression <A HREF="#5.19/1"><SUP>[5.19/1]</SUP></A> may be used as the condition, which includes expressions dependent on template arguments.
<P>
<SPAN CLASS="code">BOOST_POOL_POSTULATE</SPAN> may be used at namespace scope, class scope, or function scope. It may <STRONG>not</STRONG> be used anywhere else; for example, inside of parameter lists. For templates, the postulate is tested when the template is instantiated. It may not be used more than once per line; multiple tests must be placed on separate lines.
<P>
If the condition is false, the compiler will trigger an error at the place where the postulate macro is used. For this reason, it is often suggested that a comment be placed on the line before the postulate to explain why it is necessary.
<P>
This file also provides a macro, <SPAN CLASS="code">BOOST_POOL_JOIN</SPAN>, which merges two preprocessor tokens <STRONG>after</STRONG> macro substitution. (The <SPAN CLASS="code">##</SPAN> preprocessor operator merges them <STRONG>before</STRONG> macro substitution).
<P>
<H2>Examples</H2>
<P>
One of the simplest examples is to ensure that we are running on a 32-bit platform:
<PRE CLASS="code">// This code is only valid on a 32-bit platform
BOOST_POOL_POSTULATE(sizeof(int) * CHAR_BIT == 32);</PRE>
<P>
Or, for more portable code, to ensure that we are running on a 2's complement platform:
<PRE CLASS="code">// This code must run on a 2's complement platform
BOOST_POOL_POSTULATE(~1 + 1 == -1);</PRE>
<P>
More complicated usage allows arbitrary restrictions on template arguments:
<PRE CLASS="code">template &lt;int x, int y&gt;
struct EmmaWoodhouse
{
// The following tests are not actually tested until
// EmmaWoodhouse&lt;X, Y&gt; is instantiated for some X and Y
// x has to be &gt;= 13 because . . .
BOOST_POOL_POSTULATE(x &gt;= 13);
// y has to be &gt; x because . . .
BOOST_POOL_POSTULATE(y &gt; x);
. . .
};</PRE>
<P>
<H2>Symbols</H2>
<P>
<UL>
<LI>BOOST_POOL_POSTULATE (macro)</LI>
<LI>BOOST_POOL_JOIN (macro)</LI>
</UL>
<P>
<H2>Notes</H2>
<P>
No compile-time assertion mechanism is perfect. However, each one should attempt to satisfy the following requirements:
<OL>
<LI>Basics
<DL>
<DT>Can use compile-time constants<DD>It can use anything that the compiler can figure out at compile time, using the same rules as those for array sizes, not the more restrictive rules of the preprocessor.
<DT>Stop with error<DD>With a false expression it will prevent the program from compiling, causing an an error.
<DT>Portable<DD>It will work on any conforming compiler (uses only things in the standard).
<DT>Practical<DD>It will work on currently available compilers.
<DT>Efficient<DD>No real code should be generated and no storage should be used. Using it has no cost or effect on the program other than preventing it from compiling -- it doesn't change optimizations, sizes of structures, or anything like that.
</DL></LI><LI>Error Message
<DL>
<DT>Error on correct line<DD>Give an error message <STRONG>at the line</STRONG> where the assertion fails. The line that the compiler reports an error on will be the line of the assertion statement.
<DT>Good error message<DD>The error message will be easy to understand on any compiler.
</DL></LI><LI>Usage
<DL>
<DT>Universal syntax<DD>Usable in both declarations and implementations in the same way. It can be used inside a function definition or outside a function definition, inside a class declaration or outside a class declaration.
<DT>Simple syntax<DD>It can be called in a simple way, similar to assert.
<DT>Robust syntax<DD>Won't silently fail on simple coding errors.
</DL></LI><LI>Namespace pollution
<DL>
<DT>Minimal pollution<DD>Scopes should be polluted in a minimal way.
<DT>Macro avoidance<DD>Since macros pollute <STRONG>every</STRONG> scope, they should be avoided.
</DL></LI></OL>
<P>
The search for a good compile-time postulate has been going on for years. This solution is the result of the combined effort of at least: John Maddock, Darin Adler, Jay Zipnick, Beman Dawes, and Csaba Szepesvari. In particular, John Maddock was the person who first formulated this particular solution; whereas Csaba Szepesvari, Darin Adler, and Beman Dawes are responsible for the requirements. Jay Zipnick is responsible for the name &quot;postualte.&quot;
<P>
<H2>Dependencies</H2>
<P>
None.
<P>
<H2>Selected Quotations from the Standard</H2>
<P>
<A NAME="5.19/1">
<STRONG>5.19/1: Expressions: Constant Expressions:</STRONG> &quot;. . . An <EM>integral constant expression</EM> can involve only literals (2.13), enumerators, <SPAN CLASS="code">const</SPAN> variables or static data members of integral or enumeration types initialized with constant expressions (8.5), non-type template parameters of integral or enumeration types, and <SPAN CLASS="code">sizeof</SPAN> expressions. Floating literals (2.13.3) can appear only if they are cast to integral or enumeration types. Only type conversions to integral or enumeration types can be used. In particular, except in <SPAN CLASS="code">sizeof</SPAN> expressions, functions, class objects, pointers, or references shall not be used, and assignment, increment, decrement, function-call, or comma operators shall not be used.&quot;</A>
<P>
<H2>Future Directions</H2>
<P>
This header will soon be replaced by the Boost static assert library.
<P>
<HR>
<P>
Copyright &copy; 2000, 2001 Stephen Cleary (<A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>)
<P>
This file can be redistributed and/or modified under the terms found in <A HREF="../copyright.html">copyright.html</A>
<P>
This software and its documentation is provided &quot;as is&quot; without express or implied warranty, and with no claim as to its suitability for any purpose.
</BODY>
</HTML>
@@ -0,0 +1,76 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>Simple Segregated Storage Implementation</TITLE>
<LINK HREF="../pool.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY>
<IMG SRC="../../../../c++boost.gif" WIDTH=276 HEIGHT=86 ALT="C++ Boost">
<H1 ALIGN=CENTER>Simple Segregated Storage Implementation</H1>
<P>
<H2>Dependencies</H2>
<P>
Includes the system headers <SPAN CLASS="code">&lt;cstddef&gt;</SPAN> and <SPAN CLASS="code">&lt;functional&gt;</SPAN>.
<P>
<H2>Protected Interface</H2>
<P>
<H3>Synopsis</H3>
<PRE CLASS="code">template &lt;typename SizeType = std::size_t&gt;
class simple_segregated_storage
{
... // Public interface
protected:
void * first;
static void * & nextof(void * const ptr);
void * find_prev(void * ptr);
};</PRE>
<P>
<H3 CLASS="code">void * first;</H3>
<P>
This data member is the free list. It points to the first chunk in the free list, or is equal to 0 if the free list is empty.
<P>
<H3 CLASS="code">static void * & nextof(void * const ptr);</H3>
<P>
This is a convenience function. It helps clean up code dealing with the free list by making it more readable. The return value is just <SPAN CLASS="code">*ptr</SPAN> cast to the appropriate type. <SPAN CLASS="code">ptr</SPAN> must not be 0.
<P>
As an example, let us assume that we want to truncate the free list after the first chunk. That is, we want to set <SPAN CLASS="code">*first</SPAN> to 0; this will result in a free list with only one entry. The normal way to do this is to first cast <SPAN CLASS="code">first</SPAN> to a pointer to a pointer to void, and then dereference and assign (<SPAN CLASS="code">*static_cast&lt;void **&gt;(first) = 0;</SPAN>). This can be done more easily through the use of this convenience function (<SPAN CLASS="code">nextof(first) = 0;</SPAN>).
<P>
<H3 CLASS="code">void * find_prev(void * ptr);</H3>
<P>
Traverses the free list referred to by <SPAN CLASS="code">first</SPAN>, and returns the pointer previous to where <SPAN CLASS="code">ptr</SPAN> would go if it was in the free list. Returns 0 if <SPAN CLASS="code">ptr</SPAN> would go at the beginning of the free list (i.e., before <SPAN CLASS="code">first</SPAN>).
<P>
Note that this function finds the location previous to where <SPAN CLASS="code">ptr</SPAN> <STRONG>would</STRONG> go <STRONG>if it was</STRONG> in the free list. It does <STRONG>not</STRONG> find the entry in the free list before <SPAN CLASS="code">ptr</SPAN> (unless <SPAN CLASS="code">ptr</SPAN> is already in the free list). Specifically, <SPAN CLASS="code">find_prev(0)</SPAN> will return 0, <STRONG>not</STRONG> the last entry in the free list.
<P>
<H2><A HREF="../interfaces/simple_segregated_storage.html">Interface Description</A></H2>
<P>
<HR>
<P>
Copyright &copy; 2000, 2001 Stephen Cleary (<A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>)
<P>
This file can be redistributed and/or modified under the terms found in <A HREF="../copyright.html">copyright.html</A>
<P>
This software and its documentation is provided &quot;as is&quot; without express or implied warranty, and with no claim as to its suitability for any purpose.
</BODY>
</HTML>
+94
View File
@@ -0,0 +1,94 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>singleton - Singleton</TITLE>
<LINK HREF="../pool.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY>
<IMG SRC="../../../../c++boost.gif" WIDTH=276 HEIGHT=86 ALT="C++ Boost">
<H1 ALIGN=CENTER>singleton - Singleton</H1>
<P>
<H2>Introduction</H2>
<P>
detail/singleton.hpp provides a way to access a Singleton of a class type. This is <STRONG>not</STRONG> a general Singleton solution! It is restricted in that the class type must have a default constructor.
<P>
<H2>Synopsis</H2>
<PRE CLASS="code">namespace details {
namespace pool {
template &lt;typename T&gt;
class singleton_default
{
private:
singleton_default();
public:
typedef T object_type;
static object_type & instance();
};
} // namespace pool
} // namespace details</PRE>
<P>
<H2>Semantics</H2>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Symbol Table</EM></CAPTION>
<TR><TH>Symbol<TH>Meaning
<TR><TD CLASS="code">T<TD>Any class with a non-throwing default constructor and non-throwing destructor
</TABLE>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Requirements satisfied by <SPAN CLASS="code">singleton_default&lt;T&gt;</SPAN></EM></CAPTION>
<TR><TH>Expression<TH>Return Type<TH>Assertion/Note/Pre/Post-Condition
<TR><TD CLASS="code">singleton_default&lt;T&gt;::instance()<TD CLASS="code">T &amp;<TD>Returns a reference to the singleton instance
</TABLE>
<P>
<H2>Guarantees</H2>
<P>
The singleton instance is guaranteed to be constructed before <SPAN CLASS="code">main()</SPAN> begins, and destructed after <SPAN CLASS="code">main()</SPAN> ends. Furthermore, it is guaranteed to be constructed before the first call to <SPAN CLASS="code">singleton_default&lt;T&gt;::instance()</SPAN> is complete (even if called before <SPAN CLASS="code">main()</SPAN> begins). Thus, if there are not multiple threads running except within <SPAN CLASS="code">main()</SPAN>, and if all access to the singleton is restricted by mutexes, then this guarantee allows a thread-safe singleton.
<P>
<H2>Details</H2>
<P>
For details on how we provide the guarantees above, see the comments in the header file.
<P>
<H2>Dependencies</H2>
<P>
None.
<P>
<H2>Future Directions</H2>
<P>
This header may be replaced by a Boost singleton library.
<P>
<HR>
<P>
Copyright &copy; 2000, 2001 Stephen Cleary (<A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>)
<P>
This file can be redistributed and/or modified under the terms found in <A HREF="../copyright.html">copyright.html</A>
<P>
This software and its documentation is provided &quot;as is&quot; without express or implied warranty, and with no claim as to its suitability for any purpose.
</BODY>
</HTML>
+82
View File
@@ -0,0 +1,82 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>Singleton Pool Implementation</TITLE>
<LINK HREF="../pool.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY>
<IMG SRC="../../../../c++boost.gif" WIDTH=276 HEIGHT=86 ALT="C++ Boost">
<H1 ALIGN=CENTER>Singleton Pool Implementation</H1>
<P>
<H2>Dependencies</H2>
<P>
Includes the Boost headers <SPAN CLASS="code">&quot;pool.hpp&quot;</SPAN> (see <A HREF="pool.html">pool.html</A>), <SPAN CLASS="code">&quot;detail/singleton.hpp&quot;</SPAN> (see <A HREF="singleton.html">singleton.html</A>), <SPAN CLASS="code">&quot;detail/mutex.hpp&quot;</SPAN> (see <A HREF="mutex.html">mutex.html</A>), and <SPAN CLASS="code">&quot;detail/guard.hpp&quot;</SPAN> (see <A HREF="guard.html">guard.html</A>).
<P>
<H2>Synopsis</H2>
<PRE CLASS="code">template &lt;typename Tag,
unsigned RequestedSize,
typename UserAllocator = default_user_allocator_new_delete,
typename Mutex = details::pool::default_mutex,
unsigned NextSize = 32&gt;
class singleton_pool
{
... // public interface
public: // extensions to public interface
typedef Mutex mutex;
static const unsigned next_size = NextSize;
};</PRE>
<P>
<H2>Extensions to Public Interface</H2>
<P>
<H3>Additional template parameters</H3>
<P>
<H4 CLASS="code">Mutex</H4>
<P>
This class is the type of <A HREF="mutex.html">mutex</A> to use to protect simultaneous access to the underlying Pool. It is exposed so that users may declare some singleton pools normally (i.e., with synchronization), but some singleton pools without synchronization (by specifying <SPAN CLASS="code">details::pool::null_mutex</SPAN>) for efficiency reasons.
<P>
<H4 CLASS="code">NextSize</H4>
<P>
The value of this parameter is passed to the underlying Pool when it is created. See the extensions to the public interface of <A HREF="pool.html">pool</A> for more information.
<P>
<H3>Additional members</H3>
<P>
The typedef <SPAN CLASS="code">mutex</SPAN> and the static const value <SPAN CLASS="code">next_size</SPAN> publish the values of the template parameters <SPAN CLASS="code">Mutex</SPAN> and <SPAN CLASS="code">NextSize</SPAN>, respectively.
<P>
<H2>Future Directions</H2>
<P>
When the Boost multithreading library is completed, the <SPAN CLASS="code">Mutex</SPAN> parameter will be replaced by something from that library providing the same flexibility and will move from an implementation detail into the interface specification.
<P>
<H2><A HREF="../interfaces/singleton_pool.html">Interface Description</A></H2>
<P>
<HR>
<P>
Copyright &copy; 2000, 2001 Stephen Cleary (<A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>)
<P>
This file can be redistributed and/or modified under the terms found in <A HREF="../copyright.html">copyright.html</A>
<P>
This software and its documentation is provided &quot;as is&quot; without express or implied warranty, and with no claim as to its suitability for any purpose.
</BODY>
</HTML>
+155
View File
@@ -0,0 +1,155 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>Boost Pool Library</TITLE>
<LINK HREF="pool.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY>
<IMG SRC="../../../c++boost.gif" WIDTH=276 HEIGHT=86 ALT="C++ Boost">
<H1 ALIGN=CENTER>Boost Pool Library</H1>
<P>
<H2>Introduction</H2>
<P>
<H3>What is Pool?</H3>
<P>
Pool allocation is a memory allocation scheme that is very fast, but limited in its usage. For more information on pool allocation (also called &quot;simple segregated storage&quot;), see <A HREF="concepts.html">the concepts document</A>.
<P>
<H3>Why should I use Pool?</H3>
<P>
Using Pools gives you more control over how memory is used in your program. For example, you could have a situation where you want to allocate a bunch of small objects at one point, and then reach a point in your program where none of them are needed any more. Using pool interfaces, you can choose to run their destructors or just drop them off into oblivion; the pool interface will guarantee that there are no system memory leaks.
<P>
<H3>When should I use Pool?</H3>
<P>
Pools are generally used when there is a lot of allocation and deallocation of small objects. Another common usage is the situation above, where many objects may be dropped out of memory.
<P>
In general, use Pools when you need a more efficient way to do unusual memory control.
<P>
<H3>How do I use Pool?</H3>
<P>
See the <A HREF="interfaces.html">pool interfaces document</A>, which covers the different Pool interfaces supplied by this library.
<P>
<H2>Library Structure and Dependencies</H2>
<P>
Each exposed library header <EM>xxx</EM>.hpp has a corresponding header <EM>xxx</EM>_fwd.hpp, which contains forward declarations of each exposed library symbol of that header.
<P>
The library may use macros, which will be prefixed with <SPAN CLASS="code">BOOST_POOL_</SPAN>. The exception to this rule are the include file guards, which (for file <EM>xxx</EM>.hpp) is <SPAN CLASS="code">BOOST_<EM>xxx</EM>_HPP</SPAN>.
<P>
All exposed symbols defined by the library will be in namespace <SPAN CLASS="code">boost</SPAN>. All symbols used only by the implementation will be in namespace <SPAN CLASS="code">boost::details::pool</SPAN>.
<P>
Every header used only by the implementation is in the subdirectory <SPAN CLASS="code">detail/</SPAN>.
<P>
Any header in the library may include any other header in the library or any system-supplied header at its discretion.
<P>
<H2>Installation</H2>
<P>
The Boost Pool library is a header file library. That means there is no .lib, .dll, or .so to build; just add the Boost directory to your compiler's include file path, and you should be good to go!
<P>
<H2>Building the Test Programs</H2>
<P>
The subdirectory &quot;build&quot; contains subdirectories for several different platforms. These subdirectories contain all necessary work-around code for that platform, as well as makefiles or IDE project files as appropriate.
<P>
Read the &quot;readme.txt&quot; in the proper subdirectory, if it exists.
<P>
The standard makefile targets are &quot;all&quot;, &quot;clean&quot; (which deletes any intermediate files), and &quot;veryclean&quot; (which deletes any intermediate files and executables). All intermediate and executable files are built in the same directory as the makefile/project file. If there is a project file supplied instead of a makefile, &quot;clean&quot; and &quot;veryclean&quot; shell scripts/batch files will be provided.
<P>
Project files and makefiles for additional platforms may be sent to Stephen Cleary at <A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>.
<P>
<H2>Documentation Map</H2>
<UL>
<LI>Overview of Pooling
<UL>
<LI><A HREF="concepts.html">concepts.html</A> - The basic ideas behind pooling.</LI>
<LI><A HREF="implementation/alignment.html">implementation/alignment.html</A> - How we guarantee alignment portably.</LI>
<LI><A HREF="interfaces.html">interfaces.html</A> - What interfaces are provided and when to use each one.</LI>
</UL>
</LI>
<LI>Pool Exposed Interfaces
<UL>
<LI><A HREF="interfaces/simple_segregated_storage.html">interfaces/simple_segregated_storage.html</A> - Not for the faint of heart; embedded programmers only.</LI>
<LI><A HREF="interfaces/pool.html">interfaces/pool.html</A> - The basic pool interface.</LI>
<LI><A HREF="interfaces/singleton_pool.html">interfaces/singleton_pool.html</A> - The basic pool interface as a thread-safe singleton.</LI>
<LI><A HREF="interfaces/object_pool.html">interfaces/object_pool.html</A> - A type-oriented (instead of size-oriented) pool interface.</LI>
<LI><A HREF="interfaces/pool_alloc.html">interfaces/pool_alloc.html</A> - A Standard Allocator pool interface based on singleton_pool.</LI>
<LI><A HREF="interfaces/user_allocator.html">interfaces/user_allocator.html</A> - OK, not a pool interface, but it describes how the user can control how Pools allocate system memory.</LI>
</UL>
</LI>
<LI>Pool Implementation Details and Extensions
<UL>
<LI>Interface Implementations and Extensions
<UL>
<LI><A HREF="implementation/simple_segregated_storage.html">implementation/simple_segregated_storage.html</A></LI>
<LI><A HREF="implementation/pool.html">implementation/pool.html</A></LI>
<LI><A HREF="implementation/singleton_pool.html">implementation/singleton_pool.html</A></LI>
<LI><A HREF="implementation/object_pool.html">implementation/object_pool.html</A></LI>
<LI><A HREF="implementation/pool_alloc.html">implementation/pool_alloc.html</A></LI>
</UL>
</LI>
<LI>Components Used Only by the Implementation
<UL>
<LI><A HREF="implementation/ct_gcd_lcm.html">implementation/ct_gcd_lcm.html</A> - Compile-time GCD and LCM.</LI>
<LI><A HREF="implementation/for.html">implementation/for.html</A> - Description of an m4 component.</LI>
<LI><A HREF="implementation/gcd_lcm.html">implementation/gcd_lcm.html</A> - Run-time GCD and LCM.</LI>
<LI><A HREF="implementation/guard.html">implementation/guard.html</A> - Auto lock/unlock for mutex.</LI>
<LI><A HREF="implementation/mutex.html">implementation/mutex.html</A> - Platform-dependent mutex type.</LI>
<LI><A HREF="implementation/pool_construct.html">implementation/pool_construct.html</A> - The system for supporting more constructor arguments in object_pool.</LI>
<LI><A HREF="implementation/postulate.html">implementation/postulate.html</A> - Compile-time assertion.</LI>
<LI><A HREF="implementation/singleton.html">implementation/singleton.html</A> - Singleton that avoids static initialization problem.</LI>
</UL>
</LI>
</UL>
</LI>
</UL>
<P>
<H2>Future Directions</H2>
<P>
Another pool interface will be written: a base class for per-class pool allocation.
<P>
<H2>Acknowledgements</H2>
<P>
Many, many thanks to the Boost peers, notably Jeff Garland, Beman Dawes, Ed Brey, Gary Powell, Peter Dimov, and Jens Maurer for providing helpful suggestions!
<P>
<HR>
<P>
Copyright &copy; 2000, 2001 Stephen Cleary (<A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>)
<P>
This file can be redistributed and/or modified under the terms found in <A HREF="copyright.html">copyright.html</A>
<P>
This software and its documentation is provided &quot;as is&quot; without express or implied warranty, and with no claim as to its suitability for any purpose.
</BODY>
</HTML>
+137
View File
@@ -0,0 +1,137 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>Boost Pool Interfaces</TITLE>
<LINK HREF="pool.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY>
<IMG SRC="../../../c++boost.gif" WIDTH=276 HEIGHT=86 ALT="C++ Boost">
<H1 ALIGN=CENTER>Boost Pool Interfaces</H1>
<P>
<H2>Introduction</H2>
<P>
There are several interfaces provided which allow users great flexibility in how they want to use Pools. Review the <A HREF="concepts.html">concepts document</A> to get the basic understanding of how Pools work.
<P>
<H2>Terminology and Tradeoffs</H2>
<P>
<H3>Object Usage vs. Singleton Usage</H3>
<P>
<EM>Object Usage</EM> is the method where each Pool is an object that may be created and destroyed. Destroying a Pool implicitly frees all chunks that have been allocated from it.
<P>
<EM>Singleton Usage</EM> is the method where each Pool is an object with static duration; that is, it will not be destroyed until program exit. Pool objects with Singleton Usage may be shared; thus, Singleton Usage implies thread-safety as well. System memory allocated by Pool objects with Singleton Usage may be freed through <SPAN CLASS="code">release_memory</SPAN> or <SPAN CLASS="code">purge_memory</SPAN>.
<P>
<H3>Out-of-Memory Conditions: Exceptions vs. Null Return</H3>
<P>
Some Pool interfaces throw exceptions when out-of-memory; others will return 0. In general, unless mandated by the Standard, Pool interfaces will always prefer to return 0 instead of throw an exception.
<P>
<H2>The Interfaces</H2>
<P>
<H3>pool</H3>
<P>
The <A HREF="interfaces/pool.html">pool interface</A> is a simple Object Usage interface with Null Return.
<P>
Example:
<PRE CLASS="code">void func()
{
boost::pool&lt;&gt; p(sizeof(int));
for (int i = 0; i < 10000; ++i)
{
int * const t = p.malloc();
... // Do something with t; don't take the time to free() it
}
} // on function exit, p is destroyed, and all malloc()'ed ints are implicitly freed</PRE>
<P>
<H3>object_pool</H3>
<P>
The <A HREF="interfaces/object_pool.html">object_pool interface</A> is an Object Usage interface with Null Return, but is aware of the type of the object for which it is allocating chunks. On destruction, any chunks that have been allocated from that object_pool will have their destructors called.
<P>
Example:
<PRE CLASS="code">struct X { ... }; // has destructor with side-effects
void func()
{
boost::object_pool&lt;X&gt; p;
for (int i = 0; i < 10000; ++i)
{
X * const t = p.malloc();
... // Do something with t; don't take the time to free() it
}
} // on function exit, p is destroyed, and all destructors for the X objects are called</PRE>
<P>
<H3>singleton_pool</H3>
<P>
The <A HREF="interfaces/singleton_pool.html">singleton_pool interface</A> is a Singleton Usage interface with Null Return. It's just the same as the pool interface but with Singleton Usage instead.
<P>
Example:
<PRE CLASS="code">struct MyPoolTag { };
typedef boost::singleton_pool&lt;MyPoolTag, sizeof(int)&gt; my_pool;
void func()
{
for (int i = 0; i < 10000; ++i)
{
int * const t = my_pool::malloc();
... // Do something with t; don't take the time to free() it
}
// Explicitly free all malloc()'ed int's
my_pool::purge_memory();
}</PRE>
<P>
<H3>pool_alloc</H3>
<P>
The <A HREF="interfaces/pool_alloc.html">pool_alloc interface</A> is a Singleton Usage interface with Exceptions. It is built on the singleton_pool interface, and provides a Standard Allocator-compliant class (for use in containers, etc.).
<P>
Example:
<PRE CLASS="code">void func()
{
std::vector&lt;int, boost::pool_allocator&lt;int&gt; &gt; v;
for (int i = 0; i < 10000; ++i)
v.push_back(13);
} // Exiting the function does NOT free the system memory allocated by the pool allocator
// You must call
// boost::singleton_pool&lt;boost::pool_allocator_tag, sizeof(int)&gt;::release_memory()
// in order to force that</PRE>
<P>
<H2>Future Directions</H2>
<P>
Another pool interface will be written: a base class for per-class pool allocation. This &quot;pool_base&quot; interface will be Singleton Usage with Exceptions, and built on the singleton_pool interface.
<P>
<HR>
<P>
Copyright &copy; 2000, 2001 Stephen Cleary (<A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>)
<P>
This file can be redistributed and/or modified under the terms found in <A HREF="copyright.html">copyright.html</A>
<P>
This software and its documentation is provided &quot;as is&quot; without express or implied warranty, and with no claim as to its suitability for any purpose.
</BODY>
</HTML>
+128
View File
@@ -0,0 +1,128 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>object_pool - Boost Object Pool Allocator</TITLE>
<LINK HREF="../pool.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY>
<IMG SRC="../../../../c++boost.gif" WIDTH=276 HEIGHT=86 ALT="C++ Boost">
<H1 ALIGN=CENTER>object_pool - Boost Object Pool Allocator</H1>
<P>
<H2>Introduction</H2>
<P>
object_pool.hpp provides a template type that can be used for fast and efficient memory allocation. It also provides automatic destruction of non-deallocated objects. For information on other pool-based interfaces, see <A HREF="../interfaces.html">the other pool interfaces</A>.
<P>
<H2>Synopsis</H2>
<PRE CLASS="code">template &lt;typename ElementType, typename UserAllocator = default_user_allocator_new_delete&gt;
class object_pool
{
private:
object_pool(const object_pool &amp;);
void operator=(const object_pool &amp;);
public:
typedef ElementType element_type;
typedef UserAllocator user_allocator;
typedef typename pool&lt;UserAllocator&gt;::size_type size_type;
typedef typename pool&lt;UserAllocator&gt;::difference_type difference_type;
object_pool();
~object_pool();
element_type * malloc();
void free(element_type * p);
bool is_from(element_type * p) const;
element_type * construct();
// other construct() functions
void destroy(element_type * p);
};</PRE>
<P>
<H2>Template Parameters</H2>
<P>
<H3>ElementType</H3>
<P>
The template parameter is the type of object to allocate/deallocate. It must have a non-throwing destructor.
<P>
<H3>UserAllocator</H3>
<P>
Defines the method that the underlying Pool will use to allocate memory from the system. See <A HREF="user_allocator.html">User Allocators</A> for details.
<P>
<H2>Semantics</H2>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Symbol Table</EM></CAPTION>
<TR><TH>Symbol<TH>Meaning
<TR><TD CLASS="code">ObjectPool<TD><SPAN CLASS="code">object_pool&lt;ElementType, UserAllocator&gt;</SPAN>
<TR><TD CLASS="code">t<TD>value of type <SPAN CLASS="code">ObjectPool</SPAN>
<TR><TD CLASS="code">u<TD>value of type <SPAN CLASS="code">const ObjectPool</SPAN>
<TR><TD CLASS="code">p<TD>value of type <SPAN CLASS="code">ElementType *</SPAN>
</TABLE>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Typedefs</EM></CAPTION>
<TR><TH>Expression<TH>Type
<TR><TD CLASS="code">ObjectPool::element_type<TD CLASS="code">ElementType
<TR><TD CLASS="code">ObjectPool::user_allocator<TD CLASS="code">UserAllocator
<TR><TD CLASS="code">ObjectPool::size_type<TD CLASS="code">pool&lt;UserAllocator&gt;::size_type
<TR><TD CLASS="code">ObjectPool::difference_type<TD CLASS="code">pool&lt;UserAllocator&gt;::difference_type
</TABLE>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Constructors, Destructors, and Testing</EM></CAPTION>
<TR><TH>Expression<TH>Return Type<TH>Notes
<TR><TD CLASS="code">ObjectPool()<TD>not used<TD>Constructs a new empty <SPAN CLASS="code">ObjectPool</SPAN>
<TR><TD CLASS="code">(&amp;t)->~ObjectPool()<TD>not used<TD>Destructs the <SPAN CLASS="code">ObjectPool</SPAN>; <SPAN CLASS="code">~ElementType()</SPAN> is called for each allocated ElementType that has not been deallocated. O(N).
<TR><TD CLASS="code">u.is_from(p)<TD CLASS="code">bool<TD>Returns <SPAN CLASS="code">true</SPAN> if <SPAN CLASS="code">p</SPAN> was allocated from <SPAN CLASS="code">u</SPAN> or may be returned as the result of a future allocation from <SPAN CLASS="code">u</SPAN>. Returns <SPAN CLASS="code">false</SPAN> if <SPAN CLASS="code">p</SPAN> was allocated from some other pool or may be returned as the result of a future allocation from some other pool. Otherwise, the return value is meaningless; note that this function may <STRONG>not</STRONG> be used to reliably test random pointer values.
</TABLE>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Allocation and Deallocation</EM></CAPTION>
<TR><TH>Expression<TH>Return Type<TH>Pre-Condition<TH>Semantic Equivalence<TH>Notes
<TR><TD CLASS="code">t.malloc()<TD CLASS="code">ElementType *<TD><TD><TD>Allocates memory that can hold an object of type <SPAN CLASS="code">ElementType</SPAN>. If out of memory, returns <SPAN CLASS="code">0</SPAN>. Amortized O(1).
<TR><TD CLASS="code">t.free(p)<TD>not used<TD><SPAN CLASS="code">p</SPAN> must have been previously allocated from <SPAN CLASS="code">t</SPAN><TD><TD>Deallocates a chunk of memory. Note that <SPAN CLASS="code">p</SPAN> may not be <SPAN CLASS="code">0</SPAN>. Note that the destructor for <SPAN CLASS="code">p</SPAN> is not called. O(N).
<TR><TD CLASS="code">t.construct(???)<TD CLASS="code">ElementType *<TD><SPAN CLASS="code">ElementType</SPAN> must have a constructor matching <SPAN CLASS="code">???</SPAN>; the number of parameters given must not exceed what is supported through <A HREF="../implementation/pool_construct.html">pool_construct</A><TD><TD>Allocates and initializes an object of type <SPAN CLASS="code">ElementType</SPAN>. If out of memory, returns <SPAN CLASS="code">0</SPAN>. Amortized O(1).
<TR><TD CLASS="code">t.destroy(p)<TD>not used<TD><SPAN CLASS="code">p</SPAN> must have been previously allocated from <SPAN CLASS="code">t</SPAN><TD CLASS="code">p->~ElementType(); t.free(p);<TD>
</TABLE>
<P>
<H2>Symbols</H2>
<P>
<UL>
<LI>boost::object_pool</LI>
</UL>
<P>
<H2><A HREF="../implementation/object_pool.html">Implementation Details</A></H2>
<P>
<HR>
<P>
Copyright &copy; 2000, 2001 Stephen Cleary (<A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>)
<P>
This file can be redistributed and/or modified under the terms found in <A HREF="../copyright.html">copyright.html</A>
<P>
This software and its documentation is provided &quot;as is&quot; without express or implied warranty, and with no claim as to its suitability for any purpose.
</BODY>
</HTML>
+143
View File
@@ -0,0 +1,143 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>Pool</TITLE>
<LINK HREF="../pool.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY>
<IMG SRC="../../../../c++boost.gif" WIDTH=276 HEIGHT=86 ALT="C++ Boost">
<H1 ALIGN=CENTER>Pool</H1>
<P>
<H2>Introduction</H2>
<P>
<SPAN CLASS="code">pool</SPAN> is a fast memory allocator, and guarantees proper alignment of all allocated chunks.
<P>
pool.hpp provides two <A HREF="user_allocator.html">UserAllocator</A> classes and a template class <SPAN CLASS="code">pool</SPAN>, which extends and generalizes the framework provided by the <A HREF="simple_segregated_storage.html">simple segregated storage</A> solution. For information on other pool-based interfaces, see <A HREF="../interfaces.html">the other pool interfaces</A>.
<P>
<H2>Synopsis</H2>
<PRE CLASS="code">struct default_user_allocator_new_delete; // see <A HREF="user_allocator.html">User Allocators</A>
struct default_user_allocator_malloc_free; // see <A HREF="user_allocator.html">User Allocators</A>
template &lt;typename UserAllocator = default_user_allocator_new_delete&gt;
class pool
{
private:
pool(const pool &amp;);
void operator=(const pool &amp;);
public:
typedef UserAllocator user_allocator;
typedef typename UserAllocator::size_type size_type;
typedef typename UserAllocator::difference_type difference_type;
explicit pool(size_type requested_size);
~pool();
bool release_memory();
bool purge_memory();
bool is_from(void * chunk) const;
size_type get_requested_size() const;
void * malloc();
void * ordered_malloc();
void * ordered_malloc(size_type n);
void free(void * chunk);
void ordered_free(void * chunk);
void free(void * chunks, size_type n);
void ordered_free(void * chunks, size_type n);
};</PRE>
<P>
<H2>Template Parameters</H2>
<P>
<H3>UserAllocator</H3>
<P>
Defines the method that the Pool will use to allocate memory from the system. See <A HREF="user_allocator.html">User Allocators</A> for details.
<P>
<H2>Semantics</H2>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Symbol Table</EM></CAPTION>
<TR><TH>Symbol<TH>Meaning
<TR><TD CLASS="code">Pool<TD CLASS="code">pool&lt;UserAllocator&gt;
<TR><TD CLASS="code">t<TD>value of type <SPAN CLASS="code">Pool</SPAN>
<TR><TD CLASS="code">u<TD>value of type <SPAN CLASS="code">const Pool</SPAN>
<TR><TD CLASS="code">chunk<TD>value of type <SPAN CLASS="code">void *</SPAN>
<TR><TD CLASS="code">n<TD>value of type <SPAN CLASS="code">size_type</SPAN>
<TR><TD CLASS="code">RequestedSize<TD>value of type <SPAN CLASS="code">Pool::size_type</SPAN>; must be greater than 0
</TABLE>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Typedefs</EM></CAPTION>
<TR><TH>Expression<TH>Type
<TR><TD CLASS="code">Pool::user_allocator<TD CLASS="code">UserAllocator
<TR><TD CLASS="code">Pool::size_type<TD CLASS="code">UserAllocator::size_type
<TR><TD CLASS="code">Pool::difference_type<TD CLASS="code">UserAllocator::difference_type
</TABLE>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Constructors, Destructors, and Testing</EM></CAPTION>
<TR><TH>Expression<TH>Return Type<TH>Notes
<TR><TD CLASS="code">Pool(RequestedSize)<TD>not used<TD>Constructs a new empty <SPAN CLASS="code">Pool</SPAN> that can be used to allocate chunks of size <SPAN CLASS="code">RequestedSize</SPAN>
<TR><TD CLASS="code">(&amp;t)->~Pool()<TD>not used<TD>Destructs the <SPAN CLASS="code">Pool</SPAN>, freeing its list of memory blocks
<TR><TD CLASS="code">u.is_from(chunk)<TD CLASS="code">bool<TD>Returns <SPAN CLASS="code">true</SPAN> if <SPAN CLASS="code">chunk</SPAN> was allocated from <SPAN CLASS="code">u</SPAN> or may be returned as the result of a future allocation from <SPAN CLASS="code">u</SPAN>. Returns <SPAN CLASS="code">false</SPAN> if <SPAN CLASS="code">chunk</SPAN> was allocated from some other pool or may be returned as the result of a future allocation from some other pool. Otherwise, the return value is meaningless; note that this function may <STRONG>not</STRONG> be used to reliably test random pointer values.
<TR><TD CLASS="code">u.get_requested_size()<TD CLASS="code">size_type<TD>Returns the value passed into the constructor. This value will not change during the lifetime of a <SPAN CLASS="code">Pool</SPAN> object.
</TABLE>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Allocation and Deallocation</EM></CAPTION>
<TR><TH>Expression<TH>Return Type<TH>Pre-Condition<TH>Notes
<TR><TD CLASS="code">t.malloc()<TD CLASS="code">void *<TD><TD>Allocates a chunk of memory. Searches in the list of memory blocks for a block that has a free chunk, and returns that free chunk if found. Otherwise, creates a new memory block, adds its free list to <SPAN CLASS="code">t</SPAN>'s free list, and returns a free chunk from that block. If a new memory block cannot be allocated, returns <SPAN CLASS="code">0</SPAN>. Amortized O(1).
<TR><TD CLASS="code">t.ordered_malloc()<TD CLASS="code">void *<TD><TD>Same as above, only merges the free lists, to preserve order. Amortized O(1).
<TR><TD CLASS="code">t.ordered_malloc(n)<TD CLASS="code">void *<TD><TD>Same as above, only allocates enough contiguous chunks to cover <SPAN CLASS="code">n * requested_size</SPAN> bytes. Amortized O(n).
<TR><TD CLASS="code">t.free(chunk)<TD CLASS="code">void<TD><SPAN CLASS="code">chunk</SPAN> must have been previously returned by <SPAN CLASS="code">t.malloc()</SPAN> or <SPAN CLASS="code">t.ordered_malloc()</SPAN>.<TD>Deallocates a chunk of memory. Note that <SPAN CLASS="code">chunk</SPAN> may not be <SPAN CLASS="code">0</SPAN>. O(1).
<TR><TD CLASS="code">t.ordered_free(chunk)<TD CLASS="code">void<TD>Same as above<TD>Same as above, but is order-preserving. Note that <SPAN CLASS="code">chunk</SPAN> may not be <SPAN CLASS="code">0</SPAN>. O(N) with respect to the size of the free list
<TR><TD CLASS="code">t.free(chunk, n)<TD CLASS="code">void<TD><SPAN CLASS="code">chunk</SPAN> must have been previously returned by <SPAN CLASS="code">t.ordered_malloc(n)</SPAN>.<TD>Assumes that <SPAN CLASS="code">chunk</SPAN> actually refers to a block of chunks spanning <SPAN CLASS="code">n * partition_sz</SPAN> bytes; deallocates each chunk in that block. Note that <SPAN CLASS="code">chunk</SPAN> may not be <SPAN CLASS="code">0</SPAN>. O(n).
<TR><TD CLASS="code">t.ordered_free(chunk, n)<TD CLASS="code">void<TD><SPAN CLASS="code">chunk</SPAN> must have been previously returned by <SPAN CLASS="code">t.ordered_malloc(n)</SPAN>.<TD>Assumes that <SPAN CLASS="code">chunk</SPAN> actually refers to a block of chunks spanning <SPAN CLASS="code">n * partition_sz</SPAN> bytes; deallocates each chunk in that block. Note that <SPAN CLASS="code">chunk</SPAN> may not be <SPAN CLASS="code">0</SPAN>. Order-preserving. O(N + n) where N is the size of the free list.
<TR><TD CLASS="code">t.release_memory()<TD CLASS="code">bool<TD><SPAN CLASS="code">t</SPAN> must be ordered.<TD>Frees every memory block that doesn't have any allocated chunks. Returns <SPAN CLASS="code">true</SPAN> if at least one memory block was freed.
<TR><TD CLASS="code">t.purge_memory()<TD CLASS="code">bool<TD><TD>Frees every memory block. This function invalidates any pointers previously returned by allocation functions of <SPAN CLASS="code">t</SPAN>. Returns <SPAN CLASS="code">true</SPAN> if at least one memory block was freed.
</TABLE>
<P>
<H2>Symbols</H2>
<P>
<UL>
<LI>boost::default_user_allocator_new_delete</LI>
<LI>boost::default_user_allocator_malloc_new</LI>
<LI>boost::pool</LI>
</UL>
<P>
<H2><A HREF="../implementation/pool.html">Implementation Details</A></H2>
<P>
<HR>
<P>
Copyright &copy; 2000, 2001 Stephen Cleary (<A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>)
<P>
This file can be redistributed and/or modified under the terms found in <A HREF="../copyright.html">copyright.html</A>
<P>
This software and its documentation is provided &quot;as is&quot; without express or implied warranty, and with no claim as to its suitability for any purpose.
</BODY>
</HTML>
+202
View File
@@ -0,0 +1,202 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>pool_alloc - Boost Pool Standard Allocators</TITLE>
<LINK HREF="../pool.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY>
<IMG SRC="../../../../c++boost.gif" WIDTH=276 HEIGHT=86 ALT="C++ Boost">
<H1 ALIGN=CENTER>pool_alloc - Boost Pool Standard Allocators</H1>
<P>
<H2>Introduction</H2>
<P>
pool_alloc.hpp provides two template types that can be used for fast and efficient memory allocation. These types both satisfy the Standard Allocator requirements [20.1.5] and the additional requirements in [20.1.5/4], so they can be used with Standard or user-supplied containers. For information on other pool-based interfaces, see <A HREF="../interfaces.html">the other pool interfaces</A>.
<P>
<H2>Synopsis</H2>
<PRE CLASS="code">struct pool_allocator_tag { };
template &lt;typename T,
typename UserAllocator = default_user_allocator_new_delete&gt;
class pool_allocator
{
public:
typedef UserAllocator user_allocator;
typedef T value_type;
typedef value_type * pointer;
typedef const value_type * const_pointer;
typedef value_type &amp; reference;
typedef const value_type &amp; const_reference;
typedef typename pool&lt;UserAllocator&gt;::size_type size_type;
typedef typename pool&lt;UserAllcoator&gt;::difference_type difference_type;
template &lt;typename U&gt;
struct rebind
{ typedef pool_allocator&lt;U, UserAllocator&gt; other; };
public:
pool_allocator();
pool_allocator(const pool_allocator &amp;);
// The following is not explicit, mimicking std::allocator [20.4.1]
template &lt;typename U&gt;
pool_allocator(const pool_allocator&lt;U, UserAllocator&gt; &amp;);
pool_allocator &amp; operator=(const pool_allocator &amp;);
~pool_allocator();
static pointer address(reference r);
static const_pointer address(const_reference s);
static size_type max_size();
static void construct(pointer ptr, const value_type &amp; t);
static void destroy(pointer ptr);
bool operator==(const pool_allocator &amp;) const;
bool operator!=(const pool_allocator &amp;) const;
static pointer allocate(size_type n);
static pointer allocate(size_type n, pointer);
static void deallocate(pointer ptr, size_type n);
};
struct fast_pool_allocator_tag { };
template &lt;typename T
typename UserAllocator = default_user_allocator_new_delete&gt;
class fast_pool_allocator
{
public:
typedef UserAllocator user_allocator;
typedef T value_type;
typedef value_type * pointer;
typedef const value_type * const_pointer;
typedef value_type &amp; reference;
typedef const value_type &amp; const_reference;
typedef typename pool&lt;UserAllocator&gt;::size_type size_type;
typedef typename pool&lt;UserAllocator&gt;::difference_type difference_type;
template &lt;typename U&gt;
struct rebind
{ typedef fast_pool_allocator&lt;U, UserAllocator&gt; other; };
public:
fast_pool_allocator();
fast_pool_allocator(const fast_pool_allocator &amp;);
// The following is not explicit, mimicking std::allocator [20.4.1]
template &lt;typename U&gt;
fast_pool_allocator(const fast_pool_allocator&lt;U, UserAllocator&gt; &amp;);
fast_pool_allocator &amp; operator=(const fast_pool_allocator &amp;);
~fast_pool_allocator();
static pointer address(reference r);
static const_pointer address(const_reference s);
static size_type max_size();
static void construct(pointer ptr, const value_type &amp; t);
static void destroy(pointer ptr);
bool operator==(const fast_pool_allocator &amp;) const;
bool operator!=(const fast_pool_allocator &amp;) const;
static pointer allocate(size_type n);
static pointer allocate(size_type n, pointer);
static void deallocate(pointer ptr, size_type n);
static pointer allocate();
static void deallocate(pointer ptr);
};</PRE>
<P>
<H2>Template Parameters</H2>
<P>
<H3>T</H3>
<P>
The first template parameter is the type of object to allocate/deallocate.
<P>
<H3>UserAllocator</H3>
<P>
Defines the method that the underlying Pool will use to allocate memory from the system. See <A HREF="user_allocator.html">User Allocators</A> for details.
<P>
<H2>Semantics</H2>
<P>
Both of the pool allocators above satisfy all Standard Allocator requirements, as laid out in the Standard [20.1.5]. They also both satisfy the additional requirements found in [20.1.5/4]; this permits their usage with any Standard-compliant container.
<P>
In addition, the <SPAN CLASS="code">fast_pool_allocator</SPAN> also provides an additional allocation and an additional deallocation function:
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Symbol Table</EM></CAPTION>
<TR><TH>Symbol<TH>Meaning
<TR><TD CLASS="code">PoolAlloc<TD><SPAN CLASS="code">fast_pool_allocator&lt;T, UserAllocator&gt;</SPAN>
<TR><TD CLASS="code">p<TD>value of type <SPAN CLASS="code">T *</SPAN>
</TABLE>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Additional allocation/deallocation functions (<SPAN CLASS="code">fast_pool_allocator</SPAN> only)</EM></CAPTION>
<TR><TH>Expression<TH>Return Type<TH>Semantic Equivalence
<TR><TD CLASS="code">PoolAlloc::allocate()<TD CLASS="code">T *<TD CLASS="code">PoolAlloc::allocate(1)
<TR><TD CLASS="code">PoolAlloc::deallocate(p)<TD>void<TD CLASS="code">PoolAlloc::deallocate(p, 1)
</TABLE>
<P>
The typedef <SPAN CLASS="code">user_allocator</SPAN> publishes the value of the <SPAN CLASS="code">UserAllocator</SPAN> template parameter.
<P>
<H2>Notes</H2>
<P>
If the allocation functions run out of memory, they will throw <SPAN CLASS="code">std::bad_alloc</SPAN>.
<P>
The underlying Pool type used by the allocators is accessible through the <A HREF="singleton_pool.html">Singleton Pool Interface</A>. The identifying tag used for <SPAN CLASS="code">pool_allocator</SPAN> is <SPAN CLASS="code">pool_allocator_tag</SPAN>, and the tag used for <SPAN CLASS="code">fast_pool_allocator</SPAN> is <SPAN CLASS="code">fast_pool_allocator_tag</SPAN>. All template parameters of the allocators (including <A HREF="../implementation/pool_alloc.html">implementation-specific ones</A>) determine the type of the underlying Pool, with the exception of the first parameter <SPAN CLASS="code">T</SPAN>, whose size is used instead.
<P>
Since the size of <SPAN CLASS="code">T</SPAN> is used to determine the type of the underlying Pool, each allocator for different types of the same size <EM>will share</EM> the same underlying pool. The tag class prevents pools from being shared between <SPAN CLASS="code">pool_allocator</SPAN> and <SPAN CLASS="code">fast_pool_allocator</SPAN>. For example, on a system where sizeof(int) == sizeof(void *), <SPAN CLASS="code">pool_allocator&lt;int&gt;</SPAN> and <SPAN CLASS="code">pool_allocator&lt;void *&gt;</SPAN> will both allocate/deallocate from/to the same pool.
<P>
If there is only one thread running before <SPAN CLASS="code">main()</SPAN> starts and after <SPAN CLASS="code">main()</SPAN> ends, then both allocators are completely thread-safe.
<P>
<H2>The Fast Pool Allocator</H2>
<P>
<SPAN CLASS="code">pool_allocator</SPAN> is a more general-purpose solution, geared towards efficiently servicing requests for any number of contiguous chunks. <SPAN CLASS="code">fast_pool_allocator</SPAN> is also a general-purpose solution, but is geared towards efficiently servicing requests for one chunk at a time; it will work for contiguous chunks, but not as well as <SPAN CLASS="code">pool_allocator</SPAN>. If you are seriously concerned about performance, use <SPAN CLASS="code">fast_pool_allocator</SPAN> when dealing with containers such as <SPAN CLASS="code">std::list</SPAN>, and use <SPAN CLASS="code">pool_allocator</SPAN> when dealing with containers such as <SPAN CLASS="code">std::vector</SPAN>.
<P>
<H2>Symbols</H2>
<P>
<UL>
<LI>boost::pool_allocator</LI>
<LI>boost::pool_allocator_tag</LI>
<LI>boost::fast_pool_allocator</LI>
<LI>boost::fast_pool_allocator_tag</LI>
</UL>
<P>
<H2><A HREF="../implementation/pool_alloc.html">Implementation Details</A></H2>
<P>
<HR>
<P>
Copyright &copy; 2000, 2001 Stephen Cleary (<A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>)
<P>
This file can be redistributed and/or modified under the terms found in <A HREF="../copyright.html">copyright.html</A>
<P>
This software and its documentation is provided &quot;as is&quot; without express or implied warranty, and with no claim as to its suitability for any purpose.
</BODY>
</HTML>
@@ -0,0 +1,150 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>Simple Segregated Storage</TITLE>
<LINK HREF="../pool.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY>
<IMG SRC="../../../../c++boost.gif" WIDTH=276 HEIGHT=86 ALT="C++ Boost">
<H1 ALIGN=CENTER>Simple Segregated Storage</H1>
<P>
<H2>Introduction</H2>
<P>
simple_segregated_storage.hpp provides a template class <SPAN CLASS="code">simple_segregated_storage</SPAN> that controls access to a <EM>free list</EM> of memory chunks. Please note that this is a <STRONG>very</STRONG> simple class, with preconditions on almost all its functions. It is intended to be the fastest and smallest possible quick memory allocator &mdash; e.g., something to use in embedded systems. This class delegates many difficult preconditions to the user (i.e., alignment issues). For more general usage, see <A HREF="../interfaces.html">the other pool interfaces</A>.
<P>
<H2>Synopsis</H2>
<PRE CLASS="code">template &lt;typename SizeType = std::size_t&gt;
class simple_segregated_storage
{
private:
simple_segregated_storage(const simple_segregated_storage &amp;);
void operator=(const simple_segregated_storage &amp;);
public:
typedef SizeType size_type;
simple_segregated_storage();
~simple_segregated_storage();
static void * segregate(void * block,
size_type nsz, size_type npartition_sz,
void * end = 0);
void add_block(void * block,
size_type nsz, size_type npartition_sz);
void add_ordered_block(void * block,
size_type nsz, size_type npartition_sz);
bool empty() const;
void * malloc();
void free(void * chunk);
void ordered_free(void * chunk);
void * malloc_n(size_type n, size_type partition_sz);
void free_n(void * chunks, size_type n,
size_type partition_sz);
void ordered_free_n(void * chunks, size_type n,
size_type partition_sz);
};</PRE>
<P>
<H2>Semantics</H2>
<P>
An object of type <SPAN CLASS="code">simple_segregated_storage&lt;SizeType&gt;</SPAN> is <EM>empty</EM> if its free list is empty. If it is not empty, then it is <EM>ordered</EM> if its free list is ordered. A free list is ordered if repeated calls to <SPAN CLASS="code">malloc()</SPAN> will result in a constantly-increasing sequence of values, as determined by <SPAN CLASS="code">std::less&lt;void *&gt;</SPAN>. A member function is <EM>order-preserving</EM> if the free list maintains its order orientation (that is, an ordered free list is still ordered after the member function call).
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Symbol Table</EM></CAPTION>
<TR><TH>Symbol<TH>Meaning
<TR><TD CLASS="code">Store<TD CLASS="code">simple_segregated_storage&lt;SizeType&gt;
<TR><TD CLASS="code">t<TD>value of type <SPAN CLASS="code">Store</SPAN>
<TR><TD CLASS="code">u<TD>value of type <SPAN CLASS="code">const Store</SPAN>
<TR><TD CLASS="code">block, chunk, end<TD>values of type <SPAN CLASS="code">void *</SPAN>
<TR><TD CLASS="code">partition_sz, sz, n<TD>values of type <SPAN CLASS="code">Store::size_type</SPAN>
</TABLE>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Template Parameters</EM></CAPTION>
<TR><TH>Parameter<TH>Default<TH>Requirements
<TR><TD CLASS="code">SizeType<TD CLASS="code">std::size_t<TD>An unsigned integral type
</TABLE>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Typedefs</EM></CAPTION>
<TR><TH>Symbol<TH>Type
<TR><TD CLASS="code">size_type<TD CLASS="code">SizeType
</TABLE>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Constructors, Destructors, and State</EM></CAPTION>
<TR><TH>Expression<TH>Return Type<TH>Post-Condition<TH>Notes
<TR><TD CLASS="code">Store()<TD>not used<TD CLASS="code">empty()<TD>Constructs a new <SPAN CLASS="code">Store</SPAN>
<TR><TD CLASS="code">(&amp;t)->~Store()<TD>not used<TD><TD>Destructs the <SPAN CLASS="code">Store</SPAN>
<TR><TD CLASS="code">u.empty()<TD CLASS="code">bool<TD><TD>Returns <SPAN CLASS="code">true</SPAN> if <SPAN CLASS="code">u</SPAN> is empty. Order-preserving.
</TABLE>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Segregation</EM></CAPTION>
<TR><TH>Expression<TH>Return Type<TH>Pre-Condition<TH>Post-Condition<TH>Semantic Equivalence<TH>Notes
<TR><TD CLASS="code">Store::segregate(block, sz, partition_sz, end)<TD CLASS="code">void *<TD><SPAN CLASS="code">partition_sz &gt;= sizeof(void *)</SPAN><BR><SPAN CLASS="code">partition_sz = sizeof(void *) * i</SPAN>, for some integer <SPAN CLASS="code">i</SPAN><BR><SPAN CLASS="code">sz &gt;= partition_sz</SPAN><BR><SPAN CLASS="code">block</SPAN> is properly aligned for an array of objects of size <SPAN CLASS="code">partition_sz</SPAN><BR><SPAN CLASS="code">block</SPAN> is properly aligned for an array of <SPAN CLASS="code">void *</SPAN><TD><TD><TD>Interleaves a free list through the memory block specified by <SPAN CLASS="code">block</SPAN> of size <SPAN CLASS="code">sz</SPAN> bytes, partitioning it into as many <SPAN CLASS="code">partition_sz</SPAN>-sized chunks as possible. The last chunk is set to point to <SPAN CLASS="code">end</SPAN>, and a pointer to the first chunck is returned (this is always equal to <SPAN CLASS="code">block</SPAN>). This interleaved free list is ordered. O(sz).
<TR><TD CLASS="code">Store::segregate(block, sz, partition_sz)<TD CLASS="code">void *<TD>Same as above<TD><TD CLASS="code">Store::segregate(block, sz, partition_sz, 0)<TD>
<TR><TD CLASS="code">t.add_block(block, sz, partition_sz)<TD CLASS="code">void<TD>Same as above<TD CLASS="code">!t.empty()<TD><TD>Segregates the memory block specified by <SPAN CLASS="code">block</SPAN> of size <SPAN CLASS="code">sz</SPAN> bytes into <SPAN CLASS="code">partition_sz</SPAN>-sized chunks, and adds that free list to its own. If <SPAN CLASS="code">t</SPAN> was empty before this call, then it is ordered after this call. O(sz).
<TR><TD CLASS="code">t.add_ordered_block(block, sz, partition_sz)<TD CLASS="code">void<TD>Same as above<TD CLASS="code">!t.empty()<TD><TD>Segregates the memory block specified by <SPAN CLASS="code">block</SPAN> of size <SPAN CLASS="code">sz</SPAN> bytes into <SPAN CLASS="code">partition_sz</SPAN>-sized chunks, and merges that free list into its own. Order-preserving. O(sz).
</TABLE>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Allocation and Deallocation</EM></CAPTION>
<TR><TH>Expression<TH>Return Type<TH>Pre-Condition<TH>Post-Condition<TH>Semantic Equivalence<TH>Notes
<TR><TD CLASS="code">t.malloc()<TD CLASS="code">void *<TD CLASS="code">!t.empty()<TD><TD><TD>Takes the first available chunk from the free list and returns it. Order-preserving. O(1).
<TR><TD CLASS="code">t.free(chunk)<TD CLASS="code">void<TD><SPAN CLASS="code">chunk</SPAN> was previously returned from a call to <SPAN CLASS="code">t.malloc()</SPAN><TD CLASS="code">!t.empty()<TD><TD>Places <SPAN CLASS="code">chunk</SPAN> back on the free list. Note that <SPAN CLASS="code">chunk</SPAN> may not be <SPAN CLASS="code">0</SPAN>. O(1).
<TR><TD CLASS="code">t.ordered_free(chunk)<TD CLASS="code">void<TD>Same as above<TD CLASS="code">!t.empty()<TD><TD>Places <SPAN CLASS="code">chunk</SPAN> back on the free list. Note that <SPAN CLASS="code">chunk</SPAN> may not be <SPAN CLASS="code">0</SPAN>. Order-preserving. O(N) with respect to the size of the free list.
<TR><TD CLASS="code">t.malloc_n(n, partition_sz)<TD CLASS="code">void *<TD CLASS="code">!empty()<TD><TD><TD>Attempts to find a contiguous sequence of <SPAN CLASS="code">n</SPAN> <SPAN CLASS="code">partition_sz</SPAN>-sized chunks. If found, removes them all from the free list and returns a pointer to the first. If not found, returns <SPAN CLASS="code">0</SPAN>. It is strongly recommended (but not required) that the free list be ordered, as this algorithm will fail to find a contiguous sequence unless it is contiguous in the free list as well. Order-preserving. O(N) with respect to the size of the free list.
<TR><TD CLASS="code">t.free_n(chunk, n, partition_sz)<TD CLASS="code">void<TD><SPAN CLASS="code">chunk</SPAN> was previously returned from a call to <SPAN CLASS="code">t.malloc_n(n, partition_sz)</SPAN><TD CLASS="code">!t.empty()<TD CLASS="code">t.add_block(chunk, n * partition_sz, partition_sz)<TD>Assumes that <SPAN CLASS="code">chunk</SPAN> actually refers to a block of chunks spanning <SPAN CLASS="code">n * partition_sz</SPAN> bytes; segregates and adds in that block. Note that <SPAN CLASS="code">chunk</SPAN> may not be <SPAN CLASS="code">0</SPAN>. O(n).
<TR><TD CLASS="code">t.ordered_free_n(chunk, n, partition_sz)<TD CLASS="code">void<TD>same as above<TD>same as above<TD CLASS="code">t.add_ordered_block(chunk, n * partition_sz, partition_sz)<TD>Same as above, except it merges in the free list. Order-preserving. O(N + n) where N is the size of the free list.
</TABLE>
<P>
<H2>Symbols</H2>
<P>
<UL>
<LI>boost::simple_segregated_storage</LI>
</UL>
<P>
<H2><A HREF="../implementation/simple_segregated_storage.html">Implementation Details</A></H2>
<P>
<HR>
<P>
Copyright &copy; 2000, 2001 Stephen Cleary (<A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>)
<P>
This file can be redistributed and/or modified under the terms found in <A HREF="../copyright.html">copyright.html</A>
<P>
This software and its documentation is provided &quot;as is&quot; without express or implied warranty, and with no claim as to its suitability for any purpose.
</BODY>
</HTML>
+157
View File
@@ -0,0 +1,157 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>Singleton Pool</TITLE>
<LINK HREF="../pool.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY>
<IMG SRC="../../../../c++boost.gif" WIDTH=276 HEIGHT=86 ALT="C++ Boost">
<H1 ALIGN=CENTER>Singleton Pool</H1>
<P>
<H2>Introduction</H2>
<P>
singleton_pool.hpp provides a template class <SPAN CLASS="code">singleton_pool</SPAN>, which provides access to a <SPAN CLASS="code">pool</SPAN> as a singleton object. For information on other pool-based interfaces, see <A HREF="../interfaces.html">the other pool interfaces</A>.
<P>
<H2>Synopsis</H2>
<PRE CLASS="code">template &lt;typename Tag, unsigned RequestedSize,
typename UserAllocator = default_user_allocator_new_delete&gt;
struct singleton_pool
{
public:
typedef Tag tag;
typedef UserAllocator user_allocator;
typedef typename pool&lt;UserAllocator&gt;::size_type size_type;
typedef typename pool&lt;UserAllocator&gt;::difference_type difference_type;
static const unsigned requested_size = RequestedSize;
private:
static pool&lt;size_type&gt; p; // exposition only!
singleton_pool();
public:
static bool is_from(void * ptr);
static void * malloc();
static void * ordered_malloc();
static void * ordered_malloc(size_type n);
static void free(void * ptr);
static void ordered_free(void * ptr);
static void free(void * ptr, std::size_t n);
static void ordered_free(void * ptr, size_type n);
static bool release_memory();
static bool purge_memory();
};</PRE>
<P>
<H2>Notes</H2>
<P>
The underlying pool <SPAN CLASS="code">p</SPAN> referenced by the static functions in <SPAN CLASS="code">singleton_pool</SPAN> is actually declared in a way that it is:
<UL>
<LI>Thread-safe if there is only one thread running before main() begins and after main() ends -- all of the static functions of <SPAN CLASS="code">singleton_pool</SPAN> synchronize their access to <SPAN CLASS="code">p</SPAN>.</LI>
<LI>Guaranteed to be constructed before it is used -- thus, the simple static object in the synopsis above would actually be an incorrect implementation. The actual <A HREF="../implementation/singleton_pool.html">implementation</A> to guarantee this is considerably more complicated.
</UL>
<P>
Note that a different underlying pool <SPAN CLASS="code">p</SPAN> exists for each different set of template parameters, including <A HREF="../implementation/singleton_pool.html">implementation-specific ones</A>.
<P>
<H2>Template Parameters</H2>
<P>
<H3>Tag</H3>
<P>
The <SPAN CLASS="code">Tag</SPAN> template parameter allows different unbounded sets of singleton pools to exist. For example, the <A HREF="pool_alloc.html">pool allocators</A> use two tag classes to ensure that the two different allocator types never share the same underlying singleton pool.
<P>
<SPAN CLASS="code">Tag</SPAN> is never actually used by <SPAN CLASS="code">singleton_pool</SPAN>.
<P>
<H3>RequestedSize</H3>
<P>
The requested size of memory chunks to allocate. This is passed as a constructor parameter to the underlying <SPAN CLASS="code">pool</SPAN>. Must be greater than 0.
<P>
<H3>UserAllocator</H3>
<P>
Defines the method that the underlying <SPAN CLASS="code">pool</SPAN> will use to allocate memory from the system. See <A HREF="user_allocator.html">User Allocators</A> for details.
<P>
<H2>Semantics</H2>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Symbol Table</EM></CAPTION>
<TR><TH>Symbol<TH>Meaning
<TR><TD CLASS="code">SingletonPool<TD CLASS="code">singleton_pool&lt;Tag, RequestedSize, UserAllocator&gt;
<TR><TD CLASS="code">chunk<TD>value of type <SPAN CLASS="code">void *</SPAN>
<TR><TD CLASS="code">n<TD>value of type <SPAN CLASS="code">size_type</SPAN>
</TABLE>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Typedefs/Static Const Values</EM></CAPTION>
<TR><TH>Expression<TH>Type/Value
<TR><TD CLASS="code">SingletonPool::tag<TD CLASS="code">Tag
<TR><TD CLASS="code">SingletonPool::user_allocator<TD CLASS="code">UserAllocator
<TR><TD CLASS="code">SingletonPool::size_type<TD CLASS="code">pool&lt;UserAllocator&gt;::size_type
<TR><TD CLASS="code">SingletonPool::difference_type<TD CLASS="code">pool&lt;UserAllocator&gt;::difference_type
<TR><TD CLASS="code">SingletonPool::requested_size<TD CLASS="code">RequestedSize
</TABLE>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Functions</EM></CAPTION>
<TR><TH>Expression<TH>Return Type<TH>Semantic Equivalent
<TR><TD CLASS="code">SingletonPool::is_from(chunk)<TD CLASS="code">bool<TD><SPAN CLASS="code">SingletonPool::p.is_from(chunk);</SPAN> synchronized
<TR><TD CLASS="code">SingletonPool::malloc()<TD CLASS="code">void *<TD><SPAN CLASS="code">SingletonPool::p.malloc();</SPAN> synchronized
<TR><TD CLASS="code">SingletonPool::ordered_malloc(n)<TD CLASS="code">void *<TD><SPAN CLASS="code">SingletonPool::p.ordered_malloc(n);</SPAN> synchronized
<TR><TD CLASS="code">SingletonPool::free(chunk)<TD CLASS="code">void<TD><SPAN CLASS="code">SingletonPool::p.free(chunk);</SPAN> synchronized
<TR><TD CLASS="code">SingletonPool::ordered_free(chunk)<TD CLASS="code">void<TD><SPAN CLASS="code">SingletonPool::p.ordered_free(chunk);</SPAN> synchronized
<TR><TD CLASS="code">SingletonPool::free(chunk, n)<TD CLASS="code">void<TD><SPAN CLASS="code">SingletonPool::p.free(chunk, n);</SPAN> synchronized
<TR><TD CLASS="code">SingletonPool::ordered_free(chunk, n)<TD CLASS="code">void<TD><SPAN CLASS="code">SingletonPool::p.ordered_free(chunk, n);</SPAN> synchronized
<TR><TD CLASS="code">SingletonPool::release_memory()<TD CLASS="code">bool<TD><SPAN CLASS="code">SingletonPool::p.release_memory();</SPAN> synchronized
<TR><TD CLASS="code">SingletonPool::purge_memory()<TD CLASS="code">bool<TD><SPAN CLASS="code">SingletonPool::p.purge_memory();</SPAN> synchronized
</TABLE>
<P>
For more information on the semantics of these functions, see the <A HREF="pool.html">pool interface</A>.
<P>
<H2>Symbols</H2>
<P>
<UL>
<LI>boost::singleton_pool</LI>
</UL>
<P>
<H2><A HREF="../implementation/singleton_pool.html">Implementation Details</A></H2>
<P>
<HR>
<P>
Copyright &copy; 2000, 2001 Stephen Cleary (<A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>)
<P>
This file can be redistributed and/or modified under the terms found in <A HREF="../copyright.html">copyright.html</A>
<P>
This software and its documentation is provided &quot;as is&quot; without express or implied warranty, and with no claim as to its suitability for any purpose.
</BODY>
</HTML>
+91
View File
@@ -0,0 +1,91 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>Pool</TITLE>
<LINK HREF="../pool.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY>
<IMG SRC="../../../../c++boost.gif" WIDTH=276 HEIGHT=86 ALT="C++ Boost">
<H1 ALIGN=CENTER>User Allocators</H1>
<P>
<H2>Introduction</H2>
<P>
Pool objects need to request memory blocks from the system, which the Pool then splits into chunks to allocate to the user. By specifying a <SPAN CLASS="code">UserAllocator</SPAN> template parameter to various Pool interfaces, users can control how those system memory blocks are allocated.
<P>
<H2>Semantics</H2>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Symbol Table</EM></CAPTION>
<TR><TH>Symbol<TH>Meaning
<TR><TD CLASS="code">UserAllocator<TD>A User Allocator type
<TR><TD CLASS="code">block<TD>value of type <SPAN CLASS="code">char *</SPAN>
<TR><TD CLASS="code">n<TD>value of type <SPAN CLASS="code">UserAllocator::size_type</SPAN>
</TABLE>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Typedefs</EM></CAPTION>
<TR><TH>Expression<TH>Type
<TR><TD CLASS="code">UserAllocator::size_type<TD>An unsigned integral type that can represent the size of the largest object to be allocated
<TR><TD CLASS="code">UserAllocator::difference_type<TD>A signed integral type that can represent the difference of any two pointers
</TABLE>
<P>
<TABLE BORDER ALIGN=CENTER>
<CAPTION><EM>Allocation and Deallocation</EM></CAPTION>
<TR><TH>Expression<TH>Return Type<TH>Pre-Condition/Notes
<TR><TD CLASS="code">UserAllocator::malloc(n)<TD CLASS="code">char *<TD>Attempts to allocate <SPAN CLASS="code">n</SPAN> bytes from the system. Returns 0 if out-of-memory.
<TR><TD CLASS="code">UserAllocator::free(block)<TD CLASS="code">void<TD><SPAN CLASS="code">block</SPAN> must have been previously returned from a call to <SPAN CLASS="code">UserAllocator::malloc</SPAN>.
</TABLE>
<P>
<H2>Provided Implementations</H2>
<P>
There are two <SPAN CLASS="code">UserAllocator</SPAN> classes provided. Both of them are in pool.hpp (see <A HREF="pool.html">pool</A>). The default value for the template parameter <SPAN CLASS="code">UserAllocator</SPAN> is always <SPAN CLASS="code">default_user_allocator_new_delete</SPAN>.
<P>
<H3>Synopsis</H3>
<PRE CLASS="code">struct default_user_allocator_new_delete
{
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
static char * malloc(const size_type bytes)
{ return new (std::nothrow) char[bytes]; }
static void free(char * const block)
{ delete [] block; }
};
struct default_user_allocator_malloc_free
{
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
static char * malloc(const size_type bytes)
{ return reinterpret_cast&lt;char *&gt;(std::malloc(bytes)); }
static void free(char * const block)
{ std::free(block); }
};</PRE>
<P>
<HR>
<P>
Copyright &copy; 2000, 2001 Stephen Cleary (<A HREF="mailto:shammah@voyager.net">shammah@voyager.net</A>)
<P>
This file can be redistributed and/or modified under the terms found in <A HREF="../copyright.html">copyright.html</A>
<P>
This software and its documentation is provided &quot;as is&quot; without express or implied warranty, and with no claim as to its suitability for any purpose.
</BODY>
</HTML>
+11
View File
@@ -0,0 +1,11 @@
/*
Copyright (C) 2000 Stephen Cleary (shammah@voyager.net)
This file can be redistributed and/or modified under the terms found
in "copyright.html"
This software and its documentation is provided "as is" without express or
implied warranty, and with no claim as to its suitability for any purpose.
*/
*.code { font-family: monospace; }
*.m4 { white-space: pre; font-family: monospace; font-size: 75% }
+68
View File
@@ -0,0 +1,68 @@
// Copyright (C) 2000 Stephen Cleary (shammah@voyager.net)
//
// This file can be redistributed and/or modified under the terms found
// in "copyright.html"
// This software and its documentation is provided "as is" without express or
// implied warranty, and with no claim as to its suitability for any purpose.
//
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_POOL_CT_GCD_LCM_HPP
#define BOOST_POOL_CT_GCD_LCM_HPP
#include <boost/pool/detail/postulate.hpp>
namespace boost {
namespace details {
namespace pool {
// Compile-time calculation of greatest common divisor and least common multiple
//
// ct_gcd is a compile-time algorithm that calculates the greatest common
// divisor of two unsigned integers, using Euclid's algorithm.
//
// assumes: A != 0 && B != 0
//
namespace details {
template <unsigned A, unsigned B, bool Bis0>
struct ct_gcd_helper;
template <unsigned A, unsigned B>
struct ct_gcd_helper<A, B, false>
{
//WAS: static const unsigned value = ct_gcd_helper<B, (A % B), (A % B) == 0>::value;
static const unsigned value = ct_gcd_helper<B, (A % B), ((A % B) == 0)>::value;
};
template <unsigned A, unsigned B>
struct ct_gcd_helper<A, B, true>
{
static const unsigned value = A;
};
} // namespace details
template <unsigned A, unsigned B>
struct ct_gcd
{
BOOST_POOL_POSTULATE(A != 0 && B != 0);
static const unsigned value = details::ct_gcd_helper<A, B, false>::value;
};
//
// ct_lcm is a compile-time algorithm that calculates the least common
// multiple of two unsigned integers.
//
// assumes: A != 0 && B != 0
//
template <unsigned A, unsigned B>
struct ct_lcm
{
static const unsigned value = A / ct_gcd<A, B>::value * B;
};
} // namespace pool
} // namespace details
} // namespace boost
#endif
+109
View File
@@ -0,0 +1,109 @@
m4_dnl
m4_dnl Copyright (C) 2000 Stephen Cleary (shammah@voyager.net)
m4_dnl
m4_dnl This file can be redistributed and/or modified under the terms found
m4_dnl in "copyright.html"
m4_dnl This software and its documentation is provided "as is" without express or
m4_dnl implied warranty, and with no claim as to its suitability for any purpose.
m4_dnl
m4_dnl See http://www.boost.org for updates, documentation, and revision history.
m4_dnl
m4_dnl
m4_dnl
m4_dnl BOOST_M4_FOR: repeat a given text for a range of values
m4_dnl $1 - variable to hold the current value.
m4_dnl $2 - the starting value.
m4_dnl $3 - the ending value (text is _not_ repeated for this value).
m4_dnl $4 - the text to repeat.
m4_dnl $5 - the delimeter text (optional).
m4_dnl
m4_dnl If the starting value is < ending value:
m4_dnl Will repeat $4, binding $1 to the values in the range [$2, $3).
m4_dnl Else (that is, starting value >= ending value):
m4_dnl Will do nothing
m4_dnl Repeats $5 in-between each occurrence of $4
m4_dnl
m4_dnl Logic:
m4_dnl Set $1 to $2 and call BOOST_M4_FOR_LIST_HELPER:
m4_dnl If $1 >= $3, do nothing
m4_dnl Else
m4_dnl output $4,
m4_dnl set $1 to itself incremented,
m4_dnl If $1 != $3, output $5,
m4_dnl and use recursion
m4_dnl
m4_define(`BOOST_M4_FOR',
`m4_ifelse(m4_eval($# < 4 || $# > 5), 1,
`m4_errprint(m4___file__:m4___line__: `Boost m4 script: BOOST_M4_FOR: Wrong number of arguments ($#)')',
`m4_pushdef(`$1', `$2')BOOST_M4_FOR_HELPER($@)m4_popdef(`$1')')')m4_dnl
m4_define(`BOOST_M4_FOR_HELPER',
`m4_ifelse(m4_eval($1 >= $3), 1, ,
`$4`'m4_define(`$1', m4_incr($1))m4_ifelse(m4_eval($1 != $3), 1, `$5')`'BOOST_M4_FOR_HELPER($@)')')m4_dnl
m4_dnl
m4_dnl Testing/Examples:
m4_dnl
m4_dnl The following line will output:
m4_dnl "repeat.m4:42: Boost m4 script: BOOST_M4_FOR: Wrong number of arguments (3)"
m4_dnl BOOST_M4_FOR(i, 1, 3)
m4_dnl
m4_dnl The following line will output:
m4_dnl "repeat.m4:46: Boost m4 script: BOOST_M4_FOR: Wrong number of arguments (6)"
m4_dnl BOOST_M4_FOR(i, 1, 3, i, ` ', 13)
m4_dnl
m4_dnl The following line will output (nothing):
m4_dnl ""
m4_dnl BOOST_M4_FOR(i, 7, 0, i )
m4_dnl
m4_dnl The following line will output (nothing):
m4_dnl ""
m4_dnl BOOST_M4_FOR(i, 0, 0, i )
m4_dnl
m4_dnl The following line will output:
m4_dnl "0 1 2 3 4 5 6 "
m4_dnl BOOST_M4_FOR(i, 0, 7, i )
m4_dnl
m4_dnl The following line will output:
m4_dnl "-13 -12 -11 "
m4_dnl BOOST_M4_FOR(i, -13, -10, i )
m4_dnl
m4_dnl The following two lines will output:
m4_dnl "(0, 0) (0, 1) (0, 2) (0, 3) "
m4_dnl "(1, 0) (1, 1) (1, 2) (1, 3) "
m4_dnl "(2, 0) (2, 1) (2, 2) (2, 3) "
m4_dnl "(3, 0) (3, 1) (3, 2) (3, 3) "
m4_dnl "(4, 0) (4, 1) (4, 2) (4, 3) "
m4_dnl "(5, 0) (5, 1) (5, 2) (5, 3) "
m4_dnl "(6, 0) (6, 1) (6, 2) (6, 3) "
m4_dnl "(7, 0) (7, 1) (7, 2) (7, 3) "
m4_dnl ""
m4_dnl BOOST_M4_FOR(i, 0, 8, BOOST_M4_FOR(j, 0, 4, (i, j) )
m4_dnl )
m4_dnl
m4_dnl The following line will output (nothing):
m4_dnl ""
m4_dnl BOOST_M4_FOR(i, 7, 0, i, |)
m4_dnl
m4_dnl The following line will output (nothing):
m4_dnl ""
m4_dnl BOOST_M4_FOR(i, 0, 0, i, |)
m4_dnl
m4_dnl The following line will output:
m4_dnl "0|1|2|3|4|5|6"
m4_dnl BOOST_M4_FOR(i, 0, 7, i, |)
m4_dnl
m4_dnl The following line will output:
m4_dnl "-13, -12, -11"
m4_dnl BOOST_M4_FOR(i, -13, -10, i, `, ')
m4_dnl
m4_dnl The following two lines will output:
m4_dnl "[(0, 0), (0, 1), (0, 2), (0, 3)],"
m4_dnl "[(1, 0), (1, 1), (1, 2), (1, 3)],"
m4_dnl "[(2, 0), (2, 1), (2, 2), (2, 3)],"
m4_dnl "[(3, 0), (3, 1), (3, 2), (3, 3)],"
m4_dnl "[(4, 0), (4, 1), (4, 2), (4, 3)],"
m4_dnl "[(5, 0), (5, 1), (5, 2), (5, 3)],"
m4_dnl "[(6, 0), (6, 1), (6, 2), (6, 3)],"
m4_dnl "[(7, 0), (7, 1), (7, 2), (7, 3)]"
m4_dnl BOOST_M4_FOR(i, 0, 8, `[BOOST_M4_FOR(j, 0, 4, (i, j), `, ')]', `,
m4_dnl ')
m4_dnl
+59
View File
@@ -0,0 +1,59 @@
// Copyright (C) 2000 Stephen Cleary (shammah@voyager.net)
//
// This file can be redistributed and/or modified under the terms found
// in "copyright.html"
// This software and its documentation is provided "as is" without express or
// implied warranty, and with no claim as to its suitability for any purpose.
//
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_POOL_GCD_LCM_HPP
#define BOOST_POOL_GCD_LCM_HPP
namespace boost {
namespace details {
namespace pool {
// Greatest common divisor and least common multiple
//
// gcd is an algorithm that calculates the greatest common divisor of two
// integers, using Euclid's algorithm.
//
// Pre: A > 0 && B > 0
// Recommended: A > B
template <typename Integer>
Integer gcd(Integer A, Integer B)
{
do
{
const Integer tmp(B);
B = A % B;
A = tmp;
} while (B != 0);
return A;
}
//
// lcm is an algorithm that calculates the least common multiple of two
// integers.
//
// Pre: A > 0 && B > 0
// Recommended: A > B
template <typename Integer>
Integer lcm(const Integer & A, const Integer & B)
{
Integer ret = A;
ret /= gcd(A, B);
ret *= B;
return ret;
}
} // namespace pool
} // namespace details
} // namespace boost
#endif
+41
View File
@@ -0,0 +1,41 @@
// Copyright (C) 2000 Stephen Cleary (shammah@voyager.net)
//
// This file can be redistributed and/or modified under the terms found
// in "copyright.html"
// This software and its documentation is provided "as is" without express or
// implied warranty, and with no claim as to its suitability for any purpose.
//
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_POOL_GUARD_HPP
#define BOOST_POOL_GUARD_HPP
// Extremely Light-Weight guard glass
namespace boost {
namespace details {
namespace pool {
template <typename Mutex>
class guard
{
private:
Mutex & mtx;
guard(const guard &);
void operator=(const guard &);
public:
explicit guard(Mutex & nmtx)
:mtx(nmtx) { mtx.lock(); }
~guard() { mtx.unlock(); }
};
} // namespace pool
} // namespace details
} // namespace boost
#endif
+134
View File
@@ -0,0 +1,134 @@
// Copyright (C) 2000 Stephen Cleary (shammah@voyager.net)
//
// This file can be redistributed and/or modified under the terms found
// in "copyright.html"
// This software and its documentation is provided "as is" without express or
// implied warranty, and with no claim as to its suitability for any purpose.
//
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_POOL_MUTEX_HPP
#define BOOST_POOL_MUTEX_HPP
// Extremely Light-Weight wrapper classes for OS thread synchronization
// Configuration: for now, we just choose between pthread or Win32 mutexes or none
#define BOOST_MUTEX_HELPER_NONE 0
#define BOOST_MUTEX_HELPER_WIN32 1
#define BOOST_MUTEX_HELPER_PTHREAD 2
#ifdef BOOST_NO_MT
// No multithreading -> make locks into no-ops
#define BOOST_MUTEX_HELPER BOOST_MUTEX_HELPER_NONE
#else
#ifdef __WIN32__
#define BOOST_MUTEX_HELPER BOOST_MUTEX_HELPER_WIN32
#else
#include <unistd.h>
#ifdef _POSIX_THREADS
#define BOOST_MUTEX_HELPER BOOST_MUTEX_HELPER_PTHREAD
#endif
#endif
#endif
#ifndef BOOST_MUTEX_HELPER
#error Unable to determine platform mutex type; define BOOST_NO_MT to assume single-threaded
#endif
#ifdef __WIN32__
#include <windows.h>
#elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_PTHREAD
#include <pthread.h>
#endif
namespace boost {
namespace details {
namespace pool {
#ifdef __WIN32__
class win32_mutex
{
private:
CRITICAL_SECTION mtx;
win32_mutex(const win32_mutex &);
void operator=(const win32_mutex &);
public:
win32_mutex()
{ InitializeCriticalSection(&mtx); }
~win32_mutex()
{ DeleteCriticalSection(&mtx); }
void lock()
{ EnterCriticalSection(&mtx); }
void unlock()
{ LeaveCriticalSection(&mtx); }
};
#endif // defined(__WIN32__)
#ifdef _POSIX_THREADS
class pthread_mutex
{
private:
pthread_mutex_t mtx;
pthread_mutex(const pthread_mutex &);
void operator=(const pthread_mutex &);
public:
pthread_mutex()
{ pthread_mutex_init(&mtx, 0); }
~pthread_mutex()
{ pthread_mutex_destroy(&mtx); }
void lock()
{ pthread_mutex_lock(&mtx); }
void unlock()
{ pthread_mutex_unlock(&mtx); }
};
#endif // defined(_POSIX_THREADS)
class null_mutex
{
private:
null_mutex(const null_mutex &);
void operator=(const null_mutex &);
public:
null_mutex() { }
static void lock() { }
static void unlock() { }
};
#if BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_NONE
typedef null_mutex default_mutex;
#elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_WIN32
typedef win32_mutex default_mutex;
#elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_PTHREAD
typedef pthread_mutex default_mutex;
#endif
} // namespace pool
} // namespace details
} // namespace boost
#undef BOOST_MUTEX_HELPER_WIN32
#undef BOOST_MUTEX_HELPER_PTHREAD
#undef BOOST_MUTEX_HELPER_NONE
#undef BOOST_MUTEX_HELPER
#endif
+29
View File
@@ -0,0 +1,29 @@
@echo off
rem
rem Copyright (C) 2000 Stephen Cleary (shammah@voyager.net)
rem
rem This file can be redistributed and/or modified under the terms found
rem in "copyright.html"
rem This software and its documentation is provided "as is" without express or
rem implied warranty, and with no claim as to its suitability for any purpose.
rem
rem See http://www.boost.org for updates, documentation, and revision history.
rem
rem Check for Windows NT
if %OS%==Windows_NT goto NT
rem Not NT - run m4 as normal, then exit
m4 -P -E -DNumberOfArguments=%1 pool_construct.m4 > pool_construct.inc
goto end
rem DJGPP programs (including m4) running on Windows/NT do NOT support long
rem file names (see the DJGPP v2 FAQ, question 8.1)
rem I don't redirect input, or else you'll lose the file name entirely -
rem 'pool_c~1.m4' is better than 'stdin' in error messages
rem Note that the output doesn't have to be a short name because it's an
rem argument to the command shell, not m4.
:NT
m4 -P -E -DNumberOfArguments=%1 pool_c~1.m4 > pool_construct.inc
:end
@@ -0,0 +1,858 @@
// Copyright (C) 2000 Stephen Cleary (shammah@voyager.net)
//
// Permission to copy, use, and distribute this software is granted, provided
// that this copyright notice appears in all copies.
// Permission to modify the code and to distribute modified code is granted,
// provided that this copyright notice appears in all copies, and a notice
// that the code was modified is included with the copyright notice.
//
// This software is provided "as is" without express or implied warranty, and
// with no claim as to its suitability for any purpose.
//
// See http://www.boost.org for updates, documentation, and revision history.
// This file was AUTOMATICALLY GENERATED from "pool_c~1.m4"
// Do NOT include directly!
// Do NOT edit!
template <typename T0>
element_type * construct(T0 & a0)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0>
element_type * construct(const T0 & a0)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0>
element_type * construct(volatile T0 & a0)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0>
element_type * construct(const volatile T0 & a0)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1>
element_type * construct(T0 & a0, T1 & a1)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1>
element_type * construct(const T0 & a0, T1 & a1)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1>
element_type * construct(volatile T0 & a0, T1 & a1)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1>
element_type * construct(const volatile T0 & a0, T1 & a1)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1>
element_type * construct(T0 & a0, const T1 & a1)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1>
element_type * construct(const T0 & a0, const T1 & a1)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1>
element_type * construct(volatile T0 & a0, const T1 & a1)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1>
element_type * construct(const volatile T0 & a0, const T1 & a1)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1>
element_type * construct(T0 & a0, volatile T1 & a1)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1>
element_type * construct(const T0 & a0, volatile T1 & a1)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1>
element_type * construct(volatile T0 & a0, volatile T1 & a1)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1>
element_type * construct(const volatile T0 & a0, volatile T1 & a1)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1>
element_type * construct(T0 & a0, const volatile T1 & a1)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1>
element_type * construct(const T0 & a0, const volatile T1 & a1)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1>
element_type * construct(volatile T0 & a0, const volatile T1 & a1)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1>
element_type * construct(const volatile T0 & a0, const volatile T1 & a1)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(T0 & a0, T1 & a1, T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const T0 & a0, T1 & a1, T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(volatile T0 & a0, T1 & a1, T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const volatile T0 & a0, T1 & a1, T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(T0 & a0, const T1 & a1, T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const T0 & a0, const T1 & a1, T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(volatile T0 & a0, const T1 & a1, T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const volatile T0 & a0, const T1 & a1, T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(T0 & a0, volatile T1 & a1, T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const T0 & a0, volatile T1 & a1, T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(volatile T0 & a0, volatile T1 & a1, T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const volatile T0 & a0, volatile T1 & a1, T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(T0 & a0, const volatile T1 & a1, T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const T0 & a0, const volatile T1 & a1, T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(volatile T0 & a0, const volatile T1 & a1, T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const volatile T0 & a0, const volatile T1 & a1, T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(T0 & a0, T1 & a1, const T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const T0 & a0, T1 & a1, const T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(volatile T0 & a0, T1 & a1, const T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const volatile T0 & a0, T1 & a1, const T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(T0 & a0, const T1 & a1, const T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const T0 & a0, const T1 & a1, const T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(volatile T0 & a0, const T1 & a1, const T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const volatile T0 & a0, const T1 & a1, const T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(T0 & a0, volatile T1 & a1, const T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const T0 & a0, volatile T1 & a1, const T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(volatile T0 & a0, volatile T1 & a1, const T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const volatile T0 & a0, volatile T1 & a1, const T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(T0 & a0, const volatile T1 & a1, const T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const T0 & a0, const volatile T1 & a1, const T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(volatile T0 & a0, const volatile T1 & a1, const T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const volatile T0 & a0, const volatile T1 & a1, const T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(T0 & a0, T1 & a1, volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const T0 & a0, T1 & a1, volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(volatile T0 & a0, T1 & a1, volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const volatile T0 & a0, T1 & a1, volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(T0 & a0, const T1 & a1, volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const T0 & a0, const T1 & a1, volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(volatile T0 & a0, const T1 & a1, volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const volatile T0 & a0, const T1 & a1, volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(T0 & a0, volatile T1 & a1, volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const T0 & a0, volatile T1 & a1, volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(volatile T0 & a0, volatile T1 & a1, volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const volatile T0 & a0, volatile T1 & a1, volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(T0 & a0, const volatile T1 & a1, volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const T0 & a0, const volatile T1 & a1, volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(volatile T0 & a0, const volatile T1 & a1, volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const volatile T0 & a0, const volatile T1 & a1, volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(T0 & a0, T1 & a1, const volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const T0 & a0, T1 & a1, const volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(volatile T0 & a0, T1 & a1, const volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const volatile T0 & a0, T1 & a1, const volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(T0 & a0, const T1 & a1, const volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const T0 & a0, const T1 & a1, const volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(volatile T0 & a0, const T1 & a1, const volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const volatile T0 & a0, const T1 & a1, const volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(T0 & a0, volatile T1 & a1, const volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const T0 & a0, volatile T1 & a1, const volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(volatile T0 & a0, volatile T1 & a1, const volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const volatile T0 & a0, volatile T1 & a1, const volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(T0 & a0, const volatile T1 & a1, const volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const T0 & a0, const volatile T1 & a1, const volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(volatile T0 & a0, const volatile T1 & a1, const volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
template <typename T0, typename T1, typename T2>
element_type * construct(const volatile T0 & a0, const volatile T1 & a1, const volatile T2 & a2)
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(a0, a1, a2); }
catch (...) { free(ret); throw; }
return ret;
}
@@ -0,0 +1,88 @@
m4_dnl
m4_dnl Copyright (C) 2000 Stephen Cleary (shammah@voyager.net)
m4_dnl
m4_dnl This file can be redistributed and/or modified under the terms found
m4_dnl in "copyright.html"
m4_dnl This software and its documentation is provided "as is" without express or
m4_dnl implied warranty, and with no claim as to its suitability for any purpose.
m4_dnl
m4_dnl See http://www.boost.org for updates, documentation, and revision history.
m4_dnl
m4_dnl
m4_dnl
m4_dnl Avoid the use of any m4_* identifiers in this header file,
m4_dnl as that may cause incompatibility problems with future
m4_dnl versions of m4.
m4_dnl
m4_dnl This is a normal header file, except that lines starting
m4_dnl with `m4_dnl' will be stripped, TBA_FOR
m4_dnl macros will be replaced with repeated text, and text in
m4_dnl single quotes (`...') will have their single quotes
m4_dnl stripped.
m4_dnl
m4_dnl
m4_dnl Check to make sure NumberOfArguments was defined. If it's not defined,
m4_dnl default to 3
m4_dnl
m4_ifdef(`NumberOfArguments', , `m4_errprint(m4___file__:m4___line__`: NumberOfArguments is not defined; defaulting to 3
')m4_define(`NumberOfArguments', 3)')m4_dnl
m4_ifelse(NumberOfArguments, , `m4_errprint(m4___file__:m4___line__`: NumberOfArguments is defined to be empty; defaulting to 3
')m4_define(`NumberOfArguments', 3)')m4_dnl
m4_dnl
m4_dnl Check to make sure NumberOfArguments >= 1. If it's not, then fatal error.
m4_dnl
m4_ifelse(m4_eval(NumberOfArguments < 1), 1, `m4_errprint(m4___file__:m4___line__`: NumberOfArguments ('NumberOfArguments`) is less than 1
')m4_m4exit(1)')m4_dnl
m4_dnl
m4_dnl Include the BOOST_M4_FOR macro definition
m4_dnl
m4_include(`for.m4')`'m4_dnl
m4_dnl
m4_dnl Begin the generated file.
m4_dnl
// Copyright (C) 2000 Stephen Cleary (shammah@voyager.net)
//
// This file can be redistributed and/or modified under the terms found
// in "copyright.html"
// This software and its documentation is provided "as is" without express or
// implied warranty, and with no claim as to its suitability for any purpose.
//
// See http://www.boost.org for updates, documentation, and revision history.
m4_dnl These warnings apply to the file generated from this file.
m4_dnl Of course, you may freely edit this file.
// This file was AUTOMATICALLY GENERATED from "m4___file__"
// Do NOT include directly!
// Do NOT edit!
m4_dnl
m4_dnl First we define a simple 'cv_qual' macro which takes a number, either
m4_dnl 0, 1, 2, or 3, and determines cv-qualification.
m4_dnl
m4_define(`cv_qual',
`m4_ifelse($1, 0, `',
`m4_ifelse($1, 1, `const ',
`m4_ifelse($1, 2, `volatile ',
`m4_ifelse($1, 3, `const volatile ',
`m4_errprint(m4___file__:m4___line__: `Boost m4 script: cv-determiner: Not 0, 1, 2, or 3 (was '$1`)')'
)')')')')m4_dnl
m4_dnl
m4_dnl Next we go through the actual loop. For each number of arguments from
m4_dnl 1 to NumberOfArguments, we create a template function that takes that
m4_dnl many template arguments, and also generate all cv-qualified permutations
m4_dnl of that function.
m4_dnl
BOOST_M4_FOR(N, 1, NumberOfArguments + 1,
`BOOST_M4_FOR(cv, 0, m4_eval(4 ** N),
`template <BOOST_M4_FOR(i, 0, N, `typename T`'i', `, ')>
element_type * construct(BOOST_M4_FOR(i, 0, N,
`cv_qual(m4_eval((cv >> (i * 2)) % 4))T`'i & a`'i', `, '))
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(BOOST_M4_FOR(i, 0, N, `a`'i', `, ')); }
catch (...) { free(ret); throw; }
return ret;
}
')')
@@ -0,0 +1,13 @@
#!/bin/sh
#
# Copyright (C) 2000 Stephen Cleary (shammah@voyager.net)
#
# This file can be redistributed and/or modified under the terms found
# in "copyright.html"
# This software and its documentation is provided "as is" without express or
# implied warranty, and with no claim as to its suitability for any purpose.
#
# See http://www.boost.org for updates, documentation, and revision history.
#
m4 -P -E -DNumberOfArguments=$1 pool_construct.m4 > pool_construct.inc
+52
View File
@@ -0,0 +1,52 @@
// Copyright (C) 2000 Stephen Cleary (shammah@voyager.net)
//
// This file can be redistributed and/or modified under the terms found
// in "copyright.html"
// This software and its documentation is provided "as is" without express or
// implied warranty, and with no claim as to its suitability for any purpose.
//
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_POOL_POSTULATE_HPP
#define BOOST_POOL_POSTULATE_HPP
// Join: merge tokens *after* macro substitution
#define BOOST_POOL_JOIN_HELPER(x, y) x ## y
#define BOOST_POOL_JOIN(x, y) BOOST_POOL_JOIN_HELPER(x, y)
// Postulate: compile-time assertion
namespace boost {
namespace details {
namespace pool {
// BOOST_POOL_POSTULATE_FAILED cannot be instantiated if its template parameter is
// false. This is what the compiler will try to do if a postulate fails.
template <bool>
struct BOOST_POOL_POSTULATE_FAILED;
template <>
struct BOOST_POOL_POSTULATE_FAILED<true> { };
// POSTULATE_helper is just a helper class used to force the implicit
// instantiation of BOOST_POOL_POSTULATE_FAILED.
template <int>
struct POSTULATE_helper { };
} // namespace pool
} // namespace details
} // namespace boost
// The postulate will try to typedef a type (*_helper) that will force
// the implicit instantiation (through sizeof) of *_FAILED. If the
// postulate is false, an error message of the form 'Undefined structure
// boost::details::pool::BOOST_POOL_POSTULATE_FAILED<0>' will result.
// Postulate uses the identifier 'BOOST_POOL_POSTULATE_on_line_' merged with the
// current line number to generate a unique identifier. For this reason,
// only one postulate is allowed per line.
#define BOOST_POOL_POSTULATE(cond) \
typedef ::boost::details::pool::POSTULATE_helper \
<sizeof(::boost::details::pool::BOOST_POOL_POSTULATE_FAILED<(cond)>)> \
BOOST_POOL_JOIN(BOOST_POOL_POSTULATE_on_line_, __LINE__)
#endif
+35
View File
@@ -0,0 +1,35 @@
// (C) Copyright David Abrahams 2001. Permission to copy, use, modify,
// sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
//
// See http://www.boost.org for most recent version including documentation.
// Revision History
// 09 Feb 01 Applied John Maddock's Borland patch Moving <true>
// specialization to unspecialized template (David Abrahams)
// 06 Feb 01 Created (David Abrahams)
#ifndef SELECT_TYPE_DWA20010206_HPP
# define SELECT_TYPE_DWA20010206_HPP
namespace boost { namespace detail {
// Template class if_true -- select among 2 types based on a bool constant expression
// Usage:
// typename if_true<(bool_const_expression)>::template then<true_type, false_type>::type
template <bool> struct if_true
{
template <class T, class F>
struct then { typedef T type; };
};
template <>
struct if_true<false>
{
template <class T, class F>
struct then { typedef F type; };
};
}}
#endif // SELECT_TYPE_DWA20010206_HPP
+98
View File
@@ -0,0 +1,98 @@
// Copyright (C) 2000 Stephen Cleary (shammah@voyager.net)
//
// This file can be redistributed and/or modified under the terms found
// in "copyright.html"
// This software and its documentation is provided "as is" without express or
// implied warranty, and with no claim as to its suitability for any purpose.
//
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_POOL_SINGLETON_HPP
#define BOOST_POOL_SINGLETON_HPP
//
// The following helper classes are placeholders for a generic "singleton"
// class. The classes below support usage of singletons, including use in
// program startup/shutdown code, AS LONG AS there is only one thread
// running before main() begins, and only one thread running after main()
// exits.
//
// This class is also limited in that it can only provide singleton usage for
// classes with default constructors.
//
// The design of this class is somewhat twisted, but can be followed by the
// calling inheritance. Let us assume that there is some user code that
// calls "singleton_default<T>::instance()". The following (convoluted)
// sequence ensures that the same function will be called before main():
// instance() contains a call to create_object.do_nothing()
// Thus, object_creator is implicitly instantiated, and create_object
// must exist.
// Since create_object is a static member, its constructor must be
// called before main().
// The constructor contains a call to instance(), thus ensuring that
// instance() will be called before main().
// The first time instance() is called (i.e., before main()) is the
// latest point in program execution where the object of type T
// can be created.
// Thus, any call to instance() will auto-magically result in a call to
// instance() before main(), unless already present.
// Furthermore, since the instance() function contains the object, instead
// of the singleton_default class containing a static instance of the
// object, that object is guaranteed to be constructed (at the latest) in
// the first call to instance(). This permits calls to instance() from
// static code, even if that code is called before the file-scope objects
// in this file have been initialized.
namespace boost {
namespace details {
namespace pool {
// T must be: no-throw default constructible and no-throw destructible
template <typename T>
struct singleton_default
{
private:
struct object_creator
{
// This constructor does nothing more than ensure that instance()
// is called before main() begins, thus creating the static
// T object before multithreading race issues can come up.
object_creator() { singleton_default::instance(); }
inline void do_nothing() const { }
};
static object_creator create_object;
singleton_default();
public:
typedef T object_type;
// If, at any point (in user code), singleton_default<T>::instance()
// is called, then the following function is instantiated.
static object_type & instance()
{
// This is the object that we return a reference to.
// It is guaranteed to be created before main() begins because of
// the next line.
static object_type obj;
// The following line does nothing else than force the instantiation
// of singleton_default<T>::create_object, whose constructor is
// called before main() begins.
create_object.do_nothing();
return obj;
}
};
template <typename T>
typename singleton_default<T>::object_creator
singleton_default<T>::create_object;
} // namespace pool
} // namespace details
} // namespace boost
#endif
+124
View File
@@ -0,0 +1,124 @@
// Copyright (C) 2000, 2001 Stephen Cleary (shammah@voyager.net)
//
// This file can be redistributed and/or modified under the terms found
// in "copyright.html"
// This software and its documentation is provided "as is" without express or
// implied warranty, and with no claim as to its suitability for any purpose.
//
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_OBJECT_POOL_HPP
#define BOOST_OBJECT_POOL_HPP
#include <boost/pool/object_pool_fwd.hpp>
// boost::pool
#include <boost/pool/pool.hpp>
namespace boost {
// T must have a non-throwing destructor
template <typename T, typename UserAllocator>
class object_pool: protected pool<UserAllocator>
{
public:
typedef T element_type;
typedef UserAllocator user_allocator;
typedef typename pool<UserAllocator>::size_type size_type;
typedef typename pool<UserAllocator>::difference_type difference_type;
public:
// This constructor parameter is an extension!
explicit object_pool(const size_type next_size = 32)
:pool<UserAllocator>(sizeof(T), next_size) { }
~object_pool();
// Returns 0 if out-of-memory
element_type * malloc()
{ return static_cast<element_type *>(pool<UserAllocator>::ordered_malloc()); }
void free(element_type * const chunk)
{ pool<UserAllocator>::ordered_free(chunk); }
bool is_from(element_type * const chunk) const
{ return pool<UserAllocator>::is_from(chunk); }
element_type * construct()
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(); }
catch (...) { free(ret); throw; }
return ret;
}
// Include automatically-generated file for family of template construct()
// functions
#include <boost/pool/detail/pool_construct.inc>
void destroy(element_type * const chunk)
{
chunk->~T();
free(chunk);
}
// These functions are extensions!
size_type get_next_size() const { return pool<UserAllocator>::get_next_size(); }
void set_next_size(const size_type x) { pool<UserAllocator>::set_next_size(x); }
};
template <typename T, typename UserAllocator>
object_pool<T, UserAllocator>::~object_pool()
{
// handle trivial case
if (!list.valid())
return;
details::PODptr<size_type> iter = list;
details::PODptr<size_type> next = iter;
// Start 'freed_iter' at beginning of free list
void * freed_iter = first;
const size_type partition_size = alloc_size();
do
{
// increment next
next = next.next();
// delete all contained objects that aren't freed
// Iterate 'i' through all chunks in the memory block
for (char * i = iter.begin(); i != iter.end(); i += partition_size)
{
// If this chunk is free
if (i == freed_iter)
{
// Increment freed_iter to point to next in free list
freed_iter = nextof(freed_iter);
// Continue searching chunks in the memory block
continue;
}
// This chunk is not free (allocated), so call its destructor
static_cast<T *>(static_cast<void *>(i))->~T();
// and continue searching chunks in the memory block
}
// free storage
UserAllocator::free(iter.begin());
// increment iter
iter = next;
} while (iter.valid());
// Make the block list empty so that the inherited destructor doesn't try to
// free it again.
list.invalidate();
}
} // namespace boost
#endif
+23
View File
@@ -0,0 +1,23 @@
// Copyright (C) 2000, 2001 Stephen Cleary (shammah@voyager.net)
//
// This file can be redistributed and/or modified under the terms found
// in "copyright.html"
// This software and its documentation is provided "as is" without express or
// implied warranty, and with no claim as to its suitability for any purpose.
//
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_OBJECT_POOL_FWD_HPP
#define BOOST_OBJECT_POOL_FWD_HPP
// boost::default_user_allocator_new_delete fwd
#include <boost/pool/pool_fwd.hpp>
namespace boost {
template <typename T, typename UserAllocator = default_user_allocator_new_delete>
class object_pool;
} // namespace boost
#endif
+549
View File
@@ -0,0 +1,549 @@
// Copyright (C) 2000, 2001 Stephen Cleary (shammah@voyager.net)
//
// This file can be redistributed and/or modified under the terms found
// in "copyright.html"
// This software and its documentation is provided "as is" without express or
// implied warranty, and with no claim as to its suitability for any purpose.
//
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_POOL_HPP
#define BOOST_POOL_HPP
#include <boost/config.hpp> // for workarounds
// std::less, std::less_equal, std::greater
#include <functional>
// new[], delete[], std::nothrow
#include <new>
// std::size_t, std::ptrdiff_t
#include <cstddef>
// std::malloc, std::free
#include <cstdlib>
// std::invalid_argument
#include <exception>
#include <boost/pool/pool_fwd.hpp>
// boost::details::pool::ct_lcm
#include <boost/pool/detail/ct_gcd_lcm.hpp>
// boost::details::pool::lcm
#include <boost/pool/detail/gcd_lcm.hpp>
// boost::simple_segregated_storage
#include <boost/pool/simple_segregated_storage.hpp>
namespace boost {
struct default_user_allocator_new_delete
{
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
static char * malloc(const size_type bytes)
{ return new (std::nothrow) char[bytes]; }
static void free(char * const block)
{ delete [] block; }
};
struct default_user_allocator_malloc_free
{
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
static char * malloc(const size_type bytes)
{ return reinterpret_cast<char *>(std::malloc(bytes)); }
static void free(char * const block)
{ std::free(block); }
};
namespace details {
// PODptr is a class that pretends to be a "pointer" to different class types
// that don't really exist. It provides member functions to access the "data"
// of the "object" it points to. Since these "class" types are of variable
// size, and contains some information at the *end* of its memory (for
// alignment reasons), PODptr must contain the size of this "class" as well as
// the pointer to this "object".
template <typename SizeType>
class PODptr
{
public:
typedef SizeType size_type;
private:
char * ptr;
size_type sz;
char * ptr_next_size() const
{ return (ptr + sz - sizeof(size_type)); }
char * ptr_next_ptr() const
{
return (ptr_next_size() -
pool::ct_lcm<sizeof(size_type), sizeof(void *)>::value);
}
public:
PODptr(char * const nptr, const size_type nsize)
:ptr(nptr), sz(nsize) { }
PODptr()
:ptr(0), sz(0) { }
bool valid() const { return (begin() != 0); }
void invalidate() { begin() = 0; }
char * & begin() { return ptr; }
char * begin() const { return ptr; }
char * end() const { return ptr_next_ptr(); }
size_type total_size() const { return sz; }
size_type element_size() const
{
return (sz - sizeof(size_type) -
pool::ct_lcm<sizeof(size_type), sizeof(void *)>::value);
}
size_type & next_size() const
{ return *(reinterpret_cast<size_type *>(ptr_next_size())); }
char * & next_ptr() const
{ return *(reinterpret_cast<char **>(ptr_next_ptr())); }
PODptr next() const
{ return PODptr<size_type>(next_ptr(), next_size()); }
void next(const PODptr & arg) const
{
next_ptr() = arg.begin();
next_size() = arg.total_size();
}
};
} // namespace details
template <typename UserAllocator>
class pool: protected simple_segregated_storage<
typename UserAllocator::size_type>
{
public:
typedef UserAllocator user_allocator;
typedef typename UserAllocator::size_type size_type;
typedef typename UserAllocator::difference_type difference_type;
private:
static const unsigned min_alloc_size =
details::pool::ct_lcm<sizeof(void *), sizeof(size_type)>::value;
// Returns 0 if out-of-memory
// Called if malloc/ordered_malloc needs to resize the free list
void * malloc_need_resize();
void * ordered_malloc_need_resize();
protected:
details::PODptr<size_type> list;
simple_segregated_storage<size_type> & store() { return *this; }
const simple_segregated_storage<size_type> & store() const { return *this; }
const size_type requested_size;
size_type next_size;
// finds which POD in the list 'chunk' was allocated from
details::PODptr<size_type> find_POD(void * const chunk) const;
// is_from() tests a chunk to determine if it belongs in a block
static bool is_from(void * const chunk, char * const i,
const size_type sizeof_i)
{
// We use std::less_equal and std::less to test 'chunk'
// against the array bounds because standard operators
// may return unspecified results.
// This is to ensure portability. The operators < <= > >= are only
// defined for pointers to objects that are 1) in the same array, or
// 2) subobjects of the same object [5.9/2].
// The functor objects guarantee a total order for any pointer [20.3.3/8]
//WAS:
// return (std::less_equal<void *>()(static_cast<void *>(i), chunk)
// && std::less<void *>()(chunk,
// static_cast<void *>(i + sizeof_i)));
std::less_equal<void *> lt_eq;
std::less<void *> lt;
return (lt_eq(i, chunk) && lt(chunk, i + sizeof_i));
}
size_type alloc_size() const
{
const unsigned min_size = min_alloc_size;
return details::pool::lcm<size_type>(requested_size, min_size);
}
public:
// The second parameter here is an extension!
// pre: npartition_size != 0 && nnext_size != 0
explicit pool(const size_type nrequested_size,
const size_type nnext_size = 32)
:list(0, 0), requested_size(nrequested_size), next_size(nnext_size)
{ }
~pool() { purge_memory(); }
// Releases memory blocks that don't have chunks allocated
// pre: lists are ordered
// Returns true if memory was actually deallocated
bool release_memory();
// Releases *all* memory blocks, even if chunks are still allocated
// Returns true if memory was actually deallocated
bool purge_memory();
// These functions are extensions!
size_type get_next_size() const { return next_size; }
void set_next_size(const size_type nnext_size) { next_size = nnext_size; }
// Both malloc and ordered_malloc do a quick inlined check first for any
// free chunks. Only if we need to get another memory block do we call
// the non-inlined *_need_resize() functions.
// Returns 0 if out-of-memory
void * malloc()
{
// Look for a non-empty storage
if (!store().empty())
return store().malloc();
return malloc_need_resize();
}
void * ordered_malloc()
{
// Look for a non-empty storage
if (!store().empty())
return store().malloc();
return ordered_malloc_need_resize();
}
// Returns 0 if out-of-memory
// Allocate a contiguous section of n chunks
void * ordered_malloc(size_type n);
// pre: 'chunk' must have been previously
// returned by *this.malloc().
void free(void * const chunk)
{ store().free(chunk); }
// pre: 'chunk' must have been previously
// returned by *this.malloc().
void ordered_free(void * const chunk)
{ store().ordered_free(chunk); }
// pre: 'chunk' must have been previously
// returned by *this.malloc(n).
void free(void * const chunks, const size_type n)
{
const size_type partition_size = alloc_size();
const size_type total_req_size = n * requested_size;
const size_type num_chunks = total_req_size / partition_size +
static_cast<bool>(total_req_size % partition_size);
store().free_n(chunks, num_chunks, partition_size);
}
// pre: 'chunk' must have been previously
// returned by *this.malloc(n).
void ordered_free(void * const chunks, const size_type n)
{
const size_type partition_size = alloc_size();
const size_type total_req_size = n * requested_size;
const size_type num_chunks = total_req_size / partition_size +
static_cast<bool>(total_req_size % partition_size);
store().ordered_free_n(chunks, num_chunks, partition_size);
}
// is_from() tests a chunk to determine if it was allocated from *this
bool is_from(void * const chunk) const
{
return (find_POD(chunk).valid());
}
};
template <typename UserAllocator>
bool pool<UserAllocator>::release_memory()
{
// This is the return value: it will be set to true when we actually call
// UserAllocator::free(..)
bool ret = false;
// This is a current & previous iterator pair over the memory block list
details::PODptr<size_type> ptr = list;
details::PODptr<size_type> prev;
// This is a current & previous iterator pair over the free memory chunk list
// Note that "prev_free" in this case does NOT point to the previous memory
// chunk in the free list, but rather the last free memory chunk before the
// current block.
void * free = first;
void * prev_free = 0;
const size_type partition_size = alloc_size();
// Search through all the all the allocated memory blocks
while (ptr.valid())
{
// At this point:
// ptr points to a valid memory block
// free points to either:
// 0 if there are no more free chunks
// the first free chunk in this or some next memory block
// prev_free points to either:
// the last free chunk in some previous memory block
// 0 if there is no such free chunk
// If there are no more free memory chunks, then every remaining
// block is allocated out to its fullest capacity, and we can't
// release any more memory
if (free == 0)
return ret;
// We have to check all the chunks. If they are *all* free (i.e., present
// in the free list), then we can free the block.
bool all_chunks_free = true;
// Iterate 'i' through all chunks in the memory block
for (char * i = ptr.begin(); i != ptr.end(); i += partition_size)
{
// If this chunk is not free
if (i != free)
{
// We won't be able to free this block
all_chunks_free = false;
// Abort searching the chunks; we won't be able to free this
// block because a chunk is not free.
break;
}
// We do not increment prev_free because we are in the same block
free = nextof(free);
}
const details::PODptr<size_type> next = ptr.next();
if (!all_chunks_free)
{
// Rush through all free chunks from this block
std::less<void *> lt;
void * const last = ptr.end() - partition_size;
do
{
free = nextof(free);
} while (lt(free, last));
// Increment free one more time and set prev_free to maintain the
// invariants:
// free points to the first free chunk in some next memory block, or
// 0 if there is no such chunk.
// prev_free points to the last free chunk in this memory block.
prev_free = free;
free = nextof(free);
}
else
{
// All chunks from this block are free
// Remove block from list
if (prev.valid())
prev.next(next);
else
list = next;
// Remove all entries in the free list from this block
if (prev_free != 0)
nextof(prev_free) = free;
else
first = free;
// And release memory
UserAllocator::free(ptr.begin());
ret = true;
}
// Increment ptr
ptr = next;
}
return ret;
}
template <typename UserAllocator>
bool pool<UserAllocator>::purge_memory()
{
details::PODptr<size_type> iter = list;
if (!iter.valid())
return false;
do
{
// hold "next" pointer
const details::PODptr<size_type> next = iter.next();
// delete the storage
UserAllocator::free(iter.begin());
// increment iter
iter = next;
} while (iter.valid());
list.invalidate();
first = 0;
return true;
}
template <typename UserAllocator>
void * pool<UserAllocator>::malloc_need_resize()
{
// No memory in any of our storages; make a new storage,
const size_type partition_size = alloc_size();
const size_type POD_size = next_size * partition_size +
details::pool::ct_lcm<sizeof(size_type), sizeof(void *)>::value + sizeof(size_type);
char * const ptr = UserAllocator::malloc(POD_size);
if (ptr == 0)
return 0;
const details::PODptr<size_type> node(ptr, POD_size);
next_size <<= 1;
// initialize it,
store().add_block(node.begin(), node.element_size(), partition_size);
// insert it into the list,
node.next(list);
list = node;
// and return a chunk from it.
return store().malloc();
}
template <typename UserAllocator>
void * pool<UserAllocator>::ordered_malloc_need_resize()
{
// No memory in any of our storages; make a new storage,
const size_type partition_size = alloc_size();
const size_type POD_size = next_size * partition_size +
details::pool::ct_lcm<sizeof(size_type), sizeof(void *)>::value + sizeof(size_type);
char * const ptr = UserAllocator::malloc(POD_size);
if (ptr == 0)
return 0;
const details::PODptr<size_type> node(ptr, POD_size);
next_size <<= 1;
// initialize it,
// (we can use "add_block" here because we know that
// the free list is empty, so we don't have to use
// the slower ordered version)
store().add_block(node.begin(), node.element_size(), partition_size);
// insert it into the list,
// handle border case
if (!list.valid() || std::greater<void *>()(list.begin(), node.begin()))
{
node.next(list);
list = node;
}
else
{
details::PODptr<size_type> prev = list;
while (true)
{
// if we're about to hit the end or
// if we've found where "node" goes
if (prev.next_ptr() == 0
|| std::greater<void *>()(prev.next_ptr(), node.begin()))
break;
prev = prev.next();
}
node.next(prev.next());
prev.next(node);
}
// and return a chunk from it.
return store().malloc();
}
template <typename UserAllocator>
void * pool<UserAllocator>::ordered_malloc(const pool::size_type n)
{
const size_type partition_size = alloc_size();
const size_type total_req_size = n * requested_size;
const size_type num_chunks = total_req_size / partition_size +
static_cast<bool>(total_req_size % partition_size);
void * ret = store().malloc_n(num_chunks, partition_size);
if (ret != 0)
return ret;
// Not enougn memory in our storages; make a new storage,
next_size = std::max(next_size, num_chunks);
const size_type POD_size = next_size * partition_size +
details::pool::ct_lcm<sizeof(size_type), sizeof(void *)>::value + sizeof(size_type);
char * const ptr = UserAllocator::malloc(POD_size);
if (ptr == 0)
return 0;
const details::PODptr<size_type> node(ptr, POD_size);
// Split up block so we can use what wasn't requested
// (we can use "add_block" here because we know that
// the free list is empty, so we don't have to use
// the slower ordered version)
if (next_size > num_chunks)
store().add_block(node.begin() + num_chunks * partition_size,
node.element_size() - num_chunks * partition_size, partition_size);
next_size <<= 1;
// insert it into the list,
// handle border case
if (!list.valid() || std::greater<void *>()(list.begin(), node.begin()))
{
node.next(list);
list = node;
}
else
{
details::PODptr<size_type> prev = list;
while (true)
{
// if we're about to hit the end or
// if we've found where "node" goes
if (prev.next_ptr() == 0
|| std::greater<void *>()(prev.next_ptr(), node.begin()))
break;
prev = prev.next();
}
node.next(prev.next());
prev.next(node);
}
// and return it.
return node.begin();
}
template <typename UserAllocator>
details::PODptr<typename pool<UserAllocator>::size_type>
pool<UserAllocator>::find_POD(void * const chunk) const
{
// We have to find which storage this chunk is from.
details::PODptr<size_type> iter = list;
while (iter.valid())
{
if (is_from(chunk, iter.begin(), iter.element_size()))
return iter;
iter = iter.next();
}
return iter;
}
} // namespace boost
#endif
+220
View File
@@ -0,0 +1,220 @@
// Copyright (C) 2000, 2001 Stephen Cleary (shammah@voyager.net)
//
// This file can be redistributed and/or modified under the terms found
// in "copyright.html"
// This software and its documentation is provided "as is" without express or
// implied warranty, and with no claim as to its suitability for any purpose.
//
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_POOL_ALLOC_HPP
#define BOOST_POOL_ALLOC_HPP
// std::numeric_limits
#include <limits>
// new, std::bad_alloc
#include <new>
#include <boost/pool/pool_alloc_fwd.hpp>
// boost::singleton_pool
#include <boost/pool/singleton_pool.hpp>
#if defined(_RWSTD_VER) && (_RWSTD_VER <= 0x020101)
// Needed, as of BCB5 & cl 5.5
#define BOOST_POOL_ALLOC_ALLOW_NULL_DEALLOCATE
#endif
#if defined(__SGI_STL_PORT) && (__SGI_STL_PORT <= 0x400)
// Needed, as of STLport 4.0
#define BOOST_POOL_ALLOC_ALLOW_NULL_DEALLOCATE
#endif
namespace boost {
struct pool_allocator_tag { };
template <typename T,
typename UserAllocator,
typename Mutex,
unsigned NextSize>
class pool_allocator
{
public:
typedef T value_type;
typedef UserAllocator user_allocator;
typedef Mutex mutex;
static const unsigned next_size = NextSize;
typedef value_type * pointer;
typedef const value_type * const_pointer;
typedef value_type & reference;
typedef const value_type & const_reference;
typedef typename pool<UserAllocator>::size_type size_type;
typedef typename pool<UserAllocator>::difference_type difference_type;
template <typename U>
struct rebind
{
typedef pool_allocator<U, UserAllocator, Mutex, NextSize> other;
};
public:
pool_allocator() { }
// default copy constructor
// default assignment operator
// not explicit, mimicking std::allocator [20.4.1]
template <typename U>
pool_allocator(const pool_allocator<U, UserAllocator, Mutex, NextSize> &)
{ }
// default destructor
static pointer address(reference r)
{ return &r; }
static const_pointer address(const_reference s)
{ return &s; }
static size_type max_size()
{ return std::numeric_limits<size_type>::max(); }
static void construct(const pointer ptr, const value_type & t)
{ new (ptr) T(t); }
static void destroy(const pointer ptr)
{ ptr->~T(); }
bool operator==(const pool_allocator &) const
{ return true; }
bool operator!=(const pool_allocator &) const
{ return false; }
static pointer allocate(const size_type n)
{
const pointer ret = static_cast<pointer>(
singleton_pool<pool_allocator_tag, sizeof(T), UserAllocator, Mutex,
NextSize>::ordered_malloc(n) );
if (ret == 0)
throw std::bad_alloc();
return ret;
}
static pointer allocate(const size_type n, const pointer)
{ return allocate(n); }
static void deallocate(const pointer ptr, const size_type n)
{
#ifdef BOOST_POOL_ALLOC_ALLOW_NULL_DEALLOCATE
if (ptr == 0 || n == 0)
return;
#endif
singleton_pool<pool_allocator_tag, sizeof(T), UserAllocator, Mutex,
NextSize>::ordered_free(ptr, n);
}
};
struct fast_pool_allocator_tag { };
template <typename T,
typename UserAllocator,
typename Mutex,
unsigned NextSize>
class fast_pool_allocator
{
public:
typedef T value_type;
typedef UserAllocator user_allocator;
typedef Mutex mutex;
static const unsigned next_size = NextSize;
typedef value_type * pointer;
typedef const value_type * const_pointer;
typedef value_type & reference;
typedef const value_type & const_reference;
typedef typename pool<UserAllocator>::size_type size_type;
typedef typename pool<UserAllocator>::difference_type difference_type;
template <typename U>
struct rebind
{
typedef fast_pool_allocator<U, UserAllocator, Mutex, NextSize> other;
};
public:
fast_pool_allocator() { }
// default copy constructor
// default assignment operator
// not explicit, mimicking std::allocator [20.4.1]
template <typename U>
fast_pool_allocator(
const fast_pool_allocator<U, UserAllocator, Mutex, NextSize> &)
{ }
// default destructor
static pointer address(reference r)
{ return &r; }
static const_pointer address(const_reference s)
{ return &s; }
static size_type max_size()
{ return std::numeric_limits<size_type>::max(); }
void construct(const pointer ptr, const value_type & t)
{ new (ptr) T(t); }
void destroy(const pointer ptr)
{ ptr->~T(); }
bool operator==(const fast_pool_allocator &) const
{ return true; }
bool operator!=(const fast_pool_allocator &) const
{ return false; }
static pointer allocate(const size_type n)
{
const pointer ret = (n == 1) ?
static_cast<pointer>(
singleton_pool<fast_pool_allocator_tag, sizeof(T),
UserAllocator, Mutex, NextSize>::malloc() ) :
static_cast<pointer>(
singleton_pool<fast_pool_allocator_tag, sizeof(T),
UserAllocator, Mutex, NextSize>::ordered_malloc(n) );
if (ret == 0)
throw std::bad_alloc();
return ret;
}
static pointer allocate(const size_type n, const pointer)
{ return allocate(n); }
static pointer allocate()
{
const pointer ret = static_cast<pointer>(
singleton_pool<fast_pool_allocator_tag, sizeof(T),
UserAllocator, Mutex, NextSize>::malloc() );
if (ret == 0)
throw std::bad_alloc();
return ret;
}
static void deallocate(const pointer ptr, const size_type n)
{
#ifdef BOOST_POOL_ALLOC_ALLOW_NULL_DEALLOCATE
if (ptr == 0 || n == 0)
return;
#endif
if (n == 1)
singleton_pool<fast_pool_allocator_tag, sizeof(T),
UserAllocator, Mutex, NextSize>::free(ptr);
else
singleton_pool<fast_pool_allocator_tag, sizeof(T),
UserAllocator, Mutex, NextSize>::free(ptr, n);
}
static void deallocate(const pointer ptr)
{
singleton_pool<fast_pool_allocator_tag, sizeof(T),
UserAllocator, Mutex, NextSize>::free(ptr);
}
};
} // namespace boost
#undef BOOST_POOL_ALLOC_ALLOW_NULL_DEALLOCATE
#endif
+38
View File
@@ -0,0 +1,38 @@
// Copyright (C) 2000, 2001 Stephen Cleary (shammah@voyager.net)
//
// This file can be redistributed and/or modified under the terms found
// in "copyright.html"
// This software and its documentation is provided "as is" without express or
// implied warranty, and with no claim as to its suitability for any purpose.
//
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_POOL_ALLOC_FWD_HPP
#define BOOST_POOL_ALLOC_FWD_HPP
// boost::details::pool::default_mutex
#include <boost/pool/detail/mutex.hpp>
// boost::default_user_allocator_new_delete fwd
#include <boost/pool/pool_fwd.hpp>
namespace boost {
struct pool_allocator_tag;
template <typename T,
typename UserAllocator = default_user_allocator_new_delete,
typename Mutex = details::pool::default_mutex,
unsigned NextSize = 32>
class pool_allocator;
struct fast_pool_allocator_tag;
template <typename T,
typename UserAllocator = default_user_allocator_new_delete,
typename Mutex = details::pool::default_mutex,
unsigned NextSize = 32>
class fast_pool_allocator;
} // namespace boost
#endif
+23
View File
@@ -0,0 +1,23 @@
// Copyright (C) 2000, 2001 Stephen Cleary (shammah@voyager.net)
//
// This file can be redistributed and/or modified under the terms found
// in "copyright.html"
// This software and its documentation is provided "as is" without express or
// implied warranty, and with no claim as to its suitability for any purpose.
//
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_POOL_FWD_HPP
#define BOOST_POOL_FWD_HPP
namespace boost {
struct default_user_allocator_new_delete;
struct default_user_allocator_malloc_free;
template <typename UserAllocator = default_user_allocator_new_delete>
class pool;
} // namespace boost
#endif
@@ -0,0 +1,270 @@
// Copyright (C) 2000, 2001 Stephen Cleary (shammah@voyager.net)
//
// This file can be redistributed and/or modified under the terms found
// in "copyright.html"
// This software and its documentation is provided "as is" without express or
// implied warranty, and with no claim as to its suitability for any purpose.
//
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_SIMPLE_SEGREGATED_STORAGE_HPP
#define BOOST_SIMPLE_SEGREGATED_STORAGE_HPP
// std::greater
#include <functional>
#include <boost/pool/simple_segregated_storage_fwd.hpp>
namespace boost {
template <typename SizeType>
class simple_segregated_storage
{
public:
typedef SizeType size_type;
private:
simple_segregated_storage(const simple_segregated_storage &);
void operator=(const simple_segregated_storage &);
// pre: (n > 0), (start != 0), (nextof(start) != 0)
// post: (start != 0)
static void * try_malloc_n(void * & start, size_type n,
size_type partition_size);
protected:
void * first;
// Traverses the free list referred to by "first",
// and returns the iterator previous to where
// "ptr" would go if it was in the free list.
// Returns 0 if "ptr" would go at the beginning
// of the free list (i.e., before "first")
void * find_prev(void * ptr);
// for the sake of code readability :)
static void * & nextof(void * const ptr)
{ return *(static_cast<void **>(ptr)); }
public:
// Post: empty()
simple_segregated_storage()
:first(0) { }
// pre: npartition_sz >= sizeof(void *)
// npartition_sz = sizeof(void *) * i, for some integer i
// nsz >= npartition_sz
// block is properly aligned for an array of object of
// size npartition_sz and array of void *
// The requirements above guarantee that any pointer to a chunk
// (which is a pointer to an element in an array of npartition_sz)
// may be cast to void **.
static void * segregate(void * block,
size_type nsz, size_type npartition_sz,
void * end = 0);
// Same preconditions as 'segregate'
// Post: !empty()
void add_block(void * const block,
const size_type nsz, const size_type npartition_sz)
{
// Segregate this block and merge its free list into the
// free list referred to by "first"
first = segregate(block, nsz, npartition_sz, first);
}
// Same preconditions as 'segregate'
// Post: !empty()
void add_ordered_block(void * const block,
const size_type nsz, const size_type npartition_sz)
{
// This (slower) version of add_block segregates the
// block and merges its free list into our free list
// in the proper order
// Find where "block" would go in the free list
void * const loc = find_prev(block);
// Place either at beginning or in middle/end
if (loc == 0)
add_block(block, nsz, npartition_sz);
else
nextof(loc) = segregate(block, nsz, npartition_sz, nextof(loc));
}
// default destructor
bool empty() const { return (first == 0); }
// pre: !empty()
void * malloc()
{
void * const ret = first;
// Increment the "first" pointer to point to the next chunk
first = nextof(first);
return ret;
}
// pre: chunk was previously returned from a malloc() referring to the
// same free list
// post: !empty()
void free(void * const chunk)
{
nextof(chunk) = first;
first = chunk;
}
// pre: chunk was previously returned from a malloc() referring to the
// same free list
// post: !empty()
void ordered_free(void * const chunk)
{
// This (slower) implementation of 'free' places the memory
// back in the list in its proper order.
// Find where "chunk" goes in the free list
void * const loc = find_prev(chunk);
// Place either at beginning or in middle/end
if (loc == 0)
free(chunk);
else
{
nextof(chunk) = nextof(loc);
nextof(loc) = chunk;
}
}
// pre: !empty()
// Note: if you're allocating/deallocating n a lot, you should
// be using an ordered pool.
void * malloc_n(size_type n, size_type partition_size);
// pre: !empty()
void * ordered_malloc_n(size_type n, size_type partition_size);
// pre: chunks was previously allocated from *this with the same
// values for n and partition_size
// post: !empty()
// Note: if you're allocating/deallocating n a lot, you should
// be using an ordered pool.
void free_n(void * const chunks, const size_type n,
const size_type partition_size)
{
add_block(chunks, n * partition_size, partition_size);
}
// pre: chunks was previously allocated from *this with the same
// values for n and partition_size
// post: !empty()
void ordered_free_n(void * const chunks, const size_type n,
const size_type partition_size)
{
add_ordered_block(chunks, n * partition_size, partition_size);
}
};
template <typename SizeType>
void * simple_segregated_storage<SizeType>::find_prev(void * const ptr)
{
// Handle border case
if (first == 0 || std::greater<void *>()(first, ptr))
return 0;
void * iter = first;
while (true)
{
// if we're about to hit the end or
// if we've found where "ptr" goes
if (nextof(iter) == 0 || std::greater<void *>()(nextof(iter), ptr))
return iter;
iter = nextof(iter);
}
}
template <typename SizeType>
void * simple_segregated_storage<SizeType>::segregate(
void * const block,
const size_type sz,
const size_type partition_sz,
void * const end)
{
// Get pointer to last valid chunk, preventing overflow on size calculations
// The division followed by the multiplication just makes sure that
// old == block + partition_sz * i, for some integer i, even if the
// block size (sz) is not a multiple of the partition size.
char * old = static_cast<char *>(block)
+ ((sz - partition_sz) / partition_sz) * partition_sz;
// Set it to point to the end
nextof(old) = end;
// Handle border case where sz == partition_sz (i.e., we're handling an array
// of 1 element)
if (old == block)
return block;
// Iterate backwards, building a singly-linked list of pointers
for (char * iter = old - partition_sz; iter != block;
old = iter, iter -= partition_sz)
nextof(iter) = old;
// Point the first pointer, too
nextof(block) = old;
return block;
}
// The following function attempts to find n contiguous chunks
// of size partition_size in the free list, starting at start.
// If it succeds, it returns the last chunk in that contiguous
// sequence, so that the sequence is known by [start, {retval}]
// If it fails, it does do either because it's at the end of the
// free list or hits a non-contiguous chunk. In either case,
// it will return 0, and set start to the last considered
// chunk. You are at the end of the free list if
// nextof(start) == 0. Otherwise, start points to the last
// chunk in the contiguous sequence, and nextof(start) points
// to the first chunk in the next contiguous sequence (assuming
// an ordered free list)
template <typename SizeType>
void * simple_segregated_storage<SizeType>::try_malloc_n(
void * & start, size_type n, const size_type partition_size)
{
void * iter = nextof(start);
while (--n != 0)
{
void * next = nextof(iter);
if (next != static_cast<char *>(iter) + partition_size)
{
// next == 0 (end-of-list) or non-contiguous chunk found
start = iter;
return 0;
}
iter = next;
}
return iter;
}
template <typename SizeType>
void * simple_segregated_storage<SizeType>::malloc_n(const size_type n,
const size_type partition_size)
{
void * start = &first;
void * iter;
do
{
if (nextof(start) == 0)
return 0;
iter = try_malloc_n(start, n, partition_size);
} while (iter == 0);
void * const ret = nextof(start);
nextof(start) = nextof(iter);
return ret;
}
} // namespace boost
#endif
@@ -0,0 +1,23 @@
// Copyright (C) 2000 Stephen Cleary (shammah@voyager.net)
//
// This file can be redistributed and/or modified under the terms found
// in "copyright.html"
// This software and its documentation is provided "as is" without express or
// implied warranty, and with no claim as to its suitability for any purpose.
//
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_SIMPLE_SEGREGATED_STORAGE_FWD_HPP
#define BOOST_SIMPLE_SEGREGATED_STORAGE_FWD_HPP
// std::size_t
#include <cstddef>
namespace boost {
template <typename SizeType = std::size_t>
class simple_segregated_storage;
} // namespace boost
#endif
+120
View File
@@ -0,0 +1,120 @@
// Copyright (C) 2000, 2001 Stephen Cleary (shammah@voyager.net)
//
// This file can be redistributed and/or modified under the terms found
// in "copyright.html"
// This software and its documentation is provided "as is" without express or
// implied warranty, and with no claim as to its suitability for any purpose.
//
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_SINGLETON_POOL_HPP
#define BOOST_SINGLETON_POOL_HPP
#include <boost/pool/singleton_pool_fwd.hpp>
// boost::pool
#include <boost/pool/pool.hpp>
// boost::details::pool::singleton_default
#include <boost/pool/detail/singleton.hpp>
// boost::details::pool::guard
#include <boost/pool/detail/guard.hpp>
namespace boost {
//
// The singleton_pool class allows other pool interfaces for types of the same
// size to share the same pool
//
template <typename Tag, unsigned RequestedSize,
typename UserAllocator,
typename Mutex,
unsigned NextSize>
struct singleton_pool
{
public:
typedef Tag tag;
typedef Mutex mutex;
typedef UserAllocator user_allocator;
typedef typename pool<UserAllocator>::size_type size_type;
typedef typename pool<UserAllocator>::difference_type difference_type;
static const unsigned requested_size = RequestedSize;
static const unsigned next_size = NextSize;
private:
struct pool_type: Mutex
{
pool<UserAllocator> p;
pool_type():p(RequestedSize, NextSize) { }
};
typedef details::pool::singleton_default<pool_type> singleton;
singleton_pool();
public:
static void * malloc()
{
pool_type & p = singleton::instance();
details::pool::guard<Mutex> g(p);
return p.p.malloc();
}
static void * ordered_malloc()
{
pool_type & p = singleton::instance();
details::pool::guard<Mutex> g(p);
return p.p.ordered_malloc();
}
static void * ordered_malloc(const size_type n)
{
pool_type & p = singleton::instance();
details::pool::guard<Mutex> g(p);
return p.p.ordered_malloc(n);
}
static bool is_from(void * const ptr)
{
pool_type & p = singleton::instance();
details::pool::guard<Mutex> g(p);
return p.p.is_from(ptr);
}
static void free(void * const ptr)
{
pool_type & p = singleton::instance();
details::pool::guard<Mutex> g(p);
p.p.free(ptr);
}
static void ordered_free(void * const ptr)
{
pool_type & p = singleton::instance();
details::pool::guard<Mutex> g(p);
p.p.ordered_free(ptr);
}
static void free(void * const ptr, const std::size_t n)
{
pool_type & p = singleton::instance();
details::pool::guard<Mutex> g(p);
p.p.free(ptr, n);
}
static void ordered_free(void * const ptr, const size_type n)
{
pool_type & p = singleton::instance();
details::pool::guard<Mutex> g(p);
p.p.ordered_free(ptr, n);
}
static bool release_memory()
{
pool_type & p = singleton::instance();
details::pool::guard<Mutex> g(p);
return p.release_memory();
}
static bool purge_memory()
{
pool_type & p = singleton::instance();
details::pool::guard<Mutex> g(p);
return p.purge_memory();
}
};
} // namespace boost
#endif
+28
View File
@@ -0,0 +1,28 @@
// Copyright (C) 2000, 2001 Stephen Cleary (shammah@voyager.net)
//
// This file can be redistributed and/or modified under the terms found
// in "copyright.html"
// This software and its documentation is provided "as is" without express or
// implied warranty, and with no claim as to its suitability for any purpose.
//
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_SINGLETON_POOL_FWD_HPP
#define BOOST_SINGLETON_POOL_FWD_HPP
// boost::details::pool::default_mutex
#include <boost/pool/detail/mutex.hpp>
// boost::default_user_allocator_new_delete fwd
#include <boost/pool/pool_fwd.hpp>
namespace boost {
template <typename Tag, unsigned RequestedSize,
typename UserAllocator = default_user_allocator_new_delete,
typename Mutex = details::pool::default_mutex,
unsigned NextSize = 32>
struct singleton_pool;
} // namespace boost
#endif
+101
View File
@@ -0,0 +1,101 @@
// Copyright (C) 2000 Stephen Cleary (shammah@voyager.net)
//
// This file can be redistributed and/or modified under the terms found
// in "copyright.html"
// This software and its documentation is provided "as is" without express or
// implied warranty, and with no claim as to its suitability for any purpose.
#ifndef BOOST_SYS_ALLOCATOR_H
#define BOOST_SYS_ALLOCATOR_H
// Symbols: malloc_allocator, new_delete_allocator
#include <cstddef>
#include <cstdlib>
#include <limits>
#include <new>
template <typename T>
struct malloc_allocator
{
typedef T * pointer;
typedef const T * const_pointer;
typedef T & reference;
typedef const T & const_reference;
typedef T value_type;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
template <typename U>
struct rebind
{
typedef malloc_allocator<U> other;
};
static pointer address(reference r) { return &r; }
static const_pointer address(const_reference r) { return &r; }
static pointer allocate(const size_type n, const pointer = 0)
{
const pointer ret = (pointer) std::malloc(n * sizeof(T));
if (ret == 0)
throw std::bad_alloc();
return ret;
}
static void deallocate(const pointer p, const size_type)
{ std::free(p); }
static size_type max_size() { return std::numeric_limits<size_type>::max(); }
bool operator==(const malloc_allocator &) const { return true; }
bool operator!=(const malloc_allocator &) const { return false; }
malloc_allocator() { }
template <typename U>
malloc_allocator(const malloc_allocator<U> &) { }
static void construct(const pointer p, const_reference t)
{ new ((void *) p) T(t); }
static void destroy(const pointer p)
{ p->~T(); }
};
template <typename T>
struct new_delete_allocator
{
typedef T * pointer;
typedef const T * const_pointer;
typedef T & reference;
typedef const T & const_reference;
typedef T value_type;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
template <typename U>
struct rebind
{
typedef new_delete_allocator<U> other;
};
static pointer address(reference r) { return &r; }
static const_pointer address(const_reference r) { return &r; }
static pointer allocate(const size_type n, const pointer = 0)
{ return (pointer) new char[n * sizeof(T)]; }
static void deallocate(const pointer p, const size_type)
{ delete [] p; }
static size_type max_size() { return std::numeric_limits<size_type>::max(); }
bool operator==(const new_delete_allocator &) const { return true; }
bool operator!=(const new_delete_allocator &) const { return false; }
new_delete_allocator() { }
template <typename U>
new_delete_allocator(const new_delete_allocator<U> &) { }
static void construct(const pointer p, const_reference t)
{ new ((void *) p) T(t); }
static void destroy(const pointer p)
{ p->~T(); }
};
#endif
+316
View File
@@ -0,0 +1,316 @@
// Copyright (C) 2000, 2001 Stephen Cleary (shammah@voyager.net)
//
// This file can be redistributed and/or modified under the terms found
// in "copyright.html"
// This software and its documentation is provided "as is" without express or
// implied warranty, and with no claim as to its suitability for any purpose.
// Uncomment this to stub out all MT locking
#define BOOST_NO_MT
#include <boost/pool/pool_alloc.hpp>
#include <boost/pool/object_pool.hpp>
#include <stdexcept>
#include <iostream>
#include <vector>
#include <algorithm>
#include <list>
#include <deque>
#include <set>
// VERBOSE will print out trace-like statements to show exactly what this
// test file is doing.
//#define VERBOSE
// Each "tester" object below checks into and out of the "cdtor_checker",
// which will report any problems related to the construction/destruction of
// "tester" objects.
class cdtor_checker
{
private:
// Each constructed object registers its "this" pointer into "objs"
std::set<void *> objs;
public:
~cdtor_checker()
{
// At end of program, print out memory leaks
// (assuming no static "tester"s)
for (std::set<void *>::const_iterator i = objs.begin();
i != objs.end(); ++i)
std::cout << "Memory leak: " << *i << std::endl;
}
void check_in(void * const This)
{
if (objs.find(This) != objs.end())
std::cout << "Double-constructed memory: " << This << std::endl;
objs.insert(This);
}
void check_out(void * const This)
{
std::set<void *>::iterator i = objs.find(This);
if (i == objs.end())
std::cout << "Destroyed non-constructed memory: " << This << std::endl;
objs.erase(This);
}
// true iff all objects that have checked in have checked out
bool ok() const { return objs.empty(); }
};
static cdtor_checker mem;
struct tester
{
tester(int arg1, int arg2)
{
if (arg1 == 17 && arg2 == 17)
{
#ifdef VERBOSE
std::cout << this << ": tester not constructed" << std::endl;
#endif
throw std::logic_error("No construction allowed!");
}
#ifdef VERBOSE
std::cout << this << ": tester::tester()" << std::endl;
#endif
mem.check_in(this);
}
tester(const tester & other)
{
#ifdef VERBOSE
std::cout << this << ": tester::tester(" << &other << ')' << std::endl;
#endif
mem.check_in(this);
}
~tester()
{
#ifdef VERBOSE
std::cout << this << ": tester::~tester()" << std::endl;
#endif
mem.check_out(this);
}
};
void test()
{
{
// should do nothing
boost::object_pool<tester> pool;
}
{
// Construct several tester objects. Don't delete them (i.e.,
// test pool's garbage collection).
#ifdef VERBOSE
std::cout << "Testing pool. . ." << std::endl;
#endif
boost::object_pool<tester> pool;
for (int i = 0; i < 10; ++i)
pool.construct(13, 13);
}
{
// Construct several tester objects. Delete some of them.
#ifdef VERBOSE
std::cout << "Testing pool with some removed. . ." << std::endl;
#endif
boost::object_pool<tester> pool;
std::vector<tester *> v;
for (int i = 0; i < 10; ++i)
v.push_back(pool.construct(13, 13));
std::random_shuffle(v.begin(), v.end());
for (int i = 0; i < 5; ++i)
pool.destroy(v[i]);
}
{
// Test how pool reacts with constructors that throw exceptions.
// Shouldn't have any memory leaks.
#ifdef VERBOSE
std::cout << "Testing with exceptional constructors :). . ." << std::endl;
#endif
boost::object_pool<tester> pool;
for (int i = 0; i < 5; ++i)
{
pool.construct(13, 13);
}
for (int i = 0; i < 5; ++i)
{
try
{
// The following constructor will raise an exception.
pool.construct(17, 17);
}
catch (const std::logic_error &) { }
}
}
}
void test_alloc()
{
#ifdef VERBOSE
std::cout << "Testing allocator. . ." << std::endl;
#endif
{
// Allocate several tester objects. Delete one.
#ifdef VERBOSE
std::cout << "with vector. . ." << std::endl;
#endif
std::vector<tester, boost::pool_allocator<tester> > l;
for (int i = 0; i < 10; ++i)
l.push_back(tester(13, 13));
l.pop_back();
}
{
// Allocate several tester objects. Delete two.
#ifdef VERBOSE
std::cout << "with deque. . ." << std::endl;
#endif
std::deque<tester, boost::pool_allocator<tester> > l;
for (int i = 0; i < 10; ++i)
l.push_back(tester(13, 13));
l.pop_back();
l.pop_front();
}
{
// Allocate several tester objects. Delete two.
#ifdef VERBOSE
std::cout << "with list. . ." << std::endl;
#endif
std::list<tester, boost::fast_pool_allocator<tester> > l;
// lists rebind their allocators, so dumping is useless
for (int i = 0; i < 10; ++i)
l.push_back(tester(13, 13));
l.pop_back();
l.pop_front();
}
tester * tmp;
{
// Create a memory leak on purpose. (Allocator doesn't have
// garbage collection)
#ifdef VERBOSE
std::cout << "Testing allocator cleanup. . ." << std::endl;
#endif
// (Note: memory leak)
boost::pool_allocator<tester> a;
tmp = a.allocate(1, 0);
new (tmp) tester(13, 13);
}
if (mem.ok())
std::cout << "Error: Pool allocator cleaned up!" << std::endl;
// Remove memory checker entry (to avoid error later) and
// clean up memory leak
tmp->~tester();
boost::pool_allocator<tester>::deallocate(tmp, 1);
}
// This is a wrapper around a UserAllocator. It just registers alloc/dealloc
// to/from the system memory. It's used to make sure pool's are allocating
// and deallocating system memory properly.
// Do NOT use this class with static or singleton pools.
template <typename UserAllocator>
struct TrackAlloc
{
typedef typename UserAllocator::size_type size_type;
typedef typename UserAllocator::difference_type difference_type;
static std::set<char *> allocated_blocks;
static char * malloc(const size_type bytes)
{
char * const ret = UserAllocator::malloc(bytes);
allocated_blocks.insert(ret);
return ret;
}
static void free(char * const block)
{
if (allocated_blocks.find(block) == allocated_blocks.end())
std::cout << "Free'd non-malloc'ed block: " << (void *) block << std::endl;
allocated_blocks.erase(block);
UserAllocator::free(block);
}
static bool ok() { return allocated_blocks.empty(); }
};
template <typename UserAllocator>
std::set<char *> TrackAlloc<UserAllocator>::allocated_blocks;
typedef TrackAlloc<boost::default_user_allocator_new_delete> track_alloc;
void test_mem_usage()
{
#ifdef VERBOSE
std::cout << "Testing memory usage. . ." << std::endl;
#endif
typedef boost::pool<track_alloc> pool_type;
{
// Constructor should do nothing; no memory allocation
pool_type pool(sizeof(int));
if (!track_alloc::ok())
std::cout << "Memory error" << std::endl;
if (pool.release_memory())
std::cout << "Pool released memory" << std::endl;
if (pool.purge_memory())
std::cout << "Pool purged memory" << std::endl;
// Should allocate from system
pool.free(pool.malloc());
if (track_alloc::ok())
std::cout << "Memory error" << std::endl;
// Ask pool to give up memory it's not using; this should succeed
if (!pool.release_memory())
std::cout << "Pool didn't release memory" << std::endl;
if (!track_alloc::ok())
std::cout << "Memory error" << std::endl;
// Should allocate from system again
pool.malloc(); // loses the pointer to the returned chunk (*A*)
// Ask pool to give up memory it's not using; this should fail
if (pool.release_memory())
std::cout << "Pool released memory" << std::endl;
// Force pool to give up memory it's not using; this should succeed
// This will clean up the memory leak from (*A*)
if (!pool.purge_memory())
std::cout << "Pool didn't purge memory" << std::endl;
if (!track_alloc::ok())
std::cout << "Memory error" << std::endl;
// Should allocate from system again
pool.malloc(); // loses the pointer to the returned chunk (*B*)
// pool's destructor should purge the memory
// This will clean up the memory leak from (*B*)
}
if (!track_alloc::ok())
std::cout << "Memory error" << std::endl;
}
int main(void)
{
test();
test_alloc();
test_mem_usage();
#ifdef VERBOSE
std::cout << "main() exiting. . ." << std::endl;
#endif
if (mem.ok() && track_alloc::ok())
std::cout << "All tests passed!" << std::endl;
else
std::cout << "Memory inconsistent!" << std::endl;
return 0;
}
+449
View File
@@ -0,0 +1,449 @@
// Copyright (C) 2000, 2001 Stephen Cleary (shammah@voyager.net)
//
// This file can be redistributed and/or modified under the terms found
// in "copyright.html"
// This software and its documentation is provided "as is" without express or
// implied warranty, and with no claim as to its suitability for any purpose.
#include <boost/pool/pool_alloc.hpp>
#include <boost/pool/object_pool.hpp>
#include <iostream>
#include <vector>
#include <list>
#include <set>
#include <ctime>
#include <cerrno>
#include "sys_allocator.hpp"
unsigned long num_ints;
template <unsigned N>
struct larger_structure
{
char data[N];
};
unsigned test_number;
template <unsigned N>
static void timing_test_alloc_larger()
{
typedef boost::fast_pool_allocator<larger_structure<N>,
boost::default_user_allocator_new_delete,
boost::details::pool::null_mutex> alloc;
typedef boost::fast_pool_allocator<larger_structure<N> > alloc_sync;
double end[1][6];
std::clock_t start;
start = std::clock();
{
std::allocator<larger_structure<N> > a;
for (unsigned long i = 0; i < num_ints; ++i)
a.deallocate(a.allocate(1), 1);
}
end[0][0] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
for (unsigned long i = 0; i < num_ints; ++i)
std::free(std::malloc(sizeof(larger_structure<N>)));
}
end[0][1] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
for (unsigned long i = 0; i < num_ints; ++i)
delete new (std::nothrow) larger_structure<N>;
}
end[0][2] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
for (unsigned long i = 0; i < num_ints; ++i)
alloc::deallocate(alloc::allocate());
}
end[0][3] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
for (unsigned long i = 0; i < num_ints; ++i)
alloc_sync::deallocate(alloc_sync::allocate());
}
end[0][4] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
boost::pool<> p(sizeof(larger_structure<N>));
for (unsigned long i = 0; i < num_ints; ++i)
{
void * const t = p.malloc();
if (t != 0)
p.free(t);
}
}
end[0][5] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
std::cout << "Test " << test_number++ << ": Alloc & Dealloc " << num_ints << " structures of size " << sizeof(larger_structure<N>) << ":" << std::endl;
std::cout << " std::allocator: " << end[0][0] << " seconds" << std::endl;
std::cout << " malloc/free: " << end[0][1] << " seconds" << std::endl;
std::cout << " new/delete: " << end[0][2] << " seconds" << std::endl;
std::cout << " Pool Alloc: " << end[0][3] << " seconds" << std::endl;
std::cout << " Pool /w Sync: " << end[0][4] << " seconds" << std::endl;
std::cout << " Pool: " << end[0][5] << " seconds" << std::endl;
}
static void timing_test_alloc()
{
typedef boost::fast_pool_allocator<int,
boost::default_user_allocator_new_delete,
boost::details::pool::null_mutex> alloc;
typedef boost::fast_pool_allocator<int> alloc_sync;
double end[2][6];
std::clock_t start;
int ** p = new int*[num_ints];
start = std::clock();
{
std::allocator<int> a;
for (unsigned long i = 0; i < num_ints; ++i)
a.deallocate(a.allocate(1), 1);
}
end[0][0] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
for (unsigned long i = 0; i < num_ints; ++i)
std::free(std::malloc(sizeof(int)));
}
end[0][1] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
for (unsigned long i = 0; i < num_ints; ++i)
delete new (std::nothrow) int;
}
end[0][2] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
for (unsigned long i = 0; i < num_ints; ++i)
alloc::deallocate(alloc::allocate());
}
end[0][3] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
for (unsigned long i = 0; i < num_ints; ++i)
alloc_sync::deallocate(alloc_sync::allocate());
}
end[0][4] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
boost::pool<> p(sizeof(int));
for (unsigned long i = 0; i < num_ints; ++i)
{
void * const t = p.malloc();
if (t != 0)
p.free(t);
}
}
end[0][5] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
std::allocator<int> a;
for (unsigned long i = 0; i < num_ints; ++i)
p[i] = a.allocate(1);
for (unsigned long i = 0; i < num_ints; ++i)
a.deallocate(p[i], 1);
}
end[1][0] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
for (unsigned long i = 0; i < num_ints; ++i)
p[i] = (int *) std::malloc(sizeof(int));
for (unsigned long i = 0; i < num_ints; ++i)
std::free(p[i]);
}
end[1][1] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
for (unsigned long i = 0; i < num_ints; ++i)
p[i] = new (std::nothrow) int;
for (unsigned long i = 0; i < num_ints; ++i)
delete p[i];
}
end[1][2] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
for (unsigned long i = 0; i < num_ints; ++i)
p[i] = alloc::allocate();
for (unsigned long i = 0; i < num_ints; ++i)
alloc::deallocate(p[i]);
}
end[1][3] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
for (unsigned long i = 0; i < num_ints; ++i)
p[i] = alloc_sync::allocate();
for (unsigned long i = 0; i < num_ints; ++i)
alloc_sync::deallocate(p[i]);
}
end[1][4] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
boost::pool<> pl(sizeof(int));
for (unsigned long i = 0; i < num_ints; ++i)
p[i] = reinterpret_cast<int *>(pl.malloc());
for (unsigned long i = 0; i < num_ints; ++i)
if (p[i] != 0)
pl.free(p[i]);
}
end[1][5] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
delete [] p;
std::cout << "Test 3: Alloc & Dealloc " << num_ints << " ints:" << std::endl;
std::cout << " std::allocator: " << end[0][0] << " seconds" << std::endl;
std::cout << " malloc/free: " << end[0][1] << " seconds" << std::endl;
std::cout << " new/delete: " << end[0][2] << " seconds" << std::endl;
std::cout << " Pool Alloc: " << end[0][3] << " seconds" << std::endl;
std::cout << " Pool /w Sync: " << end[0][4] << " seconds" << std::endl;
std::cout << " Pool: " << end[0][5] << " seconds" << std::endl;
std::cout << "Test 4: Alloc " << num_ints << " ints & Dealloc " << num_ints << " ints:" << std::endl;
std::cout << " std::allocator: " << end[1][0] << " seconds" << std::endl;
std::cout << " malloc/free: " << end[1][1] << " seconds" << std::endl;
std::cout << " new/delete: " << end[1][2] << " seconds" << std::endl;
std::cout << " Pool Alloc: " << end[1][3] << " seconds" << std::endl;
std::cout << " Pool /w Sync: " << end[1][4] << " seconds" << std::endl;
std::cout << " Pool: " << end[1][5] << " seconds" << std::endl;
}
static void timing_test_containers()
{
typedef boost::pool_allocator<int,
boost::default_user_allocator_new_delete,
boost::details::pool::null_mutex> alloc;
typedef boost::pool_allocator<int> alloc_sync;
typedef boost::fast_pool_allocator<int,
boost::default_user_allocator_new_delete,
boost::details::pool::null_mutex> fast_alloc;
typedef boost::fast_pool_allocator<int> fast_alloc_sync;
double end[3][5];
std::clock_t start;
start = std::clock();
{
std::vector<int, std::allocator<int> > x;
for (unsigned long i = 0; i < num_ints; ++i)
x.push_back(0);
}
end[0][0] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
std::vector<int, malloc_allocator<int> > x;
for (unsigned long i = 0; i < num_ints; ++i)
x.push_back(0);
}
end[0][1] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
std::vector<int, new_delete_allocator<int> > x;
for (unsigned long i = 0; i < num_ints; ++i)
x.push_back(0);
}
end[0][2] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
std::vector<int, alloc> x;
for (unsigned long i = 0; i < num_ints; ++i)
x.push_back(0);
}
end[0][3] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
std::vector<int, alloc_sync> x;
for (unsigned long i = 0; i < num_ints; ++i)
x.push_back(0);
}
end[0][4] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
std::set<int, std::less<int>, std::allocator<int> > x;
for (unsigned long i = 0; i < num_ints; ++i)
x.insert(0);
}
end[1][0] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
std::set<int, std::less<int>, malloc_allocator<int> > x;
for (unsigned long i = 0; i < num_ints; ++i)
x.insert(0);
}
end[1][1] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
std::set<int, std::less<int>, new_delete_allocator<int> > x;
for (unsigned long i = 0; i < num_ints; ++i)
x.insert(0);
}
end[1][2] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
std::set<int, std::less<int>, fast_alloc> x;
for (unsigned long i = 0; i < num_ints; ++i)
x.insert(0);
}
end[1][3] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
std::set<int, std::less<int>, fast_alloc_sync> x;
for (unsigned long i = 0; i < num_ints; ++i)
x.insert(0);
}
end[1][4] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
std::list<int, std::allocator<int> > x;
for (unsigned long i = 0; i < num_ints; ++i)
x.push_back(0);
}
end[2][0] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
std::list<int, malloc_allocator<int> > x;
for (unsigned long i = 0; i < num_ints; ++i)
x.push_back(0);
}
end[2][1] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
std::list<int, new_delete_allocator<int> > x;
for (unsigned long i = 0; i < num_ints; ++i)
x.push_back(0);
}
end[2][2] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
std::list<int, fast_alloc> x;
for (unsigned long i = 0; i < num_ints; ++i)
x.push_back(0);
}
end[2][3] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
start = std::clock();
{
std::list<int, fast_alloc_sync> x;
for (unsigned long i = 0; i < num_ints; ++i)
x.push_back(0);
}
end[2][4] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
std::cout << "Test 0: Insertion & deletion of " << num_ints << " ints in a vector:" << std::endl;
std::cout << " std::allocator: " << end[0][0] << " seconds" << std::endl;
std::cout << " malloc/free: " << end[0][1] << " seconds" << std::endl;
std::cout << " new/delete: " << end[0][2] << " seconds" << std::endl;
std::cout << " Pool Alloc: " << end[0][3] << " seconds" << std::endl;
std::cout << " Pool /w Sync: " << end[0][4] << " seconds" << std::endl;
std::cout << " Pool: not possible" << std::endl;
std::cout << "Test 1: Insertion & deletion of " << num_ints << " ints in a set:" << std::endl;
std::cout << " std::allocator: " << end[1][0] << " seconds" << std::endl;
std::cout << " malloc/free: " << end[1][1] << " seconds" << std::endl;
std::cout << " new/delete: " << end[1][2] << " seconds" << std::endl;
std::cout << " Pool Alloc: " << end[1][3] << " seconds" << std::endl;
std::cout << " Pool /w Sync: " << end[1][4] << " seconds" << std::endl;
std::cout << " Pool: not possible" << std::endl;
std::cout << "Test 2: Insertion & deletion of " << num_ints << " ints in a list:" << std::endl;
std::cout << " std::allocator: " << end[2][0] << " seconds" << std::endl;
std::cout << " malloc/free: " << end[2][1] << " seconds" << std::endl;
std::cout << " new/delete: " << end[2][2] << " seconds" << std::endl;
std::cout << " Pool Alloc: " << end[2][3] << " seconds" << std::endl;
std::cout << " Pool /w Sync: " << end[2][4] << " seconds" << std::endl;
std::cout << " Pool: not possible" << std::endl;
}
int main(int argc, char * argv[])
{
if (argc != 1 && argc != 2)
{
std::cerr << "Usage: " << argv[0]
<< " [number_of_ints_to_use_each_try]" << std::endl;
return 1;
}
errno = 0;
if (argc == 2)
{
num_ints = std::strtoul(argv[1], 0, 10);
if (errno != 0)
{
std::cerr << "Cannot convert number \"" << argv[1] << '"' << std::endl;
return 2;
}
}
else
num_ints = 700000;
try
{
timing_test_containers();
timing_test_alloc();
test_number = 5;
timing_test_alloc_larger<64>();
test_number = 6;
timing_test_alloc_larger<256>();
test_number = 7;
timing_test_alloc_larger<4096>();
}
catch (const std::bad_alloc &)
{
std::cerr << "Timing tests ran out of memory; try again with a lower value for number of ints"
<< " (current value is " << num_ints << ")" << std::endl;
return 3;
}
catch (const std::exception & e)
{
std::cerr << "Error: " << e.what() << std::endl;
return 4;
}
catch (...)
{
std::cerr << "Unknown error" << std::endl;
return 5;
}
return 0;
}