From 0a122496e1bf60c970a1fe30401eb83af29293b0 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Thu, 8 Mar 2001 20:44:22 +0000 Subject: [PATCH] Initial commit [SVN r9503] --- .gitattributes | 96 ++ TODO.txt | 5 + doc/concepts.html | 176 ++++ doc/copyright.html | 25 + doc/implementation/alignment.html | 383 ++++++++ doc/implementation/ct_gcd_lcm.html | 93 ++ doc/implementation/for.html | 75 ++ doc/implementation/gcd_lcm.html | 81 ++ doc/implementation/guard.html | 111 +++ doc/implementation/mutex.html | 129 +++ doc/implementation/object_pool.html | 70 ++ doc/implementation/pool.html | 216 +++++ doc/implementation/pool_alloc.html | 127 +++ doc/implementation/pool_construct.html | 62 ++ doc/implementation/postulate.html | 129 +++ .../simple_segregated_storage.html | 76 ++ doc/implementation/singleton.html | 94 ++ doc/implementation/singleton_pool.html | 82 ++ doc/index.html | 155 ++++ doc/interfaces.html | 137 +++ doc/interfaces/object_pool.html | 128 +++ doc/interfaces/pool.html | 143 +++ doc/interfaces/pool_alloc.html | 202 +++++ doc/interfaces/simple_segregated_storage.html | 150 +++ doc/interfaces/singleton_pool.html | 157 ++++ doc/interfaces/user_allocator.html | 91 ++ doc/pool.css | 11 + include/boost/pool/detail/ct_gcd_lcm.hpp | 68 ++ include/boost/pool/detail/for.m4 | 109 +++ include/boost/pool/detail/gcd_lcm.hpp | 59 ++ include/boost/pool/detail/guard.hpp | 41 + include/boost/pool/detail/mutex.hpp | 134 +++ include/boost/pool/detail/pool_construct.bat | 29 + include/boost/pool/detail/pool_construct.inc | 858 ++++++++++++++++++ include/boost/pool/detail/pool_construct.m4 | 88 ++ include/boost/pool/detail/pool_construct.sh | 13 + include/boost/pool/detail/postulate.hpp | 52 ++ include/boost/pool/detail/select_type.hpp | 35 + include/boost/pool/detail/singleton.hpp | 98 ++ include/boost/pool/object_pool.hpp | 124 +++ include/boost/pool/object_pool_fwd.hpp | 23 + include/boost/pool/pool.hpp | 549 +++++++++++ include/boost/pool/pool_alloc.hpp | 220 +++++ include/boost/pool/pool_alloc_fwd.hpp | 38 + include/boost/pool/pool_fwd.hpp | 23 + .../boost/pool/simple_segregated_storage.hpp | 270 ++++++ .../pool/simple_segregated_storage_fwd.hpp | 23 + include/boost/pool/singleton_pool.hpp | 120 +++ include/boost/pool/singleton_pool_fwd.hpp | 28 + test/sys_allocator.hpp | 101 +++ test/test_pool_alloc.cpp | 316 +++++++ test/time_pool_alloc.cpp | 449 +++++++++ 52 files changed, 7072 insertions(+) create mode 100644 .gitattributes create mode 100644 TODO.txt create mode 100644 doc/concepts.html create mode 100644 doc/copyright.html create mode 100644 doc/implementation/alignment.html create mode 100644 doc/implementation/ct_gcd_lcm.html create mode 100644 doc/implementation/for.html create mode 100644 doc/implementation/gcd_lcm.html create mode 100644 doc/implementation/guard.html create mode 100644 doc/implementation/mutex.html create mode 100644 doc/implementation/object_pool.html create mode 100644 doc/implementation/pool.html create mode 100644 doc/implementation/pool_alloc.html create mode 100644 doc/implementation/pool_construct.html create mode 100644 doc/implementation/postulate.html create mode 100644 doc/implementation/simple_segregated_storage.html create mode 100644 doc/implementation/singleton.html create mode 100644 doc/implementation/singleton_pool.html create mode 100644 doc/index.html create mode 100644 doc/interfaces.html create mode 100644 doc/interfaces/object_pool.html create mode 100644 doc/interfaces/pool.html create mode 100644 doc/interfaces/pool_alloc.html create mode 100644 doc/interfaces/simple_segregated_storage.html create mode 100644 doc/interfaces/singleton_pool.html create mode 100644 doc/interfaces/user_allocator.html create mode 100644 doc/pool.css create mode 100644 include/boost/pool/detail/ct_gcd_lcm.hpp create mode 100644 include/boost/pool/detail/for.m4 create mode 100644 include/boost/pool/detail/gcd_lcm.hpp create mode 100644 include/boost/pool/detail/guard.hpp create mode 100644 include/boost/pool/detail/mutex.hpp create mode 100755 include/boost/pool/detail/pool_construct.bat create mode 100644 include/boost/pool/detail/pool_construct.inc create mode 100644 include/boost/pool/detail/pool_construct.m4 create mode 100644 include/boost/pool/detail/pool_construct.sh create mode 100644 include/boost/pool/detail/postulate.hpp create mode 100644 include/boost/pool/detail/select_type.hpp create mode 100644 include/boost/pool/detail/singleton.hpp create mode 100644 include/boost/pool/object_pool.hpp create mode 100644 include/boost/pool/object_pool_fwd.hpp create mode 100644 include/boost/pool/pool.hpp create mode 100644 include/boost/pool/pool_alloc.hpp create mode 100644 include/boost/pool/pool_alloc_fwd.hpp create mode 100644 include/boost/pool/pool_fwd.hpp create mode 100644 include/boost/pool/simple_segregated_storage.hpp create mode 100644 include/boost/pool/simple_segregated_storage_fwd.hpp create mode 100644 include/boost/pool/singleton_pool.hpp create mode 100644 include/boost/pool/singleton_pool_fwd.hpp create mode 100644 test/sys_allocator.hpp create mode 100644 test/test_pool_alloc.cpp create mode 100644 test/time_pool_alloc.cpp diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3e84d7c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,96 @@ +* text=auto !eol svneol=native#text/plain +*.gitattributes text svneol=native#text/plain + +# Scriptish formats +*.bat text svneol=native#text/plain +*.bsh text svneol=native#text/x-beanshell +*.cgi text svneol=native#text/plain +*.cmd text svneol=native#text/plain +*.js text svneol=native#text/javascript +*.php text svneol=native#text/x-php +*.pl text svneol=native#text/x-perl +*.pm text svneol=native#text/x-perl +*.py text svneol=native#text/x-python +*.sh eol=lf svneol=LF#text/x-sh +configure eol=lf svneol=LF#text/x-sh + +# Image formats +*.bmp binary svneol=unset#image/bmp +*.gif binary svneol=unset#image/gif +*.ico binary svneol=unset#image/ico +*.jpeg binary svneol=unset#image/jpeg +*.jpg binary svneol=unset#image/jpeg +*.png binary svneol=unset#image/png +*.tif binary svneol=unset#image/tiff +*.tiff binary svneol=unset#image/tiff +*.svg text svneol=native#image/svg%2Bxml + +# Data formats +*.pdf binary svneol=unset#application/pdf +*.avi binary svneol=unset#video/avi +*.doc binary svneol=unset#application/msword +*.dsp text svneol=crlf#text/plain +*.dsw text svneol=crlf#text/plain +*.eps binary svneol=unset#application/postscript +*.gz binary svneol=unset#application/gzip +*.mov binary svneol=unset#video/quicktime +*.mp3 binary svneol=unset#audio/mpeg +*.ppt binary svneol=unset#application/vnd.ms-powerpoint +*.ps binary svneol=unset#application/postscript +*.psd binary svneol=unset#application/photoshop +*.rdf binary svneol=unset#text/rdf +*.rss text svneol=unset#text/xml +*.rtf binary svneol=unset#text/rtf +*.sln text svneol=native#text/plain +*.swf binary svneol=unset#application/x-shockwave-flash +*.tgz binary svneol=unset#application/gzip +*.vcproj text svneol=native#text/xml +*.vcxproj text svneol=native#text/xml +*.vsprops text svneol=native#text/xml +*.wav binary svneol=unset#audio/wav +*.xls binary svneol=unset#application/vnd.ms-excel +*.zip binary svneol=unset#application/zip + +# Text formats +.htaccess text svneol=native#text/plain +*.bbk text svneol=native#text/xml +*.cmake text svneol=native#text/plain +*.css text svneol=native#text/css +*.dtd text svneol=native#text/xml +*.htm text svneol=native#text/html +*.html text svneol=native#text/html +*.ini text svneol=native#text/plain +*.log text svneol=native#text/plain +*.mak text svneol=native#text/plain +*.qbk text svneol=native#text/plain +*.rst text svneol=native#text/plain +*.sql text svneol=native#text/x-sql +*.txt text svneol=native#text/plain +*.xhtml text svneol=native#text/xhtml%2Bxml +*.xml text svneol=native#text/xml +*.xsd text svneol=native#text/xml +*.xsl text svneol=native#text/xml +*.xslt text svneol=native#text/xml +*.xul text svneol=native#text/xul +*.yml text svneol=native#text/plain +boost-no-inspect text svneol=native#text/plain +CHANGES text svneol=native#text/plain +COPYING text svneol=native#text/plain +INSTALL text svneol=native#text/plain +Jamfile text svneol=native#text/plain +Jamroot text svneol=native#text/plain +Jamfile.v2 text svneol=native#text/plain +Jamrules text svneol=native#text/plain +Makefile* text svneol=native#text/plain +README text svneol=native#text/plain +TODO text svneol=native#text/plain + +# Code formats +*.c text svneol=native#text/plain +*.cpp text svneol=native#text/plain +*.h text svneol=native#text/plain +*.hpp text svneol=native#text/plain +*.ipp text svneol=native#text/plain +*.tpp text svneol=native#text/plain +*.jam text svneol=native#text/plain +*.java text svneol=native#text/plain diff --git a/TODO.txt b/TODO.txt new file mode 100644 index 0000000..37c4a9b --- /dev/null +++ b/TODO.txt @@ -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. diff --git a/doc/concepts.html b/doc/concepts.html new file mode 100644 index 0000000..dbe98de --- /dev/null +++ b/doc/concepts.html @@ -0,0 +1,176 @@ + + + +Pool Concepts + + + + +C++ Boost + +

Pool Concepts

+ +

+

+"Dynamic memory allocation has been a fundamental part of most computer systems since roughly 1960..."1 +
+ +

+Everyone uses dynamic memory allocation. If you have ever called malloc or new, then you have used dynamic memory allocation. Most programmers have a tendency to treat the heap as a "magic bag": we ask it for memory, and it magically creates some for us. Sometimes we run into problems because the heap is not magic. + +

+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, "virtual" 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 "nice" 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. + +

+The heap is complicated. It has to satisfy any type of memory request, for any size, and do it fast. 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 "perfect" 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 malloc'ed out to a program, the memory manager must "save" some information in it — usually just its size. Then, when the block is free'd, the memory manager can easily tell how large it is. + + + + + + + +
Memory block, not allocated
Memory not belonging to process
Memory used internally by memory allocator algorithm (usually 8-12 bytes)
Unused memory
Memory not belonging to process
+ + + + + + + +
Memory block, allocated (used by program)
Memory not belonging to process
Memory used internally by memory allocator algorithm (usually 4 bytes)
Memory usable by program
Memory not belonging to process
+ +

+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 "header fields" 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 ints 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 et. al. state that an average-case memory overhead is about ten to twenty percent2. 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. + +

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

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

+


+ +

+

Simple Segregated Storage

+ +

+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 partitioning a memory block into fixed-size chunks. Where the block comes from is not important until implementation time. A Pool is some object that uses Simple Segregated Storage in this fashion. To illustrate: + + + + + + + + + +
Memory block, split into chunks
Memory not belonging to process
Chunk 0
Chunk 1
Chunk 2
Chunk 3
Memory not belonging to process
+ +

+Each of the chunks in any given block are always 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). + +

+Simple Segregated Storage works by interleaving a free list within the unused chunks. For example: + + + + + + + + + +
Memory block, with no chunks allocated
Memory not belonging to process
Chunk 0; points to Chunk 1
Chunk 1; points to Chunk 2
Chunk 2; points to Chunk 3
Chunk 3; end-of-list
Memory not belonging to process
+ + + + + + + + + +
Memory block, with two chunks allocated
Memory not belonging to process
Chunk 0; points to Chunk 2
Chunk 1 (in use by process)
Chunk 2; end-of-list
Chunk 3 (in use by process)
Memory not belonging to process
+ +

