HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Pool allocator for a scripting language parser

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
scriptingparserlanguageforpoolallocator

Problem

At the moment I'm writing a parser and interpreter for a custom scripting language, to learn more about the basic concepts involved and to get more familiar with tools like bison and flex.

The parsing process requires the allocation of a lot of small data structures to store intermediate language symbols and syntax tree nodes. The allocation pattern consists, in general, of a lot of sequential allocations with very few deallocations, and then everything gets freed at the end of the parsing, when the source code is done processing.

This seems like the perfect case for a pool allocator that can be drained with a single call at the end, to free all memory in one action. A reference on pool allocators.

My current implementation follows. I have tried to keep things as simple as possible. The pool maintains a linked list of small arrays. Objects reside inside these small arrays, so new allocations won't require copying data over to a new portion. There is still some fragmentation, but it is much lower if compared with raw new. Fragmentation can be further mitigated by choosing the best Granularity size for the small arrays to match the use case.

Any comments are appreciated.

``
#ifndef OBJECT_POOL_HPP
#define OBJECT_POOL_HPP

#include
#include
#include
#include

#include
#include

// ========================================================
// class ObjectPool:
// ========================================================

//
// Pool of fixed-size memory blocks (similar to a list of arrays).
//
// This pool allocator operates as a linked list of small arrays.
// Each array is a pool of blocks with the size of 'T' template parameter.
// Template parameter
Granularity defines the size in objects of type 'T'
// of such arrays.
//
//
allocate() will return an uninitialized memory block.
// The user is responsible for calling
construct() on it to run class
// constructors if necessary, and
destroy()` to call class destructor
// before deallocating the b

Solution

You may want to change

struct PoolBlock
{
    PoolBlock * next;
    PoolObj objects[Granularity];
};


by

struct PoolBlock
{
    PoolObj objects[Granularity];
    PoolBlock * next;
};


If the PoolBlock is aligned for PoolObj/T you will not have the 4/8 bytes of 'next' disturbing the harmony. At the back there will be no such issue.
Besides, it's easier to fit if your next step is using (lazily) mapped memory from the page pool to store a PoolBlock.

If you target high performance and the statistics are not really needed, you may want to get rid of them (i.e.: in a release build) as their relative cost is not negligible.

Code Snippets

struct PoolBlock
{
    PoolBlock * next;
    PoolObj objects[Granularity];
};
struct PoolBlock
{
    PoolObj objects[Granularity];
    PoolBlock * next;
};

Context

StackExchange Code Review Q#93772, answer score: 2

Revisions (0)

No revisions yet.