# 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. 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.
3. 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.

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.