+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 no memory overhead for chunks that are in use by the process. + +

+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). + +

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

+


+ +

+

References

+ +

+

    +
  1. Doug Lea, A Memory Allocator. Available on the web at http://gee.cs.oswego.edu/dl/html/malloc.html
  2. +
  3. Paul R. Wilson, Mark S. Johnstone, Michael Neely, and David Boles, "Dynamic Storage Allocation: A Survey and Critical Review" in International Workshop on Memory Management, September 1995, pg. 28, 36. Available on the web at ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps
  4. +
+ +

+

Other Implementations

+ +

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

+

+ +

+


+ +

+Copyright © 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. + + + \ No newline at end of file diff --git a/doc/copyright.html b/doc/copyright.html new file mode 100644 index 0000000..a637c25 --- /dev/null +++ b/doc/copyright.html @@ -0,0 +1,25 @@ + + + +Pool Copyright + + + +C++ Boost + +

Pool Copyright

+ +

+Copyright © 2000 Stephen Cleary (shammah@voyager.net) + +

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

+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 AND that copyright notice appears in supporting documentation, AND a notice that the software was modified appears with the copyright notice. + +

+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. + + + \ No newline at end of file diff --git a/doc/implementation/alignment.html b/doc/implementation/alignment.html new file mode 100644 index 0000000..48b45f9 --- /dev/null +++ b/doc/implementation/alignment.html @@ -0,0 +1,383 @@ + + + +Guaranteeing Alignment + + + + +C++ Boost + +

Guaranteeing Alignment

+ +

+

Terminology

+ +

+Review the concepts document if you are not already familiar with it. Remember that block is a contiguous section of memory, which is partitioned or segregated into fixed-size chunks. These chunks are what are allocated and deallocated by the user. + +

+

Overview

+ +

+Each Pool has a single free list that can extend over a number of memory blocks. Thus, Pool also has a linked list of allocated memory blocks. Each memory block, by default, is allocated using new[], and all memory blocks are freed on destruction. It is the use of new[] that allows us to guarantee alignment. + +

+

Proof of Concept: Guaranteeing Alignment

+ +

+Each block of memory is allocated as a POD type (specifically, an array of characters) through operator new[]. Let POD_size be the number of characters allocated. + +

+

Predicate 1: Arrays may not have padding

+ +

+This follows from the following quote: + +

+[5.3.3/2] (Expressions::Unary expressions::Sizeof) "... 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 n elements is n times the size of an element." + +

+Therefore, arrays cannot contain padding, though the elements within the arrays may contain padding. + +

+

Predicate 2: Any block of memory allocated as an array of characters through operator new[] (hereafter referred to as the block) is properly aligned for any object of that size or smaller

+ +

+This follows from: + +

+ +

+

Consider: imaginary object type Element of a size which is a multiple of some actual object size; assume sizeof(Element) > POD_size

+ +

+Note that an object of that size can exist. One object of that size is an array of the "actual" objects. + +

+Note that the block is properly aligned for an Element. This directly follows from Predicate 2. + +

+

Corollary 1: The block is properly aligned for an array of Elements

+ +

+This follows from Predicates 1 and 2, and the following quote: + +

+[3.9/9] (Basic concepts::Types) "An object type is a (possibly cv-qualified) type that is not a function type, not a reference type, and not a void type." (Specifically, array types are object types.) + +

+

Corollary 2: For any pointer p and integer i, 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

+ +

+There are no quotes from the Standard to directly support this argument, but it fits the common conception of the meaning of "alignment". + +

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

+

Let: sizeof(Element) be the least common multiple of sizes of several actual objects (T1, T2, T3, ...)

+ +

+

Let: block be a pointer to the memory block, pe be (Element *) block, and pn be (Tn *) block

+ +

+

Corollary 3: For each integer i, such that pe + i is well-defined, then for each n, there exists some integer jn such that pn + jn is well-defined and refers to the same memory address as pe + i

+ +

+This follows naturally, since the memory block is an array of Elements, and for each n, sizeof(Element) % sizeof(Tn) == 0; thus, the boundary of each element in the array of Elements is also a boundary of each element in each array of Tn. + +

+

Theorem: For each integer i, such that pe + i is well-defined, that address (pe + i) is properly aligned for each type Tn

+ +

+Since pe + i is well-defined, then by Corollary 3, pn + jn is well-defined. It is properly aligned from Predicate 2 and Corollaries 1 and 2. + +

+

Use of the Theorem

+ +

+The proof above covers alignment requirements for cutting chunks out of a block. The implementation uses actual object sizes of: + +

+ +

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

+Therefore, alloc_size is defined to be the lcm of the sizes of the three types above. + +

+

A Look at the Memory Block

+ +

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

+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). + +

+Here's an example memory block, where requested_size == sizeof(void *) == sizeof(size_type) == 4: + + + + +
Memory block containing 4 chunks, showing overlying array structures; FLP = Interleaved Free List Pointer
Sectionssize_type alignmentvoid * alignmentrequested_size alignment + +
Memory not belonging to process + +
Chunks section (16 bytes) + (4 bytes) + FLP for Chunk 1 (4 bytes) + Chunk 1 (4 bytes) +
(4 bytes) + FLP for Chunk 2 (4 bytes) + Chunk 2 (4 bytes) +
(4 bytes) + FLP for Chunk 3 (4 bytes) + Chunk 3 (4 bytes) +
(4 bytes) + FLP for Chunk 4 (4 bytes) + Chunk 4 (4 bytes) + +
Pointer to next Block (4 bytes) + (4 bytes) + Pointer to next Block (4 bytes) + +
Size of next Block (4 bytes) + Size of next Block (4 bytes) + +
Memory not belonging to process +
+ +

+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: + + + + +
Memory block containing 4 chunks, showing overlying array structures; FLP = Interleaved Free List Pointer
Sectionssize_type alignmentvoid * alignmentrequested_size alignment + +
Memory not belonging to process + +
Chunks section (32 bytes) + (4 bytes) + FLP for Chunk 1 (4 bytes) + Chunk 1 (8 bytes) +
(4 bytes) + (4 bytes) +
(4 bytes) + FLP for Chunk 2 (4 bytes) + Chunk 2 (8 bytes) +
(4 bytes) + (4 bytes) +
(4 bytes) + FLP for Chunk 3 (4 bytes) + Chunk 3 (8 bytes) +
(4 bytes) + (4 bytes) +
(4 bytes) + FLP for Chunk 4 (4 bytes) + Chunk 4 (8 bytes) +
(4 bytes) + (4 bytes) + +
Pointer to next Block (4 bytes) + (4 bytes) + Pointer to next Block (4 bytes) + +
Size of next Block (4 bytes) + Size of next Block (4 bytes) + +
Memory not belonging to process +
+ +

+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: + + + + +
Memory block containing 2 chunks, showing overlying array structures
Sectionssize_type alignmentvoid * alignmentrequested_size alignment + +
Memory not belonging to process + + + +
Chunks section (210 bytes) + (5 bytes) + Interleaved free list pointer for Chunk 1 (15 bytes; 3 used) + Chunk 1 (105 bytes; 7 used) +
(5 bytes) +
(5 bytes) +
(5 bytes) + (15 bytes) +
(5 bytes) +
(5 bytes) +
(5 bytes) + (15 bytes) +
(5 bytes) +
(5 bytes) +
(5 bytes) + (15 bytes) +
(5 bytes) +
(5 bytes) +
(5 bytes) + (15 bytes) +
(5 bytes) +
(5 bytes) +
(5 bytes) + (15 bytes) +
(5 bytes) +
(5 bytes) +
(5 bytes) + (15 bytes) +
(5 bytes) +
(5 bytes) +
(5 bytes) + Interleaved free list pointer for Chunk 2 (15 bytes; 3 used) + Chunk 2 (105 bytes; 7 used) +
(5 bytes) +
(5 bytes) +
(5 bytes) + (15 bytes) +
(5 bytes) +
(5 bytes) +
(5 bytes) + (15 bytes) +
(5 bytes) +
(5 bytes) +
(5 bytes) + (15 bytes) +
(5 bytes) +
(5 bytes) +
(5 bytes) + (15 bytes) +
(5 bytes) +
(5 bytes) +
(5 bytes) + (15 bytes) +
(5 bytes) +
(5 bytes) +
(5 bytes) + (15 bytes) +
(5 bytes) +
(5 bytes) + + + +
Pointer to next Block (15 bytes; 3 used) + (5 bytes) + Pointer to next Block (15 bytes; 3 used) +
(5 bytes) +
(5 bytes) + + + +
Size of next Block (5 bytes; 5 used) + Size of next Block (5 bytes; 5 used) + +
Memory not belonging to process +
+ +

+

How Contiguous Chunks are Handled

+ +

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

+Using array arguments similar to the above, we can translate any request for contiguous memory for n objects of requested_size into a request for m contiguous chunks. m is simply ceil(n * requested_size / alloc_size), where alloc_size is the actual size of the chunks. To illustrate: + +

+Here's an example memory block, where requested_size == 1 and sizeof(void *) == sizeof(size_type) == 4: + + + + +
Memory block containing 4 chunks; requested_size is 1
Sectionssize_type alignmentvoid * alignmentrequested_size alignment + +
Memory not belonging to process + +
Chunks section (16 bytes) + (4 bytes) + FLP to Chunk 2 (4 bytes) + Chunk 1 (4 bytes) +
(4 bytes) + FLP to Chunk 3 (4 bytes) + Chunk 2 (4 bytes) +
(4 bytes) + FLP to Chunk 4 (4 bytes) + Chunk 3 (4 bytes) +
(4 bytes) + FLP to end-of-list (4 bytes) + Chunk 4 (4 bytes) + +
Pointer to next Block (4 bytes) + (4 bytes) + Ptr to end-of-list (4 bytes) + +
Size of next Block (4 bytes) + 0 (4 bytes) + +
Memory not belonging to process +
+ + + + +
After user requests 7 contiguous elements of requested_size
Sectionssize_type alignmentvoid * alignmentrequested_size alignment + +
Memory not belonging to process + +
Chunks section (16 bytes) + (4 bytes) + (4 bytes) + 4 bytes in use by program +
(4 bytes) + (4 bytes) + 3 bytes in use by program (1 byte unused) +
(4 bytes) + FLP to Chunk 4 (4 bytes) + Chunk 3 (4 bytes) +
(4 bytes) + FLP to end-of-list (4 bytes) + Chunk 4 (4 bytes) + +
Pointer to next Block (4 bytes) + (4 bytes) + Ptr to end-of-list (4 bytes) + +
Size of next Block (4 bytes) + 0 (4 bytes) + +
Memory not belonging to process +
+ +

+Then, when the user deallocates the contiguous memory, we can split it up into chunks again. + +

+Note that the implementation provided for allocating contiguous chunks uses a linear instead of quadratic algorithm. This means that it may not find 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). + +

+


+ +

+Copyright © 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. + + + \ No newline at end of file diff --git a/doc/implementation/ct_gcd_lcm.html b/doc/implementation/ct_gcd_lcm.html new file mode 100644 index 0000000..47f29fd --- /dev/null +++ b/doc/implementation/ct_gcd_lcm.html @@ -0,0 +1,93 @@ + + + +ct_gcd_lcm - Compile-Time GCD and LCM + + + + +C++ Boost + +

ct_gcd_lcm - Compile-Time GCD and LCM

+ +

+

Introduction

+ +

+detail/ct_gcd_lcm.hpp provides two compile-time algorithms: greatest common divisor and least common multiple. + +

+

Synopsis

+
namespace details {
+namespace pool {
+
+template <unsigned A, unsigned B>
+struct ct_gcd
+{
+  static const unsigned value = ...;
+};
+template <unsigned A, unsigned B>
+struct ct_lcm
+{
+  static const unsigned value = ...;
+};
+
+} // namespace pool
+} // namespace details
+ +

+

Semantics

+ + + + + +
Symbol Table
SymbolMeaning
A, Bcompile-time unsigned integer constants[5.19/1]
+ + + +
Semantics
ExpressionResult TypeValuePrecondition +
ct_gcd<A, B>::valuecompile-time unsigned integer constantThe greatest common divisor of A and BA != 0 && B != 0 +
ct_lcm<A, B>::valuecompile-time unsigned integer constantThe least common multiple of A and BA != 0 && B != 0 +
+ +

+

Notes

+ +

+Since these are compile-time algorithms, violation of the preconditions will result in a compile-time error. + +

+

Dependencies

+ + + +

+

Selected Quotations from the Standard

+ +

+ +5.19/1: Expressions: Constant Expressions: ". . . An integral constant expression can involve only literals (2.13), enumerators, const 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 sizeof 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 sizeof expressions, functions, class objects, pointers, or references shall not be used, and assignment, increment, decrement, function-call, or comma operators shall not be used." + +

+

Future Directions

+ +

+This header may be replaced by a Boost compile-time algorithms library. + +

+


+ +

+Copyright © 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. + + + \ No newline at end of file diff --git a/doc/implementation/for.html b/doc/implementation/for.html new file mode 100644 index 0000000..00bd862 --- /dev/null +++ b/doc/implementation/for.html @@ -0,0 +1,75 @@ + + + +for - m4 FOR Macro + + + + +C++ Boost + +

for - m4 FOR Macro

+ +

+

Introduction

+ +

+detail/for.m4 provides BOOST_M4_FOR, an m4 macro that provides the equivalent of a #for preprocessor instruction. + +

+

Usage

+ +

+This macro must be used by an m4 file. This file assumes that the option -P is used, to force an m4_ prefix on all builtin symbols. + +

+

Arguments

+ +
    +
  1. The name of a variable to hold the current value.
  2. +
  3. The starting value of the variable.
  4. +
  5. The ending value of the variable.
  6. +
  7. The text to repeat. This text may contain references to the variable, which will be replaced with the variable's current value.
  8. +
  9. The delimeter text (optional).
  10. +
+ +

+If called with the wrong number of arguments (less than 4 or more than 5), BOOST_M4_FOR will exit with an error. If the starting value ($2) is greater than or equal to the ending value ($3), BOOST_M4_FOR will do nothing. Otherwise, it will repeat the text ($4), binding the variable ($1) to the values in the range [starting value ($2), ending value ($3)), and repeat the delimeter text ($5) in-between each occurrence of the repeat text ($4). + +

+

Examples

+ +

