summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/web/json/json_batchallocator.h
blob: 0093b8cc41384c7281e17276424416d2c13b7115 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// Copyright 2007-2010 Baptiste Lepilleur
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE

#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED
# define JSONCPP_BATCHALLOCATOR_H_INCLUDED

# include <stdlib.h>
# include <assert.h>

# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION

namespace Json {
/* Fast memory allocator.
 *
 * This memory allocator allocates memory for a batch of object (specified by
 * the page size, the number of object in each page).
 *
 * It does not allow the destruction of a single object. All the allocated objects
 * can be destroyed at once. The memory can be either released or reused for future
 * allocation.
 *
 * The in-place new operator must be used to construct the object using the pointer
 * returned by allocate.
 */
template<typename AllocatedType
		,const unsigned int objectPerAllocation>
class BatchAllocator
{
public:
	typedef AllocatedType Type;

	BatchAllocator( unsigned int objectsPerPage = 255 )
		: freeHead_( 0 )
		, objectsPerPage_( objectsPerPage )
	{
//      printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() );
		assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space.
		assert( objectsPerPage >= 16 );
		batches_ = allocateBatch( 0 );   // allocated a dummy page
		currentBatch_ = batches_;
	}

	~BatchAllocator()
	{
		for ( BatchInfo *batch = batches_; batch;  )
		{
			BatchInfo *nextBatch = batch->next_;
			free( batch );
			batch = nextBatch;
		}
	}

	/// allocate space for an array of objectPerAllocation object.
	/// @warning it is the responsability of the caller to call objects constructors.
	AllocatedType *allocate()
	{
		if ( freeHead_ ) // returns node from free list.
		{
			AllocatedType *object = freeHead_;
			freeHead_ = *(AllocatedType **)object;
			return object;
		}
		if ( currentBatch_->used_ == currentBatch_->end_ )
		{
			currentBatch_ = currentBatch_->next_;
			while ( currentBatch_  &&  currentBatch_->used_ == currentBatch_->end_ )
			currentBatch_ = currentBatch_->next_;

			if ( !currentBatch_  ) // no free batch found, allocate a new one
			{
			currentBatch_ = allocateBatch( objectsPerPage_ );
			currentBatch_->next_ = batches_; // insert at the head of the list
			batches_ = currentBatch_;
			}
		}
		AllocatedType *allocated = currentBatch_->used_;
		currentBatch_->used_ += objectPerAllocation;
		return allocated;
	}

	/// Release the object.
	/// @warning it is the responsability of the caller to actually destruct the object.
	void release( AllocatedType *object )
	{
		assert( object != 0 );
		*(AllocatedType **)object = freeHead_;
		freeHead_ = object;
	}

private:
	struct BatchInfo
	{
		BatchInfo *next_;
		AllocatedType *used_;
		AllocatedType *end_;
		AllocatedType buffer_[objectPerAllocation];
	};

	// disabled copy constructor and assignement operator.
	BatchAllocator( const BatchAllocator & );
	void operator =( const BatchAllocator &);

	static BatchInfo *allocateBatch( unsigned int objectsPerPage )
	{
		const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation
								+ sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;
		BatchInfo *batch = static_cast<BatchInfo*>( malloc( mallocSize ) );
		batch->next_ = 0;
		batch->used_ = batch->buffer_;
		batch->end_ = batch->buffer_ + objectsPerPage;
		return batch;
	}

	BatchInfo *batches_;
	BatchInfo *currentBatch_;
	/// Head of a single linked list within the allocated space of freeed object
	AllocatedType *freeHead_;
	unsigned int objectsPerPage_;
};


} // namespace Json

# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION

#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED