ian@0
|
1 // Copyright 2007-2010 Baptiste Lepilleur
|
ian@0
|
2 // Distributed under MIT license, or public domain if desired and
|
ian@0
|
3 // recognized in your jurisdiction.
|
ian@0
|
4 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
ian@0
|
5
|
ian@0
|
6 #ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
ian@0
|
7 # define JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
ian@0
|
8
|
ian@0
|
9 # include <stdlib.h>
|
ian@0
|
10 # include <assert.h>
|
ian@0
|
11
|
ian@0
|
12 # ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
ian@0
|
13
|
ian@0
|
14 namespace Json {
|
ian@0
|
15
|
ian@0
|
16 /* Fast memory allocator.
|
ian@0
|
17 *
|
ian@0
|
18 * This memory allocator allocates memory for a batch of object (specified by
|
ian@0
|
19 * the page size, the number of object in each page).
|
ian@0
|
20 *
|
ian@0
|
21 * It does not allow the destruction of a single object. All the allocated objects
|
ian@0
|
22 * can be destroyed at once. The memory can be either released or reused for future
|
ian@0
|
23 * allocation.
|
ian@0
|
24 *
|
ian@0
|
25 * The in-place new operator must be used to construct the object using the pointer
|
ian@0
|
26 * returned by allocate.
|
ian@0
|
27 */
|
ian@0
|
28 template<typename AllocatedType
|
ian@0
|
29 ,const unsigned int objectPerAllocation>
|
ian@0
|
30 class BatchAllocator
|
ian@0
|
31 {
|
ian@0
|
32 public:
|
ian@0
|
33 BatchAllocator( unsigned int objectsPerPage = 255 )
|
ian@0
|
34 : freeHead_( 0 )
|
ian@0
|
35 , objectsPerPage_( objectsPerPage )
|
ian@0
|
36 {
|
ian@0
|
37 // printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() );
|
ian@0
|
38 assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space.
|
ian@0
|
39 assert( objectsPerPage >= 16 );
|
ian@0
|
40 batches_ = allocateBatch( 0 ); // allocated a dummy page
|
ian@0
|
41 currentBatch_ = batches_;
|
ian@0
|
42 }
|
ian@0
|
43
|
ian@0
|
44 ~BatchAllocator()
|
ian@0
|
45 {
|
ian@0
|
46 for ( BatchInfo *batch = batches_; batch; )
|
ian@0
|
47 {
|
ian@0
|
48 BatchInfo *nextBatch = batch->next_;
|
ian@0
|
49 free( batch );
|
ian@0
|
50 batch = nextBatch;
|
ian@0
|
51 }
|
ian@0
|
52 }
|
ian@0
|
53
|
ian@0
|
54 /// allocate space for an array of objectPerAllocation object.
|
ian@0
|
55 /// @warning it is the responsability of the caller to call objects constructors.
|
ian@0
|
56 AllocatedType *allocate()
|
ian@0
|
57 {
|
ian@0
|
58 if ( freeHead_ ) // returns node from free list.
|
ian@0
|
59 {
|
ian@0
|
60 AllocatedType *object = freeHead_;
|
ian@0
|
61 freeHead_ = *(AllocatedType **)object;
|
ian@0
|
62 return object;
|
ian@0
|
63 }
|
ian@0
|
64 if ( currentBatch_->used_ == currentBatch_->end_ )
|
ian@0
|
65 {
|
ian@0
|
66 currentBatch_ = currentBatch_->next_;
|
ian@0
|
67 while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ )
|
ian@0
|
68 currentBatch_ = currentBatch_->next_;
|
ian@0
|
69
|
ian@0
|
70 if ( !currentBatch_ ) // no free batch found, allocate a new one
|
ian@0
|
71 {
|
ian@0
|
72 currentBatch_ = allocateBatch( objectsPerPage_ );
|
ian@0
|
73 currentBatch_->next_ = batches_; // insert at the head of the list
|
ian@0
|
74 batches_ = currentBatch_;
|
ian@0
|
75 }
|
ian@0
|
76 }
|
ian@0
|
77 AllocatedType *allocated = currentBatch_->used_;
|
ian@0
|
78 currentBatch_->used_ += objectPerAllocation;
|
ian@0
|
79 return allocated;
|
ian@0
|
80 }
|
ian@0
|
81
|
ian@0
|
82 /// Release the object.
|
ian@0
|
83 /// @warning it is the responsability of the caller to actually destruct the object.
|
ian@0
|
84 void release( AllocatedType *object )
|
ian@0
|
85 {
|
ian@0
|
86 assert( object != 0 );
|
ian@0
|
87 *(AllocatedType **)object = freeHead_;
|
ian@0
|
88 freeHead_ = object;
|
ian@0
|
89 }
|
ian@0
|
90
|
ian@0
|
91 private:
|
ian@0
|
92 struct BatchInfo
|
ian@0
|
93 {
|
ian@0
|
94 BatchInfo *next_;
|
ian@0
|
95 AllocatedType *used_;
|
ian@0
|
96 AllocatedType *end_;
|
ian@0
|
97 AllocatedType buffer_[objectPerAllocation];
|
ian@0
|
98 };
|
ian@0
|
99
|
ian@0
|
100 // disabled copy constructor and assignement operator.
|
ian@0
|
101 BatchAllocator( const BatchAllocator & );
|
ian@0
|
102 void operator =( const BatchAllocator &);
|
ian@0
|
103
|
ian@0
|
104 static BatchInfo *allocateBatch( unsigned int objectsPerPage )
|
ian@0
|
105 {
|
ian@0
|
106 const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation
|
ian@0
|
107 + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;
|
ian@0
|
108 BatchInfo *batch = static_cast<BatchInfo*>( malloc( mallocSize ) );
|
ian@0
|
109 batch->next_ = 0;
|
ian@0
|
110 batch->used_ = batch->buffer_;
|
ian@0
|
111 batch->end_ = batch->buffer_ + objectsPerPage;
|
ian@0
|
112 return batch;
|
ian@0
|
113 }
|
ian@0
|
114
|
ian@0
|
115 BatchInfo *batches_;
|
ian@0
|
116 BatchInfo *currentBatch_;
|
ian@0
|
117 /// Head of a single linked list within the allocated space of freeed object
|
ian@0
|
118 AllocatedType *freeHead_;
|
ian@0
|
119 unsigned int objectsPerPage_;
|
ian@0
|
120 };
|
ian@0
|
121
|
ian@0
|
122
|
ian@0
|
123 } // namespace Json
|
ian@0
|
124
|
ian@0
|
125 # endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION
|
ian@0
|
126
|
ian@0
|
127 #endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED
|