+Note of the quotation marks (") 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. + +

+ + + + + + + + + + + + + + +
InputOutput
"BOOST_M4_FOR(i, 1, 3)"Boost m4 script: BOOST_M4_FOR: Wrong number of arguments (3)
"BOOST_M4_FOR(i, 1, 3, i, ` ', 13)"Boost m4 script: BOOST_M4_FOR: Wrong number of arguments (6)
"BOOST_M4_FOR(i, 7, 0, i )"(nothing)
"BOOST_M4_FOR(i, 0, 0, i )"(nothing)
"BOOST_M4_FOR(i, 0, 7, i )""0 1 2 3 4 5 6 "
"BOOST_M4_FOR(i, -13, -10, i )""-13 -12 -11 "
"BOOST_M4_FOR(i, 0, 8, BOOST_M4_FOR(j, 0, 4, (i, j) )"
")"
"(0, 0) (0, 1) (0, 2) (0, 3) "
"(1, 0) (1, 1) (1, 2) (1, 3) "
"(2, 0) (2, 1) (2, 2) (2, 3) "
"(3, 0) (3, 1) (3, 2) (3, 3) "
"(4, 0) (4, 1) (4, 2) (4, 3) "
"(5, 0) (5, 1) (5, 2) (5, 3) "
"(6, 0) (6, 1) (6, 2) (6, 3) "
"(7, 0) (7, 1) (7, 2) (7, 3) "
""
"BOOST_M4_FOR(i, 7, 0, i, |)"(nothing)
"BOOST_M4_FOR(i, 0, 0, i, |)"(nothing)
"BOOST_M4_FOR(i, 0, 7, i, |)""0|1|2|3|4|5|6"
"BOOST_M4_FOR(i, -13, -10, i, `, ')""-13, -12, -11"
"BOOST_M4_FOR(i, 0, 8, `[BOOST_M4_FOR(j, 0, 4, (i, j), `, ')]', `,"
"')"
"[(0, 0), (0, 1), (0, 2), (0, 3)],"
"[(1, 0), (1, 1), (1, 2), (1, 3)],"
"[(2, 0), (2, 1), (2, 2), (2, 3)],"
"[(3, 0), (3, 1), (3, 2), (3, 3)],"
"[(4, 0), (4, 1), (4, 2), (4, 3)],"
"[(5, 0), (5, 1), (5, 2), (5, 3)],"
"[(6, 0), (6, 1), (6, 2), (6, 3)],"
"[(7, 0), (7, 1), (7, 2), (7, 3)]"
+ +

+


+ +

+Copyright © 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. + + + \ No newline at end of file diff --git a/doc/implementation/gcd_lcm.html b/doc/implementation/gcd_lcm.html new file mode 100644 index 0000000..f7dd5aa --- /dev/null +++ b/doc/implementation/gcd_lcm.html @@ -0,0 +1,81 @@ + + + +gcd_lcm - GCD and LCM + + + + +C++ Boost + +

gcd_lcm - GCD and LCM

+ +

+

Introduction

+ +

+detail/gcd_lcm.hpp provides two generic integer algorithms: greatest common divisor and least common multiple. + +

+

Synopsis

+
namespace details {
+namespace pool {
+
+template <typename Integer>
+Integer gcd(Integer A, Integer B);
+
+template <typename Integer>
+Integer lcm(Integer A, Integer B);
+
+} // namespace pool
+} // namespace details
+ +

+

Semantics

+ + + + + + +
Symbol Table
SymbolMeaning
IntegerAn integral type
A, BValues of type Integer
+ + + +
Semantics
ExpressionResult TypePreconditionNotes +
gcd(A, B)IntegerA > 0 && B > 0Returns the greatest common divisor of A and B +
lcm(A, B)IntegerA > 0 && B > 0Returns the least common multiple of A and B +
+ +

+

Implementation Notes

+ +

+For faster results, ensure A > B + +

+

Dependencies

+ +

+None. + +

+

Future Directions

+ +

+This header may be replaced by a Boost algorithms library. + +

+


+ +

+Copyright © 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. + + + \ No newline at end of file diff --git a/doc/implementation/guard.html b/doc/implementation/guard.html new file mode 100644 index 0000000..5ba78af --- /dev/null +++ b/doc/implementation/guard.html @@ -0,0 +1,111 @@ + + + +guard - Auto-lock/unlock-er + + + + +C++ Boost + +

guard - Auto-lock/unlock-er

+ +

+

Introduction

+ +

+detail/guard.hpp provides a type guard<Mutex> that allows scoped access to the Mutex's locking and unlocking operations. It is used to ensure that a Mutex is unlocked, even if an exception is thrown. + +

+

Synopsis

+ +
namespace details {
+namespace pool {
+
+template <typename Mutex>
+class guard
+{
+  private:
+    guard(const guard &);
+    void operator=(const guard &);
+
+  public:
+    explicit guard(Mutex & mtx);
+    ~guard();
+};
+
+} // namespace pool
+} // namespace details
+ +

+

Semantics

+ +

+ + +
Symbol Table
SymbolMeaning +
Tguard<Mutex> +
mvalue of type Mutex & +
gvalue of type guard<Mutex> +
+ +

+ + +
Requirements on Mutex
ExpressionReturn TypeAssertion/Note/Pre/Post-Condition +
m.lock()not usedLocks the mutex referred to by m +
m.unlock()not usedUnlocks the mutex referred to by m +
+ +

+ + +
Requirements satisfied by guard
ExpressionAssertion/Note/Pre/Post-Condition +
T(m)Locks the mutex referred to by m; binds T(m) to m +
(&g)->~T()Unlocks the mutex that g is bound to +
+ +

+

Example

+ +

+Given a (platform-specific) mutex class, we can wrap code as follows: +

extern mutex global_lock;
+
+static void f()
+{
+  boost::details::pool::guard<mutex> g(global_lock);
+  // g's constructor locks "global_lock"
+
+  ... // do anything:
+      //   throw exceptions
+      //   return
+      //   or just fall through
+} // g's destructor unlocks "global_lock"
+ +

+

Dependencies

+ +

+None. + +

+

Future Directions

+ +

+This header will eventually be replaced by a Boost multithreading library. + +

+


+ +

+Copyright © 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. + + + \ No newline at end of file diff --git a/doc/implementation/mutex.html b/doc/implementation/mutex.html new file mode 100644 index 0000000..f117242 --- /dev/null +++ b/doc/implementation/mutex.html @@ -0,0 +1,129 @@ + + + +mutex - Mutex + + + + +C++ Boost + +

mutex - Mutex

+ +

+

Introduction

+ +

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

+

Configuration

+ +

+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, #define BOOST_NO_MT before any inclusion of this header. To prevent ODR violations, this should be defined in every translation unit in your project, including any library files. + +

+

Synopsis

+ +
namespace details {
+namespace pool {
+
+// Only present if on a Win32 system
+class Win32_mutex
+{
+  private:
+    Win32_mutex(const Win32_mutex &);
+    void operator=(const Win32_mutex &);
+
+  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 &);
+    void operator=(const pthread_mutex &);
+
+  public:
+    pthread_mutex();
+    ~pthread_mutex();
+
+    void lock();
+    void unlock();
+};
+
+// Present on all systems
+class null_mutex
+{
+  private:
+    null_mutex(const null_mutex &);
+    void operator=(const null_mutex &);
+
+  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
+ +

+

Semantics

+ +

+ + +
Symbol Table
SymbolMeaning +
MutexAny type defined in this header +
tvalue of type Mutex +
+ +

+ + +
Requirements satisfied by mutex
ExpressionReturn TypeAssertion/Note/Pre/Post-Condition +
m.lock()not usedLocks the mutex +
m.unlock()not usedUnlocks the mutex +
+ +

+Each mutex is always either owned or unowned. If owned, then it is owned by a particular thread. To "lock" a mutex means to wait until the mutex is unowned, and then make it owned by the current thread. To "unlock" a mutex means to release ownership from the current thread (note that the current thread must own the mutex to release that ownership!). As a special case, the null_mutex never waits. + +

+

Dependencies

+ +

+May include the system headers <windows.h>, <unistd.h>, and/or <pthread.h>. + +

+

Future Directions

+ +

+This header will eventually be replaced by a Boost multithreading library. + +

+


+ +

+Copyright © 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. + + + \ No newline at end of file diff --git a/doc/implementation/object_pool.html b/doc/implementation/object_pool.html new file mode 100644 index 0000000..1ecdd65 --- /dev/null +++ b/doc/implementation/object_pool.html @@ -0,0 +1,70 @@ + + + +Object Pool Implementation + + + + +C++ Boost + +

Object Pool Implementation

+ +

+

Dependencies

+ +

+Includes the Boost header "pool.hpp" (see pool.html). + +

+

Extensions to Public Interface

+ +

+Whenever an object of type ObjectPool needs memory from the system, it will request it from its UserAllocator 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. + +

+

Additional constructor parameter

+ +

+Users may pass an additional constructor parameter to ObjectPool. This parameter is of type size_type, 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. + +

+

next_size accessor functions

+ +

+The pair of functions size_type get_next_size() const; and void set_next_size(size_type); allow users to explicitly read and write the next_size 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. + +

+

Protected Interface

+ +

+

Synopsis

+ +
template <typename ElementType, typename UserAllocator = default_user_allocator_new_delete>
+class object_pool: protected pool<UserAllocator>
+{
+  ... // public interface
+};
+ +

+

Protected Derivation

+ +ObjectPool derives from a simple segregated storage via protected derivation; this exposes all the Pool implementation details to all classes derived from ObjectPool as well. + +

+

Interface Description

+ +

+


+ +

+Copyright © 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. + + + \ No newline at end of file diff --git a/doc/implementation/pool.html b/doc/implementation/pool.html new file mode 100644 index 0000000..81df60a --- /dev/null +++ b/doc/implementation/pool.html @@ -0,0 +1,216 @@ + + + +Pool Implementation + + + + +C++ Boost + +

Pool Implementation

+ +

+

Dependencies

+ +

+Includes the system headers <functional>, <new>, <cstddef>, <cstdlib>, and <exception>. + +

+Includes the Boost headers "detail/ct_gcd_lcm.hpp" (see ct_gcd_lcm.html), "detail/gcd_lcm.hpp" (see gcd_lcm.html), and "simple_segregated_storage.hpp" (see simple_segregated_storage.html). + +

+

Synopsis

+ +
namespace details {
+
+template <typename SizeType>
+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 <typename UserAllocator = default_user_allocator_new_delete>
+class pool: protected simple_segregated_storage<typename UserAllocator::size_type>
+{
+  ... // public interface
+
+  protected:
+    details::PODptr<size_type> list;
+
+    simple_segregated_storage<size_type> & store();
+    const simple_segregated_storage<size_type> & store() const;
+
+    const size_type requested_size;
+    size_type next_size;
+
+    details::PODptr<size_type> 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);
+};
+ +

+

Extensions to Public Interface

+ +

+Whenever an object of type pool needs memory from the system, it will request it from its UserAllocator 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. + +

+

Additional constructor parameter

+ +

+Users may pass an additional constructor parameter to pool. This parameter is of type size_type, 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. + +

+

next_size accessor functions

+ +

+The pair of functions size_type get_next_size() const; and void set_next_size(size_type); allow users to explicitly read and write the next_size 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. + +

+

Class PODptr

+ +

+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 differing sizes, and contain some information at the end of their memory (for alignment reasons), PODptr must contain the size of this "class" as well as the pointer to this "object". + +

+A PODptr holds the location and size of a memory block allocated from the system. Each memory block is split logically into three sections: +

    +
  1. Chunk area. This section may be different sizes. PODptr 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.
  2. +
  3. Next pointer. This section is always the same size for a given SizeType. 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.
  4. +
  5. Next size. This section is always the same size for a given SizeType. It holds the size of the next memory block in the memory block list.
  6. +
+ +

+The PODptr class just provides cleaner ways of dealing with raw memory blocks. + +

+

Validity

+ +

+A PODptr object is either valid or invalid. An invalid PODptr is analogous to a null pointer. + +

+The default constructor for PODptr will result in an invalid object. Calling the member function invalidate will result in that object becoming invalid. The member function valid can be used to test for validity. + +

+

Getting PODptr objects

+ +

+A PODptr may be created to point to a memory block by passing the address and size of that memory block into the constructor. A PODptr constructed in this way is valid. + +

+A PODptr may also be created by a call to the member function next, which returns a PODptr which points to the next memory block in the memory block list, or an invalid PODptr if there is no such block. + +

+

Accessing the "pointer" data

+ +

+Each PODptr keeps the address and size of its memory block. The address may be read or written by the member functions begin. The size of the memory block may only be read, and is done so by the member function total_size. + +

+

Accessing the sections of the memory block

+ +

+The chunk area may be accessed by the member functions begin and end, in conjunction with element_size. The value returned by end is always the value returned by begin plus element_size. Only begin is writeable. end is a past-the-end value; using pointers beginning at begin and ending before end allows one to iterate through the chunks in a memory block. + +

+The next pointer area may be accessed by the member function next_ptr. The next size area may be accessed by the member function next_size. Both of these are writeable. They may both be read or set at the same time through the member function next. + +

+

Protected Interface

+ +

+

Protected Derivation

+ +Pool derives from a simple segregated storage via protected derivation; this exposes all the simple segregated storage implementation details to all classes derived from Pool as well. + +

+

details::PODptr<size_type> list;

+ +

+This is the list of memory blocks that have been allocated by this Pool object. It is not the same as the list of free memory chunks (exposed by simple segregated storage as first). + +

+

store functions

+ +

+These are convenience functions, used to return the base simple segregated storage object. + +

+

const size_type requested_size;

+ +

+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 alloc_size, below. + +

+

size_type next_size

+ +

+The number of chunks to request from the UserAllocator the next time we need to allocate system memory. See the extensions descriptions, above. + +

+

details::PODptr<size_type> find_POD(void * chunk) const;

+ +

+Searches through the memory block list, looking for the block that chunk was allocated from or may be allocated from in the future. Returns that block if found, or an invalid value if chunk has been allocated from another Pool or may be allocated from another Pool in the future. Results for other values of chunk may be wrong. + +

+

static bool is_from(void * chunk, char * i, size_type sizeof_i);

+ +

+Tests chunk to see if it has been allocated from the memory chunk at i with an element size of sizeof_i. Note that sizeof_i is the size of the chunk area of that block, not the total size of that block. + +

+Returns true if chunk has been allocated from that memory block or may be allocated from that block in the future. Returns false if chunk has been allocated from another block or may be allocated from another block in the future. Results for other values of chunk may be wrong. + +

+

size_type alloc_size() const;

+ +

+Returns the calculated size of the memory chunks that will be allocated by this Pool. For alignment reasons, this is defined to be lcm(requested_size, sizeof(void *), sizeof(size_type)). + +

+

Interface Description

+ +

+


+ +

+Copyright © 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. + + + \ No newline at end of file diff --git a/doc/implementation/pool_alloc.html b/doc/implementation/pool_alloc.html new file mode 100644 index 0000000..fff3296 --- /dev/null +++ b/doc/implementation/pool_alloc.html @@ -0,0 +1,127 @@ + + + +pool_alloc - Boost Pool Standard Allocators Implementation + + + + +C++ Boost + +

pool_alloc - Boost Pool Standard Allocators Implementation

+ +

+

Dependencies

+ +

+Includes the system headers <new> and <limits>. + +

+Includes the Boost headers "singleton_pool.hpp" (see singleton_pool.html) and "detail/mutex.hpp" (see mutex.html). + +

+

Synopsis

+ +
template <typename T,
+    typename UserAllocator = default_user_allocator_new_delete,
+    typename Mutex = details::pool::default_mutex,
+    unsigned NextSize = 32>
+class pool_allocator
+{
+  public:
+    ... // public interface
+
+  public: // extensions to public interface
+    typedef Mutex mutex;
+    static const unsigned next_size = NextSize;
+
+    template <typename U>
+    struct rebind
+    {
+      typedef pool_allocator<U, UserAllocator, Mutex, NextSize> other;
+    };
+};
+
+template <typename T,
+    typename UserAllocator = default_user_allocator_new_delete,
+    typename Mutex = details::pool::default_mutex,
+    unsigned NextSize = 32>
+class fast_pool_allocator
+{
+  public:
+    ... // public interface
+
+  public: // extensions to public interface
+    typedef Mutex mutex;
+    static const unsigned next_size = NextSize;
+
+    template <typename U>
+    struct rebind
+    {
+      typedef fast_pool_allocator<U, UserAllocator, Mutex, NextSize> other;
+    };
+};
+ +

+

Extensions to Public Interface

+ +

+

Additional template parameters

+ +

+

Mutex

+ +

+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 singleton pool for more information. + +

+

NextSize

+ +

+The value of this parameter is passed to the underlying Pool when it is created. See the extensions to the public interface of pool for more information. + +

+

Modification of rebind

+ +

+The struct rebind has been redefined to preserve the values of the additional template parameters. + +

+

Additional members

+ +

+The typedef mutex and the static const value next_size publish the values of the template parameters Mutex and NextSize, respectively. + +

+

Notes

+ +

+A number of common STL libraries contain bugs in their using of allocators. Specifically, they pass null pointers to the deallocate 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: +

+ +

+

Future Directions

+ +

+When the Boost multithreading library is completed, the Mutex parameter will be replaced by something from that library providing the same flexibility and will move from an implementation detail into the interface specification. + +

+

Interface Description

+ +

+


+ +

+Copyright © 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. + + + \ No newline at end of file diff --git a/doc/implementation/pool_construct.html b/doc/implementation/pool_construct.html new file mode 100644 index 0000000..979070b --- /dev/null +++ b/doc/implementation/pool_construct.html @@ -0,0 +1,62 @@ + + + +Object Pool Constructors Generator + + + + +C++ Boost + +

Object Pool Constructors Generator

+ +

+

Description

+ +

+The template class object_pool (see object_pool.html) contains a number of functions construct(..), which both allocate and construct an object in a single operation. + +

+Since the number and type of arguments to this function is totally arbitrary, a simple system has been set up to automatically generate template construct functions. This system is based on the macro preprocessor m4, which is standard on UNIX systems and also available for Win32 systems. + +

+detail/pool_construct.m4, when run with m4, will create the file detail/pool_construct.inc, which only defines the construct functions for the proper number of arguments. The number of arguments may be passed into the file as an m4 macro, NumberOfArguments; if not provided, it will default to 3. + +

+For each different number of arguments (1 to NumberOfArguments), 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. + +

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

+detail/pool_construct.bat and detail/pool_construct.sh are also provided to call m4, defining NumberOfArguments to be their command-line parameter. See these files for more details. + +

+

Dependencies

+ +

+Dependent on for.m4 (see for.html). + +

+

Future Directions

+ +

+This system may be complemented by or replaced by a Python (or some other language) script. + +

+

Interface Description

+ +

+


+ +

+Copyright © 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. + + + \ No newline at end of file diff --git a/doc/implementation/postulate.html b/doc/implementation/postulate.html new file mode 100644 index 0000000..9e8125c --- /dev/null +++ b/doc/implementation/postulate.html @@ -0,0 +1,129 @@ + + + +postulate - Compile-Time Assertion + + + + +C++ Boost + +

postulate - Compile-Time Assertion

+ +

+

Introduction

+ +

+detail/postulate.hpp provides a macro that can be used to test compile-time boolean conditions. This macro, BOOST_POOL_POSTULATE, takes one parameter, which is the condition to test. It will fail to compile if that condition is false. Any integral constant expression [5.19/1] may be used as the condition, which includes expressions dependent on template arguments. + +

+BOOST_POOL_POSTULATE may be used at namespace scope, class scope, or function scope. It may not 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. + +

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

+This file also provides a macro, BOOST_POOL_JOIN, which merges two preprocessor tokens after macro substitution. (The ## preprocessor operator merges them before macro substitution). + +

+

Examples

+ +

+One of the simplest examples is to ensure that we are running on a 32-bit platform: +

// This code is only valid on a 32-bit platform
+BOOST_POOL_POSTULATE(sizeof(int) * CHAR_BIT == 32);
+ +

+Or, for more portable code, to ensure that we are running on a 2's complement platform: +

// This code must run on a 2's complement platform
+BOOST_POOL_POSTULATE(~1 + 1 == -1);
+ +

+More complicated usage allows arbitrary restrictions on template arguments: +

template <int x, int y>
+struct EmmaWoodhouse
+{
+  // The following tests are not actually tested until
+  //  EmmaWoodhouse<X, Y> is instantiated for some X and Y
+
+  // x has to be >= 13 because . . .
+  BOOST_POOL_POSTULATE(x >= 13);
+
+  // y has to be > x because . . .
+  BOOST_POOL_POSTULATE(y > x);
+  . . .
+};
+ +

+

Symbols

+ +

+

+ +

+

Notes

+ +

+No compile-time assertion mechanism is perfect. However, each one should attempt to satisfy the following requirements: +

    +
  1. Basics +
    +
    Can use compile-time constants
    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. +
    Stop with error
    With a false expression it will prevent the program from compiling, causing an an error. +
    Portable
    It will work on any conforming compiler (uses only things in the standard). +
    Practical
    It will work on currently available compilers. +
    Efficient
    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. +
  2. Error Message +
    +
    Error on correct line
    Give an error message at the line where the assertion fails. The line that the compiler reports an error on will be the line of the assertion statement. +
    Good error message
    The error message will be easy to understand on any compiler. +
  3. Usage +
    +
    Universal syntax
    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. +
    Simple syntax
    It can be called in a simple way, similar to assert. +
    Robust syntax
    Won't silently fail on simple coding errors. +
  4. Namespace pollution +
    +
    Minimal pollution
    Scopes should be polluted in a minimal way. +
    Macro avoidance
    Since macros pollute every scope, they should be avoided. +
+ +

+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 "postualte." + +

+

Dependencies

+ +

+None. + +

+

Selected Quotations from the Standard

+ +

+ +5.19/1: Expressions: Constant Expressions: ". . . An integral constant expression can involve only literals (2.13), enumerators, const 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 sizeof 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 sizeof expressions, functions, class objects, pointers, or references shall not be used, and assignment, increment, decrement, function-call, or comma operators shall not be used." + +

+

Future Directions

+ +

+This header will soon be replaced by the Boost static assert library. + +

+


+ +

+Copyright © 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. + + + \ No newline at end of file diff --git a/doc/implementation/simple_segregated_storage.html b/doc/implementation/simple_segregated_storage.html new file mode 100644 index 0000000..fd27edf --- /dev/null +++ b/doc/implementation/simple_segregated_storage.html @@ -0,0 +1,76 @@ + + + +Simple Segregated Storage Implementation + + + + +C++ Boost + +

Simple Segregated Storage Implementation

+ +

+

Dependencies

+ +

+Includes the system headers <cstddef> and <functional>. + +

+

Protected Interface

+ +

+

Synopsis

+ +
template <typename SizeType = std::size_t>
+class simple_segregated_storage
+{
+  ... // Public interface
+
+  protected:
+    void * first;
+    static void * & nextof(void * const ptr);
+    void * find_prev(void * ptr);
+};
+ +

+

void * first;

+ +

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

+

static void * & nextof(void * const ptr);

+ +

+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 *ptr cast to the appropriate type. ptr must not be 0. + +

+As an example, let us assume that we want to truncate the free list after the first chunk. That is, we want to set *first to 0; this will result in a free list with only one entry. The normal way to do this is to first cast first to a pointer to a pointer to void, and then dereference and assign (*static_cast<void **>(first) = 0;). This can be done more easily through the use of this convenience function (nextof(first) = 0;). + +

+

void * find_prev(void * ptr);

+ +

+Traverses the free list referred to by first, and returns the pointer 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). + +

+Note that this function finds the location previous to where ptr would go if it was in the free list. It does not find the entry in the free list before ptr (unless ptr is already in the free list). Specifically, find_prev(0) will return 0, not the last entry in the free list. + +

+

Interface Description

+ +

+


+ +

+Copyright © 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. + + + \ No newline at end of file diff --git a/doc/implementation/singleton.html b/doc/implementation/singleton.html new file mode 100644 index 0000000..21670fb --- /dev/null +++ b/doc/implementation/singleton.html @@ -0,0 +1,94 @@ + + + +singleton - Singleton + + + + +C++ Boost + +

singleton - Singleton

+ +

+

Introduction

+ +

+detail/singleton.hpp provides a way to access a Singleton of a class type. This is not a general Singleton solution! It is restricted in that the class type must have a default constructor. + +

+

Synopsis

+ +
namespace details {
+namespace pool {
+
+template <typename T>
+class singleton_default
+{
+  private:
+    singleton_default();
+
+  public:
+    typedef T object_type;
+
+    static object_type & instance();
+};
+
+} // namespace pool
+} // namespace details
+ +

+

Semantics

+ +

+ + +
Symbol Table
SymbolMeaning +
TAny class with a non-throwing default constructor and non-throwing destructor +
+ +

+ + +
Requirements satisfied by singleton_default<T>
ExpressionReturn TypeAssertion/Note/Pre/Post-Condition +
singleton_default<T>::instance()T &Returns a reference to the singleton instance +
+ +

+

Guarantees

+ +

+The singleton instance is guaranteed to be constructed before main() begins, and destructed after main() ends. Furthermore, it is guaranteed to be constructed before the first call to singleton_default<T>::instance() is complete (even if called before main() begins). Thus, if there are not multiple threads running except within main(), and if all access to the singleton is restricted by mutexes, then this guarantee allows a thread-safe singleton. + +

+

Details

+ +

+For details on how we provide the guarantees above, see the comments in the header file. + +

+

Dependencies

+ +

+None. + +

+

Future Directions

+ +

+This header may be replaced by a Boost singleton library. + +

+


+ +

+Copyright © 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. + + + \ No newline at end of file diff --git a/doc/implementation/singleton_pool.html b/doc/implementation/singleton_pool.html new file mode 100644 index 0000000..824797c --- /dev/null +++ b/doc/implementation/singleton_pool.html @@ -0,0 +1,82 @@ + + + +Singleton Pool Implementation + + + + +C++ Boost + +

Singleton Pool Implementation

+ +

+

Dependencies

+ +

+Includes the Boost headers "pool.hpp" (see pool.html), "detail/singleton.hpp" (see singleton.html), "detail/mutex.hpp" (see mutex.html), and "detail/guard.hpp" (see guard.html). + +

+

Synopsis

+ +
template <typename Tag,
+    unsigned RequestedSize,
+    typename UserAllocator = default_user_allocator_new_delete,
+    typename Mutex = details::pool::default_mutex,
+    unsigned NextSize = 32>
+class singleton_pool
+{
+  ... // public interface
+
+  public: // extensions to public interface
+    typedef Mutex mutex;
+    static const unsigned next_size = NextSize;
+};
+ +

+

Extensions to Public Interface

+ +

+

Additional template parameters

+ +

+

Mutex

+ +

+This class is the type of mutex 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 details::pool::null_mutex) for efficiency reasons. + +

+

NextSize

+ +

+The value of this parameter is passed to the underlying Pool when it is created. See the extensions to the public interface of pool for more information. + +

+

Additional members

+ +

+The typedef mutex and the static const value next_size publish the values of the template parameters Mutex and NextSize, respectively. + +

+

Future Directions

+ +

+When the Boost multithreading library is completed, the Mutex parameter will be replaced by something from that library providing the same flexibility and will move from an implementation detail into the interface specification. + +

+

Interface Description

+ +

+


+ +

+Copyright © 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. + + + \ No newline at end of file diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000..5d97bec --- /dev/null +++ b/doc/index.html @@ -0,0 +1,155 @@ + + + +Boost Pool Library + + + + +C++ Boost + +

Boost Pool Library

+ +

+

Introduction

+ +

+

What is Pool?

+ +

+Pool allocation is a memory allocation scheme that is very fast, but limited in its usage. For more information on pool allocation (also called "simple segregated storage"), see the concepts document. + +

+

Why should I use Pool?

+ +

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

+

When should I use Pool?

+ +

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

+In general, use Pools when you need a more efficient way to do unusual memory control. + +

+

How do I use Pool?

+ +

+See the pool interfaces document, which covers the different Pool interfaces supplied by this library. + +

+

Library Structure and Dependencies

+ +

+Each exposed library header xxx.hpp has a corresponding header xxx_fwd.hpp, which contains forward declarations of each exposed library symbol of that header. + +

+The library may use macros, which will be prefixed with BOOST_POOL_. The exception to this rule are the include file guards, which (for file xxx.hpp) is BOOST_xxx_HPP. + +

+All exposed symbols defined by the library will be in namespace boost. All symbols used only by the implementation will be in namespace boost::details::pool. + +

+Every header used only by the implementation is in the subdirectory detail/. + +

+Any header in the library may include any other header in the library or any system-supplied header at its discretion. + +

+

Installation

+ +

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

+

Building the Test Programs

+ +

+The subdirectory "build" 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. + +

+Read the "readme.txt" in the proper subdirectory, if it exists. + +

+The standard makefile targets are "all", "clean" (which deletes any intermediate files), and "veryclean" (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, "clean" and "veryclean" shell scripts/batch files will be provided. + +

+Project files and makefiles for additional platforms may be sent to Stephen Cleary at shammah@voyager.net. + +

+

Documentation Map

+ + + +

+

Future Directions

+ +

+Another pool interface will be written: a base class for per-class pool allocation. + +

+

Acknowledgements

+ +

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

+


+ +

+Copyright © 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. + + + \ No newline at end of file diff --git a/doc/interfaces.html b/doc/interfaces.html new file mode 100644 index 0000000..a0290e3 --- /dev/null +++ b/doc/interfaces.html @@ -0,0 +1,137 @@ + + + +Boost Pool Interfaces + + + + +C++ Boost + +

Boost Pool Interfaces

+ +

+

Introduction

+ +

+There are several interfaces provided which allow users great flexibility in how they want to use Pools. Review the concepts document to get the basic understanding of how Pools work. + +

+

Terminology and Tradeoffs

+ +

+

Object Usage vs. Singleton Usage

+ +

+Object Usage 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. + +

+Singleton Usage 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 release_memory or purge_memory. + +

+

Out-of-Memory Conditions: Exceptions vs. Null Return

+ +

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

+

The Interfaces

+ +

+

pool

+ +

+The pool interface is a simple Object Usage interface with Null Return. + +

+Example: +

void func()
+{
+  boost::pool<> 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
+ +

+

object_pool

+ +

+The object_pool interface 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. + +

+Example: +

struct X { ... }; // has destructor with side-effects
+
+void func()
+{
+  boost::object_pool<X> 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
+ +

+

singleton_pool

+ +

+The singleton_pool interface is a Singleton Usage interface with Null Return. It's just the same as the pool interface but with Singleton Usage instead. + +

+Example: +

struct MyPoolTag { };
+
+typedef boost::singleton_pool<MyPoolTag, sizeof(int)> 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();
+}
+ +

+

pool_alloc

+ +

+The pool_alloc interface 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.). + +

+Example: +

void func()
+{
+  std::vector<int, boost::pool_allocator<int> > 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<boost::pool_allocator_tag, sizeof(int)>::release_memory()
+  // in order to force that
+ +

+

Future Directions

+ +

+Another pool interface will be written: a base class for per-class pool allocation. This "pool_base" interface will be Singleton Usage with Exceptions, and built on the singleton_pool interface. + +

+


+ +

+Copyright © 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. + + + \ No newline at end of file diff --git a/doc/interfaces/object_pool.html b/doc/interfaces/object_pool.html new file mode 100644 index 0000000..7549f8f --- /dev/null +++ b/doc/interfaces/object_pool.html @@ -0,0 +1,128 @@ + + + +object_pool - Boost Object Pool Allocator + + + + +C++ Boost + +

object_pool - Boost Object Pool Allocator

+ +

+

Introduction

+ +

+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 the other pool interfaces. + +

+

Synopsis

+ +
template <typename ElementType, typename UserAllocator = default_user_allocator_new_delete>
+class object_pool
+{
+  private:
+    object_pool(const object_pool &);
+    void operator=(const object_pool &);
+
+  public:
+    typedef ElementType element_type;
+    typedef UserAllocator user_allocator;
+    typedef typename pool<UserAllocator>::size_type size_type;
+    typedef typename pool<UserAllocator>::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);
+};
+ +

+

Template Parameters

+ +

+

ElementType

+ +

+The template parameter is the type of object to allocate/deallocate. It must have a non-throwing destructor. + +

+

UserAllocator

+ +

+Defines the method that the underlying Pool will use to allocate memory from the system. See User Allocators for details. + +

+

Semantics

+ +

+ + +
Symbol Table
SymbolMeaning +
ObjectPoolobject_pool<ElementType, UserAllocator> +
tvalue of type ObjectPool +
uvalue of type const ObjectPool +
pvalue of type ElementType * +
+ +

+ + +
Typedefs
ExpressionType +
ObjectPool::element_typeElementType +
ObjectPool::user_allocatorUserAllocator +
ObjectPool::size_typepool<UserAllocator>::size_type +
ObjectPool::difference_typepool<UserAllocator>::difference_type +
+ +

+ + +
Constructors, Destructors, and Testing
ExpressionReturn TypeNotes +
ObjectPool()not usedConstructs a new empty ObjectPool +
(&t)->~ObjectPool()not usedDestructs the ObjectPool; ~ElementType() is called for each allocated ElementType that has not been deallocated. O(N). +
u.is_from(p)boolReturns true if p was allocated from u or may be returned as the result of a future allocation from u. Returns false if p 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 not be used to reliably test random pointer values. +
+ +

+ + +
Allocation and Deallocation
ExpressionReturn TypePre-ConditionSemantic EquivalenceNotes +
t.malloc()ElementType *Allocates memory that can hold an object of type ElementType. If out of memory, returns 0. Amortized O(1). +
t.free(p)not usedp must have been previously allocated from tDeallocates a chunk of memory. Note that p may not be 0. Note that the destructor for p is not called. O(N). +
t.construct(???)ElementType *ElementType must have a constructor matching ???; the number of parameters given must not exceed what is supported through pool_constructAllocates and initializes an object of type ElementType. If out of memory, returns 0. Amortized O(1). +
t.destroy(p)not usedp must have been previously allocated from tp->~ElementType(); t.free(p); +
+ +

+

Symbols

+ +

+

+ +

+

Implementation Details

+ +

+


+ +

+Copyright © 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. + + + \ No newline at end of file diff --git a/doc/interfaces/pool.html b/doc/interfaces/pool.html new file mode 100644 index 0000000..e037049 --- /dev/null +++ b/doc/interfaces/pool.html @@ -0,0 +1,143 @@ + + + +Pool + + + + +C++ Boost + +

Pool

+ +

+

Introduction

+ +

+pool is a fast memory allocator, and guarantees proper alignment of all allocated chunks. + +

+pool.hpp provides two UserAllocator classes and a template class pool, which extends and generalizes the framework provided by the simple segregated storage solution. For information on other pool-based interfaces, see the other pool interfaces. + +

+

Synopsis

+ +
struct default_user_allocator_new_delete; // see User Allocators
+struct default_user_allocator_malloc_free; // see User Allocators
+
+template <typename UserAllocator = default_user_allocator_new_delete>
+class pool
+{
+  private:
+    pool(const pool &);
+    void operator=(const pool &);
+
+  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);
+};
+ +

+

Template Parameters

+ +

+

UserAllocator

+ +

+Defines the method that the Pool will use to allocate memory from the system. See User Allocators for details. + +

+

Semantics

+ +

+ + +
Symbol Table
SymbolMeaning +
Poolpool<UserAllocator> +
tvalue of type Pool +
uvalue of type const Pool +
chunkvalue of type void * +
nvalue of type size_type +
RequestedSizevalue of type Pool::size_type; must be greater than 0 +
+ +

+ + +
Typedefs
ExpressionType +
Pool::user_allocatorUserAllocator +
Pool::size_typeUserAllocator::size_type +
Pool::difference_typeUserAllocator::difference_type +
+ +

+ + +
Constructors, Destructors, and Testing
ExpressionReturn TypeNotes +
Pool(RequestedSize)not usedConstructs a new empty Pool that can be used to allocate chunks of size RequestedSize +
(&t)->~Pool()not usedDestructs the Pool, freeing its list of memory blocks +
u.is_from(chunk)boolReturns true if chunk was allocated from u or may be returned as the result of a future allocation from u. Returns false if chunk 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 not be used to reliably test random pointer values. +
u.get_requested_size()size_typeReturns the value passed into the constructor. This value will not change during the lifetime of a Pool object. +
+ +

+ + +
Allocation and Deallocation
ExpressionReturn TypePre-ConditionNotes +
t.malloc()void *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 t's free list, and returns a free chunk from that block. If a new memory block cannot be allocated, returns 0. Amortized O(1). +
t.ordered_malloc()void *Same as above, only merges the free lists, to preserve order. Amortized O(1). +
t.ordered_malloc(n)void *Same as above, only allocates enough contiguous chunks to cover n * requested_size bytes. Amortized O(n). +
t.free(chunk)voidchunk must have been previously returned by t.malloc() or t.ordered_malloc().Deallocates a chunk of memory. Note that chunk may not be 0. O(1). +
t.ordered_free(chunk)voidSame as aboveSame as above, but is order-preserving. Note that chunk may not be 0. O(N) with respect to the size of the free list +
t.free(chunk, n)voidchunk must have been previously returned by t.ordered_malloc(n).Assumes that chunk actually refers to a block of chunks spanning n * partition_sz bytes; deallocates each chunk in that block. Note that chunk may not be 0. O(n). +
t.ordered_free(chunk, n)voidchunk must have been previously returned by t.ordered_malloc(n).Assumes that chunk actually refers to a block of chunks spanning n * partition_sz bytes; deallocates each chunk in that block. Note that chunk may not be 0. Order-preserving. O(N + n) where N is the size of the free list. +
t.release_memory()boolt must be ordered.Frees every memory block that doesn't have any allocated chunks. Returns true if at least one memory block was freed. +
t.purge_memory()boolFrees every memory block. This function invalidates any pointers previously returned by allocation functions of t. Returns true if at least one memory block was freed. +
+ +

+

Symbols

+ +

+

+ +

+

Implementation Details

+ +

+


+ +

+Copyright © 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. + + + \ No newline at end of file diff --git a/doc/interfaces/pool_alloc.html b/doc/interfaces/pool_alloc.html new file mode 100644 index 0000000..2a91ef2 --- /dev/null +++ b/doc/interfaces/pool_alloc.html @@ -0,0 +1,202 @@ + + + +pool_alloc - Boost Pool Standard Allocators + + + + +C++ Boost + +

pool_alloc - Boost Pool Standard Allocators

+ +

+

Introduction

+ +

+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 the other pool interfaces. + +

+

Synopsis

+ +
struct pool_allocator_tag { };
+
+template <typename T,
+    typename UserAllocator = default_user_allocator_new_delete>
+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 & reference;
+    typedef const value_type & const_reference;
+    typedef typename pool<UserAllocator>::size_type size_type;
+    typedef typename pool<UserAllcoator>::difference_type difference_type;
+
+    template <typename U>
+    struct rebind
+    { typedef pool_allocator<U, UserAllocator> other; };
+
+  public:
+    pool_allocator();
+    pool_allocator(const pool_allocator &);
+    // The following is not explicit, mimicking std::allocator [20.4.1]
+    template <typename U>
+    pool_allocator(const pool_allocator<U, UserAllocator> &);
+    pool_allocator & operator=(const pool_allocator &);
+    ~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 & t);
+    static void destroy(pointer ptr);
+
+    bool operator==(const pool_allocator &) const;
+    bool operator!=(const pool_allocator &) 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 <typename T
+    typename UserAllocator = default_user_allocator_new_delete>
+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 & 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> other; };
+
+  public:
+    fast_pool_allocator();
+    fast_pool_allocator(const fast_pool_allocator &);
+    // The following is not explicit, mimicking std::allocator [20.4.1]
+    template <typename U>
+    fast_pool_allocator(const fast_pool_allocator<U, UserAllocator> &);
+    fast_pool_allocator & operator=(const fast_pool_allocator &);
+    ~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 & t);
+    static void destroy(pointer ptr);
+
+    bool operator==(const fast_pool_allocator &) const;
+    bool operator!=(const fast_pool_allocator &) 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);
+};
+ +

+

Template Parameters

+ +

+

T

+ +

+The first template parameter is the type of object to allocate/deallocate. + +

+

UserAllocator

+ +

+Defines the method that the underlying Pool will use to allocate memory from the system. See User Allocators for details. + +

+

Semantics

+ +

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

+In addition, the fast_pool_allocator also provides an additional allocation and an additional deallocation function: + +

+ + +
Symbol Table
SymbolMeaning +
PoolAllocfast_pool_allocator<T, UserAllocator> +
pvalue of type T * +
+ +

+ + +
Additional allocation/deallocation functions (fast_pool_allocator only)
ExpressionReturn TypeSemantic Equivalence +
PoolAlloc::allocate()T *PoolAlloc::allocate(1) +
PoolAlloc::deallocate(p)voidPoolAlloc::deallocate(p, 1) +
+ +

+The typedef user_allocator publishes the value of the UserAllocator template parameter. + +

+

Notes

+ +

+If the allocation functions run out of memory, they will throw std::bad_alloc. + +

+The underlying Pool type used by the allocators is accessible through the Singleton Pool Interface. The identifying tag used for pool_allocator is pool_allocator_tag, and the tag used for fast_pool_allocator is fast_pool_allocator_tag. All template parameters of the allocators (including implementation-specific ones) determine the type of the underlying Pool, with the exception of the first parameter T, whose size is used instead. + +

+Since the size of T is used to determine the type of the underlying Pool, each allocator for different types of the same size will share the same underlying pool. The tag class prevents pools from being shared between pool_allocator and fast_pool_allocator. For example, on a system where sizeof(int) == sizeof(void *), pool_allocator<int> and pool_allocator<void *> will both allocate/deallocate from/to the same pool. + +

+If there is only one thread running before main() starts and after main() ends, then both allocators are completely thread-safe. + +

+

The Fast Pool Allocator

+ +

+pool_allocator is a more general-purpose solution, geared towards efficiently servicing requests for any number of contiguous chunks. fast_pool_allocator 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 pool_allocator. If you are seriously concerned about performance, use fast_pool_allocator when dealing with containers such as std::list, and use pool_allocator when dealing with containers such as std::vector. + +

+

Symbols

+ +

+

+ +

+

Implementation Details

+ +

+


+ +

+Copyright © 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. + + + \ No newline at end of file diff --git a/doc/interfaces/simple_segregated_storage.html b/doc/interfaces/simple_segregated_storage.html new file mode 100644 index 0000000..c7456d8 --- /dev/null +++ b/doc/interfaces/simple_segregated_storage.html @@ -0,0 +1,150 @@ + + + +Simple Segregated Storage + + + + +C++ Boost + +

Simple Segregated Storage

+ +

+

Introduction

+ +

+simple_segregated_storage.hpp provides a template class simple_segregated_storage that controls access to a free list of memory chunks. Please note that this is a very simple class, with preconditions on almost all its functions. It is intended to be the fastest and smallest possible quick memory allocator — 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 the other pool interfaces. + +

+

Synopsis

+ +
template <typename SizeType = std::size_t>
+class simple_segregated_storage
+{
+  private:
+    simple_segregated_storage(const simple_segregated_storage &);
+    void operator=(const simple_segregated_storage &);
+
+  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);
+};
+ +

+

Semantics

+ +

+An object of type simple_segregated_storage<SizeType> is empty if its free list is empty. If it is not empty, then it is ordered if its free list is ordered. A free list is ordered if repeated calls to malloc() will result in a constantly-increasing sequence of values, as determined by std::less<void *>. A member function is order-preserving if the free list maintains its order orientation (that is, an ordered free list is still ordered after the member function call). + +

+ + +
Symbol Table
SymbolMeaning +
Storesimple_segregated_storage<SizeType> +
tvalue of type Store +
uvalue of type const Store +
block, chunk, endvalues of type void * +
partition_sz, sz, nvalues of type Store::size_type +
+ +

+ + +
Template Parameters
ParameterDefaultRequirements +
SizeTypestd::size_tAn unsigned integral type +
+ +

+ + +
Typedefs
SymbolType +
size_typeSizeType +
+ +

+ + +
Constructors, Destructors, and State
ExpressionReturn TypePost-ConditionNotes +
Store()not usedempty()Constructs a new Store +
(&t)->~Store()not usedDestructs the Store +
u.empty()boolReturns true if u is empty. Order-preserving. +
+ +

+ + +
Segregation
ExpressionReturn TypePre-ConditionPost-ConditionSemantic EquivalenceNotes + +
Store::segregate(block, sz, partition_sz, end)void *partition_sz >= sizeof(void *)
partition_sz = sizeof(void *) * i, for some integer i
sz >= partition_sz
block is properly aligned for an array of objects of size partition_sz
block is properly aligned for an array of void *
Interleaves a free list through the memory block specified by block of size sz bytes, partitioning it into as many partition_sz-sized chunks as possible. The last chunk is set to point to end, and a pointer to the first chunck is returned (this is always equal to block). This interleaved free list is ordered. O(sz). + +
Store::segregate(block, sz, partition_sz)void *Same as aboveStore::segregate(block, sz, partition_sz, 0) + +
t.add_block(block, sz, partition_sz)voidSame as above!t.empty()Segregates the memory block specified by block of size sz bytes into partition_sz-sized chunks, and adds that free list to its own. If t was empty before this call, then it is ordered after this call. O(sz). + +
t.add_ordered_block(block, sz, partition_sz)voidSame as above!t.empty()Segregates the memory block specified by block of size sz bytes into partition_sz-sized chunks, and merges that free list into its own. Order-preserving. O(sz). +
+ +

+ + +
Allocation and Deallocation
ExpressionReturn TypePre-ConditionPost-ConditionSemantic EquivalenceNotes +
t.malloc()void *!t.empty()Takes the first available chunk from the free list and returns it. Order-preserving. O(1). + +
t.free(chunk)voidchunk was previously returned from a call to t.malloc()!t.empty()Places chunk back on the free list. Note that chunk may not be 0. O(1). + +
t.ordered_free(chunk)voidSame as above!t.empty()Places chunk back on the free list. Note that chunk may not be 0. Order-preserving. O(N) with respect to the size of the free list. + +
t.malloc_n(n, partition_sz)void *!empty()Attempts to find a contiguous sequence of n partition_sz-sized chunks. If found, removes them all from the free list and returns a pointer to the first. If not found, returns 0. 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. + +
t.free_n(chunk, n, partition_sz)voidchunk was previously returned from a call to t.malloc_n(n, partition_sz)!t.empty()t.add_block(chunk, n * partition_sz, partition_sz)Assumes that chunk actually refers to a block of chunks spanning n * partition_sz bytes; segregates and adds in that block. Note that chunk may not be 0. O(n). + +
t.ordered_free_n(chunk, n, partition_sz)voidsame as abovesame as abovet.add_ordered_block(chunk, n * partition_sz, partition_sz)Same as above, except it merges in the free list. Order-preserving. O(N + n) where N is the size of the free list. +
+ +

+

Symbols

+ +

+

+ +

+

Implementation Details

+ +

+


+ +

+Copyright © 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. + + + \ No newline at end of file diff --git a/doc/interfaces/singleton_pool.html b/doc/interfaces/singleton_pool.html new file mode 100644 index 0000000..eef2381 --- /dev/null +++ b/doc/interfaces/singleton_pool.html @@ -0,0 +1,157 @@ + + + +Singleton Pool + + + + +C++ Boost + +

Singleton Pool

+ +

+

Introduction

+ +

+singleton_pool.hpp provides a template class singleton_pool, which provides access to a pool as a singleton object. For information on other pool-based interfaces, see the other pool interfaces. + +

+

Synopsis

+ +
template <typename Tag, unsigned RequestedSize,
+    typename UserAllocator = default_user_allocator_new_delete>
+struct singleton_pool
+{
+  public:
+    typedef Tag tag;
+    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;
+
+  private:
+    static pool<size_type> 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();
+};
+ +

+

Notes

+ +

+The underlying pool p referenced by the static functions in singleton_pool is actually declared in a way that it is: +

+ +

+Note that a different underlying pool p exists for each different set of template parameters, including implementation-specific ones. + +

+

Template Parameters

+ +

+

Tag

+ +

+The Tag template parameter allows different unbounded sets of singleton pools to exist. For example, the pool allocators use two tag classes to ensure that the two different allocator types never share the same underlying singleton pool. + +

+Tag is never actually used by singleton_pool. + +

+

RequestedSize

+ +

+The requested size of memory chunks to allocate. This is passed as a constructor parameter to the underlying pool. Must be greater than 0. + +

+

UserAllocator

+ +

+Defines the method that the underlying pool will use to allocate memory from the system. See User Allocators for details. + +

+

Semantics

+ +

+ + +
Symbol Table
SymbolMeaning +
SingletonPoolsingleton_pool<Tag, RequestedSize, UserAllocator> +
chunkvalue of type void * +
nvalue of type size_type +
+ +

+ + +
Typedefs/Static Const Values
ExpressionType/Value +
SingletonPool::tagTag +
SingletonPool::user_allocatorUserAllocator +
SingletonPool::size_typepool<UserAllocator>::size_type +
SingletonPool::difference_typepool<UserAllocator>::difference_type +
SingletonPool::requested_sizeRequestedSize +
+ +

+ + +
Functions
ExpressionReturn TypeSemantic Equivalent +
SingletonPool::is_from(chunk)boolSingletonPool::p.is_from(chunk); synchronized +
SingletonPool::malloc()void *SingletonPool::p.malloc(); synchronized +
SingletonPool::ordered_malloc(n)void *SingletonPool::p.ordered_malloc(n); synchronized +
SingletonPool::free(chunk)voidSingletonPool::p.free(chunk); synchronized +
SingletonPool::ordered_free(chunk)voidSingletonPool::p.ordered_free(chunk); synchronized +
SingletonPool::free(chunk, n)voidSingletonPool::p.free(chunk, n); synchronized +
SingletonPool::ordered_free(chunk, n)voidSingletonPool::p.ordered_free(chunk, n); synchronized +
SingletonPool::release_memory()boolSingletonPool::p.release_memory(); synchronized +
SingletonPool::purge_memory()boolSingletonPool::p.purge_memory(); synchronized +
+ +

+For more information on the semantics of these functions, see the pool interface. + +

+

Symbols

+ +

+

+ +

+

Implementation Details

+ +

+


+ +

+Copyright © 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. + + + \ No newline at end of file diff --git a/doc/interfaces/user_allocator.html b/doc/interfaces/user_allocator.html new file mode 100644 index 0000000..ce048ee --- /dev/null +++ b/doc/interfaces/user_allocator.html @@ -0,0 +1,91 @@ + + + +Pool + + + + +C++ Boost + +

User Allocators

+ +

+

Introduction

+ +

+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 UserAllocator template parameter to various Pool interfaces, users can control how those system memory blocks are allocated. + +

+

Semantics

+ +

+ + +
Symbol Table
SymbolMeaning +
UserAllocatorA User Allocator type +
blockvalue of type char * +
nvalue of type UserAllocator::size_type +
+ +

+ + +
Typedefs
ExpressionType +
UserAllocator::size_typeAn unsigned integral type that can represent the size of the largest object to be allocated +
UserAllocator::difference_typeA signed integral type that can represent the difference of any two pointers +
+ +

+ + +
Allocation and Deallocation
ExpressionReturn TypePre-Condition/Notes +
UserAllocator::malloc(n)char *Attempts to allocate n bytes from the system. Returns 0 if out-of-memory. +
UserAllocator::free(block)voidblock must have been previously returned from a call to UserAllocator::malloc. +
+ +

+

Provided Implementations

+ +

+There are two UserAllocator classes provided. Both of them are in pool.hpp (see pool). The default value for the template parameter UserAllocator is always default_user_allocator_new_delete. + +

+

Synopsis

+ +
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); }
+};
+ +

+


+ +

+Copyright © 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. + + + \ No newline at end of file diff --git a/doc/pool.css b/doc/pool.css new file mode 100644 index 0000000..ff75479 --- /dev/null +++ b/doc/pool.css @@ -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% } diff --git a/include/boost/pool/detail/ct_gcd_lcm.hpp b/include/boost/pool/detail/ct_gcd_lcm.hpp new file mode 100644 index 0000000..83ea1cb --- /dev/null +++ b/include/boost/pool/detail/ct_gcd_lcm.hpp @@ -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 + +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 +struct ct_gcd_helper; +template +struct ct_gcd_helper +{ +//WAS: static const unsigned value = ct_gcd_helper::value; + static const unsigned value = ct_gcd_helper::value; +}; +template +struct ct_gcd_helper +{ + static const unsigned value = A; +}; +} // namespace details + +template +struct ct_gcd +{ + BOOST_POOL_POSTULATE(A != 0 && B != 0); + static const unsigned value = details::ct_gcd_helper::value; +}; + +// +// ct_lcm is a compile-time algorithm that calculates the least common +// multiple of two unsigned integers. +// +// assumes: A != 0 && B != 0 +// +template +struct ct_lcm +{ + static const unsigned value = A / ct_gcd::value * B; +}; + +} // namespace pool +} // namespace details + +} // namespace boost + +#endif diff --git a/include/boost/pool/detail/for.m4 b/include/boost/pool/detail/for.m4 new file mode 100644 index 0000000..e62b163 --- /dev/null +++ b/include/boost/pool/detail/for.m4 @@ -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 \ No newline at end of file diff --git a/include/boost/pool/detail/gcd_lcm.hpp b/include/boost/pool/detail/gcd_lcm.hpp new file mode 100644 index 0000000..4aecbd3 --- /dev/null +++ b/include/boost/pool/detail/gcd_lcm.hpp @@ -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 +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 +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 diff --git a/include/boost/pool/detail/guard.hpp b/include/boost/pool/detail/guard.hpp new file mode 100644 index 0000000..1699852 --- /dev/null +++ b/include/boost/pool/detail/guard.hpp @@ -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 +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 diff --git a/include/boost/pool/detail/mutex.hpp b/include/boost/pool/detail/mutex.hpp new file mode 100644 index 0000000..ab5a906 --- /dev/null +++ b/include/boost/pool/detail/mutex.hpp @@ -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 + #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 +#elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_PTHREAD + #include +#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 diff --git a/include/boost/pool/detail/pool_construct.bat b/include/boost/pool/detail/pool_construct.bat new file mode 100755 index 0000000..e1977aa --- /dev/null +++ b/include/boost/pool/detail/pool_construct.bat @@ -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 \ No newline at end of file diff --git a/include/boost/pool/detail/pool_construct.inc b/include/boost/pool/detail/pool_construct.inc new file mode 100644 index 0000000..5a0519b --- /dev/null +++ b/include/boost/pool/detail/pool_construct.inc @@ -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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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; +} + diff --git a/include/boost/pool/detail/pool_construct.m4 b/include/boost/pool/detail/pool_construct.m4 new file mode 100644 index 0000000..a858d4a --- /dev/null +++ b/include/boost/pool/detail/pool_construct.m4 @@ -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 +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; +} +')') diff --git a/include/boost/pool/detail/pool_construct.sh b/include/boost/pool/detail/pool_construct.sh new file mode 100644 index 0000000..57b5f3c --- /dev/null +++ b/include/boost/pool/detail/pool_construct.sh @@ -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 diff --git a/include/boost/pool/detail/postulate.hpp b/include/boost/pool/detail/postulate.hpp new file mode 100644 index 0000000..633fc62 --- /dev/null +++ b/include/boost/pool/detail/postulate.hpp @@ -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 +struct BOOST_POOL_POSTULATE_FAILED; +template <> +struct BOOST_POOL_POSTULATE_FAILED { }; + +// POSTULATE_helper is just a helper class used to force the implicit +// instantiation of BOOST_POOL_POSTULATE_FAILED. +template +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 \ + )> \ + BOOST_POOL_JOIN(BOOST_POOL_POSTULATE_on_line_, __LINE__) + +#endif diff --git a/include/boost/pool/detail/select_type.hpp b/include/boost/pool/detail/select_type.hpp new file mode 100644 index 0000000..2a95a98 --- /dev/null +++ b/include/boost/pool/detail/select_type.hpp @@ -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 +// 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::type + template struct if_true + { + template + struct then { typedef T type; }; + }; + + template <> + struct if_true + { + template + struct then { typedef F type; }; + }; +}} +#endif // SELECT_TYPE_DWA20010206_HPP diff --git a/include/boost/pool/detail/singleton.hpp b/include/boost/pool/detail/singleton.hpp new file mode 100644 index 0000000..ef1b37f --- /dev/null +++ b/include/boost/pool/detail/singleton.hpp @@ -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::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 +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::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::create_object, whose constructor is + // called before main() begins. + create_object.do_nothing(); + + return obj; + } +}; +template +typename singleton_default::object_creator +singleton_default::create_object; + +} // namespace pool +} // namespace details + +} // namespace boost + +#endif diff --git a/include/boost/pool/object_pool.hpp b/include/boost/pool/object_pool.hpp new file mode 100644 index 0000000..848e080 --- /dev/null +++ b/include/boost/pool/object_pool.hpp @@ -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 +#include + +namespace boost { + +// T must have a non-throwing destructor +template +class object_pool: protected pool +{ + public: + typedef T element_type; + typedef UserAllocator user_allocator; + typedef typename pool::size_type size_type; + typedef typename pool::difference_type difference_type; + + public: + // This constructor parameter is an extension! + explicit object_pool(const size_type next_size = 32) + :pool(sizeof(T), next_size) { } + + ~object_pool(); + + // Returns 0 if out-of-memory + element_type * malloc() + { return static_cast(pool::ordered_malloc()); } + void free(element_type * const chunk) + { pool::ordered_free(chunk); } + bool is_from(element_type * const chunk) const + { return pool::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 + + void destroy(element_type * const chunk) + { + chunk->~T(); + free(chunk); + } + + // These functions are extensions! + size_type get_next_size() const { return pool::get_next_size(); } + void set_next_size(const size_type x) { pool::set_next_size(x); } +}; + +template +object_pool::~object_pool() +{ + // handle trivial case + if (!list.valid()) + return; + + details::PODptr iter = list; + details::PODptr 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(static_cast(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 diff --git a/include/boost/pool/object_pool_fwd.hpp b/include/boost/pool/object_pool_fwd.hpp new file mode 100644 index 0000000..0d2845b --- /dev/null +++ b/include/boost/pool/object_pool_fwd.hpp @@ -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 + +namespace boost { + +template +class object_pool; + +} // namespace boost + +#endif diff --git a/include/boost/pool/pool.hpp b/include/boost/pool/pool.hpp new file mode 100644 index 0000000..6c5dc72 --- /dev/null +++ b/include/boost/pool/pool.hpp @@ -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 // for workarounds + +// std::less, std::less_equal, std::greater +#include +// new[], delete[], std::nothrow +#include +// std::size_t, std::ptrdiff_t +#include +// std::malloc, std::free +#include +// std::invalid_argument +#include + +#include + +// boost::details::pool::ct_lcm +#include +// boost::details::pool::lcm +#include +// boost::simple_segregated_storage +#include + +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(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 +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::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::value); + } + + size_type & next_size() const + { return *(reinterpret_cast(ptr_next_size())); } + char * & next_ptr() const + { return *(reinterpret_cast(ptr_next_ptr())); } + + PODptr next() const + { return PODptr(next_ptr(), next_size()); } + void next(const PODptr & arg) const + { + next_ptr() = arg.begin(); + next_size() = arg.total_size(); + } +}; + +} // namespace details + +template +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::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 list; + + simple_segregated_storage & store() { return *this; } + const simple_segregated_storage & 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 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()(static_cast(i), chunk) +// && std::less()(chunk, +// static_cast(i + sizeof_i))); + std::less_equal lt_eq; + std::less 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(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(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(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 +bool pool::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 ptr = list; + details::PODptr 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 next = ptr.next(); + + if (!all_chunks_free) + { + // Rush through all free chunks from this block + std::less 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 +bool pool::purge_memory() +{ + details::PODptr iter = list; + + if (!iter.valid()) + return false; + + do + { + // hold "next" pointer + const details::PODptr next = iter.next(); + + // delete the storage + UserAllocator::free(iter.begin()); + + // increment iter + iter = next; + } while (iter.valid()); + + list.invalidate(); + first = 0; + + return true; +} + +template +void * pool::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::value + sizeof(size_type); + char * const ptr = UserAllocator::malloc(POD_size); + if (ptr == 0) + return 0; + const details::PODptr 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 +void * pool::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::value + sizeof(size_type); + char * const ptr = UserAllocator::malloc(POD_size); + if (ptr == 0) + return 0; + const details::PODptr 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()(list.begin(), node.begin())) + { + node.next(list); + list = node; + } + else + { + details::PODptr 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()(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 +void * pool::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(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::value + sizeof(size_type); + char * const ptr = UserAllocator::malloc(POD_size); + if (ptr == 0) + return 0; + const details::PODptr 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()(list.begin(), node.begin())) + { + node.next(list); + list = node; + } + else + { + details::PODptr 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()(prev.next_ptr(), node.begin())) + break; + + prev = prev.next(); + } + + node.next(prev.next()); + prev.next(node); + } + + // and return it. + return node.begin(); +} + +template +details::PODptr::size_type> +pool::find_POD(void * const chunk) const +{ + // We have to find which storage this chunk is from. + details::PODptr iter = list; + while (iter.valid()) + { + if (is_from(chunk, iter.begin(), iter.element_size())) + return iter; + iter = iter.next(); + } + + return iter; +} + +} // namespace boost + +#endif diff --git a/include/boost/pool/pool_alloc.hpp b/include/boost/pool/pool_alloc.hpp new file mode 100644 index 0000000..43a4446 --- /dev/null +++ b/include/boost/pool/pool_alloc.hpp @@ -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 +// new, std::bad_alloc +#include + +#include + +// boost::singleton_pool +#include + +#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 +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::size_type size_type; + typedef typename pool::difference_type difference_type; + + template + struct rebind + { + typedef pool_allocator other; + }; + + public: + pool_allocator() { } + + // default copy constructor + + // default assignment operator + + // not explicit, mimicking std::allocator [20.4.1] + template + pool_allocator(const pool_allocator &) + { } + + // 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::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( + singleton_pool::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::ordered_free(ptr, n); + } +}; + +struct fast_pool_allocator_tag { }; + +template +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::size_type size_type; + typedef typename pool::difference_type difference_type; + + template + struct rebind + { + typedef fast_pool_allocator other; + }; + + public: + fast_pool_allocator() { } + + // default copy constructor + + // default assignment operator + + // not explicit, mimicking std::allocator [20.4.1] + template + fast_pool_allocator( + const fast_pool_allocator &) + { } + + // 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::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( + singleton_pool::malloc() ) : + static_cast( + singleton_pool::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( + singleton_pool::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::free(ptr); + else + singleton_pool::free(ptr, n); + } + static void deallocate(const pointer ptr) + { + singleton_pool::free(ptr); + } +}; + +} // namespace boost + +#undef BOOST_POOL_ALLOC_ALLOW_NULL_DEALLOCATE + +#endif diff --git a/include/boost/pool/pool_alloc_fwd.hpp b/include/boost/pool/pool_alloc_fwd.hpp new file mode 100644 index 0000000..82796ee --- /dev/null +++ b/include/boost/pool/pool_alloc_fwd.hpp @@ -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::default_user_allocator_new_delete fwd +#include + +namespace boost { + +struct pool_allocator_tag; + +template +class pool_allocator; + +struct fast_pool_allocator_tag; + +template +class fast_pool_allocator; + +} // namespace boost + +#endif diff --git a/include/boost/pool/pool_fwd.hpp b/include/boost/pool/pool_fwd.hpp new file mode 100644 index 0000000..2b220f6 --- /dev/null +++ b/include/boost/pool/pool_fwd.hpp @@ -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 +class pool; + +} // namespace boost + +#endif diff --git a/include/boost/pool/simple_segregated_storage.hpp b/include/boost/pool/simple_segregated_storage.hpp new file mode 100644 index 0000000..dc623da --- /dev/null +++ b/include/boost/pool/simple_segregated_storage.hpp @@ -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 + +#include + +namespace boost { + +template +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(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 +void * simple_segregated_storage::find_prev(void * const ptr) +{ + // Handle border case + if (first == 0 || std::greater()(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()(nextof(iter), ptr)) + return iter; + + iter = nextof(iter); + } +} + +template +void * simple_segregated_storage::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(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 +void * simple_segregated_storage::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(iter) + partition_size) + { + // next == 0 (end-of-list) or non-contiguous chunk found + start = iter; + return 0; + } + iter = next; + } + return iter; +} + +template +void * simple_segregated_storage::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 diff --git a/include/boost/pool/simple_segregated_storage_fwd.hpp b/include/boost/pool/simple_segregated_storage_fwd.hpp new file mode 100644 index 0000000..81f7916 --- /dev/null +++ b/include/boost/pool/simple_segregated_storage_fwd.hpp @@ -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 + +namespace boost { + +template +class simple_segregated_storage; + +} // namespace boost + +#endif diff --git a/include/boost/pool/singleton_pool.hpp b/include/boost/pool/singleton_pool.hpp new file mode 100644 index 0000000..99b33f0 --- /dev/null +++ b/include/boost/pool/singleton_pool.hpp @@ -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 +#include +// boost::details::pool::singleton_default +#include +// boost::details::pool::guard +#include + +namespace boost { + +// +// The singleton_pool class allows other pool interfaces for types of the same +// size to share the same pool +// +template +struct singleton_pool +{ + public: + typedef Tag tag; + typedef Mutex mutex; + typedef UserAllocator user_allocator; + typedef typename pool::size_type size_type; + typedef typename pool::difference_type difference_type; + + static const unsigned requested_size = RequestedSize; + static const unsigned next_size = NextSize; + + private: + struct pool_type: Mutex + { + pool p; + pool_type():p(RequestedSize, NextSize) { } + }; + + typedef details::pool::singleton_default singleton; + + singleton_pool(); + + public: + static void * malloc() + { + pool_type & p = singleton::instance(); + details::pool::guard g(p); + return p.p.malloc(); + } + static void * ordered_malloc() + { + pool_type & p = singleton::instance(); + details::pool::guard g(p); + return p.p.ordered_malloc(); + } + static void * ordered_malloc(const size_type n) + { + pool_type & p = singleton::instance(); + details::pool::guard g(p); + return p.p.ordered_malloc(n); + } + static bool is_from(void * const ptr) + { + pool_type & p = singleton::instance(); + details::pool::guard g(p); + return p.p.is_from(ptr); + } + static void free(void * const ptr) + { + pool_type & p = singleton::instance(); + details::pool::guard g(p); + p.p.free(ptr); + } + static void ordered_free(void * const ptr) + { + pool_type & p = singleton::instance(); + details::pool::guard 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 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 g(p); + p.p.ordered_free(ptr, n); + } + static bool release_memory() + { + pool_type & p = singleton::instance(); + details::pool::guard g(p); + return p.release_memory(); + } + static bool purge_memory() + { + pool_type & p = singleton::instance(); + details::pool::guard g(p); + return p.purge_memory(); + } +}; + +} // namespace boost + +#endif diff --git a/include/boost/pool/singleton_pool_fwd.hpp b/include/boost/pool/singleton_pool_fwd.hpp new file mode 100644 index 0000000..6bb3329 --- /dev/null +++ b/include/boost/pool/singleton_pool_fwd.hpp @@ -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::default_user_allocator_new_delete fwd +#include + +namespace boost { + +template +struct singleton_pool; + +} // namespace boost + +#endif diff --git a/test/sys_allocator.hpp b/test/sys_allocator.hpp new file mode 100644 index 0000000..1b41026 --- /dev/null +++ b/test/sys_allocator.hpp @@ -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 +#include +#include +#include + +template +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 + struct rebind + { + typedef malloc_allocator 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::max(); } + + bool operator==(const malloc_allocator &) const { return true; } + bool operator!=(const malloc_allocator &) const { return false; } + + malloc_allocator() { } + template + malloc_allocator(const malloc_allocator &) { } + + static void construct(const pointer p, const_reference t) + { new ((void *) p) T(t); } + static void destroy(const pointer p) + { p->~T(); } +}; + +template +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 + struct rebind + { + typedef new_delete_allocator 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::max(); } + + bool operator==(const new_delete_allocator &) const { return true; } + bool operator!=(const new_delete_allocator &) const { return false; } + + new_delete_allocator() { } + template + new_delete_allocator(const new_delete_allocator &) { } + + static void construct(const pointer p, const_reference t) + { new ((void *) p) T(t); } + static void destroy(const pointer p) + { p->~T(); } +}; + +#endif \ No newline at end of file diff --git a/test/test_pool_alloc.cpp b/test/test_pool_alloc.cpp new file mode 100644 index 0000000..deb69d0 --- /dev/null +++ b/test/test_pool_alloc.cpp @@ -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 +#include + +#include +#include +#include +#include +#include +#include +#include + +// 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 objs; + + public: + ~cdtor_checker() + { + // At end of program, print out memory leaks + // (assuming no static "tester"s) + for (std::set::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::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 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 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 pool; + std::vector 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 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 > 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 > 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 > 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 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::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 +struct TrackAlloc +{ + typedef typename UserAllocator::size_type size_type; + typedef typename UserAllocator::difference_type difference_type; + + static std::set 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 +std::set TrackAlloc::allocated_blocks; + +typedef TrackAlloc track_alloc; + +void test_mem_usage() +{ +#ifdef VERBOSE + std::cout << "Testing memory usage. . ." << std::endl; +#endif + + typedef boost::pool 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; +} + + diff --git a/test/time_pool_alloc.cpp b/test/time_pool_alloc.cpp new file mode 100644 index 0000000..b9c3360 --- /dev/null +++ b/test/time_pool_alloc.cpp @@ -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 +#include + +#include +#include +#include +#include + +#include +#include + +#include "sys_allocator.hpp" + +unsigned long num_ints; + +template +struct larger_structure +{ + char data[N]; +}; + +unsigned test_number; + +template +static void timing_test_alloc_larger() +{ + typedef boost::fast_pool_allocator, + boost::default_user_allocator_new_delete, + boost::details::pool::null_mutex> alloc; + typedef boost::fast_pool_allocator > alloc_sync; + + double end[1][6]; + std::clock_t start; + + start = std::clock(); + { + std::allocator > 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))); + } + 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; + } + 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)); + 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) << ":" << 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 alloc; + typedef boost::fast_pool_allocator alloc_sync; + + double end[2][6]; + std::clock_t start; + + int ** p = new int*[num_ints]; + + start = std::clock(); + { + std::allocator 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 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(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 alloc; + typedef boost::pool_allocator alloc_sync; + typedef boost::fast_pool_allocator fast_alloc; + typedef boost::fast_pool_allocator fast_alloc_sync; + + double end[3][5]; + std::clock_t start; + + start = std::clock(); + { + std::vector > 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 > 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 > 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 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 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, std::allocator > 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, malloc_allocator > 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, new_delete_allocator > 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, 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, 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 > 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 > 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 > 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 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 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; +} + +