[dali_1.0.34] Merge branch 'tizen'
[platform/core/uifw/dali-core.git] / dali / internal / common / fixed-size-memory-pool.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/common/fixed-size-memory-pool.h>
20
21 // INTERNAL HEADERS
22 #include <dali/public-api/common/dali-common.h>
23
24 namespace Dali
25 {
26
27 namespace Internal
28 {
29
30 /**
31  * @brief Private implementation class
32  */
33 struct FixedSizeMemoryPool::Impl
34 {
35   /**
36    * @brief Struct to represent a block of memory from which allocations can be made.
37    *
38    * The block forms a linked list.
39    */
40   struct Block
41   {
42     void* blockMemory;      ///< The allocated memory from which allocations can be made
43     Block* nextBlock;       ///< The next block in the linked list
44
45     /**
46      * @brief Construct a new block with given size
47      *
48      * @param size The size of the memory block to allocate in bytes. Must be non-zero.
49      */
50     Block( SizeType size )
51     : nextBlock( NULL )
52     {
53       blockMemory = ::operator new( size );
54       DALI_ASSERT_ALWAYS( blockMemory && "Out of memory" );
55     }
56
57     /**
58      * @brief Destructor
59      */
60     ~Block()
61     {
62       ::operator delete( blockMemory );
63     }
64   };
65
66   /**
67    * @brief Constructor
68    */
69   Impl( SizeType fixedSize, SizeType initialCapacity, SizeType maximumBlockCapacity )
70   :  mFixedSize( fixedSize ),
71      mMemoryBlocks( initialCapacity * mFixedSize ),
72      mMaximumBlockCapacity( maximumBlockCapacity ),
73      mCurrentBlock( &mMemoryBlocks ),
74      mCurrentBlockCapacity( initialCapacity ),
75      mCurrentBlockSize( 0 ),
76      mDeletedObjects( NULL )
77   {
78     // We need enough room to store the deleted list in the data
79     DALI_ASSERT_DEBUG( mFixedSize >= sizeof( void* ) );
80   }
81
82   /**
83    * @brief Destructor
84    */
85   ~Impl()
86   {
87     // Clean up memory block linked list (mMemoryBlocks will be auto-destroyed by its destructor)
88     Block* block = mMemoryBlocks.nextBlock;
89     while( block )
90     {
91       Block* nextBlock = block->nextBlock;
92       delete block;
93       block = nextBlock;
94     }
95   }
96
97   /**
98    * @brief Allocate a new block for allocating memory from
99    */
100   void AllocateNewBlock()
101   {
102     // Double capacity for the new block
103     SizeType size = mCurrentBlockCapacity * 2;
104     if( size > mMaximumBlockCapacity || size < mCurrentBlockCapacity )    // Check for overflow of size type
105     {
106       size = mMaximumBlockCapacity;
107     }
108
109     mCurrentBlockCapacity = size;
110
111     // Allocate
112     Block* block = new Block( mCurrentBlockCapacity * mFixedSize );
113     mCurrentBlock->nextBlock = block;       // Add to end of linked list
114     mCurrentBlock = block;
115
116     mCurrentBlockSize = 0;
117   }
118
119   SizeType mFixedSize;                ///< The size of each allocation in bytes
120
121   Block mMemoryBlocks;                ///< Linked list of allocated memory blocks
122   SizeType mMaximumBlockCapacity;     ///< The maximum allowed capacity of allocations in a new memory block
123
124   Block* mCurrentBlock;               ///< Pointer to the active block
125   SizeType mCurrentBlockCapacity;     ///< The maximum number of allocations that can be allocated for the current block
126   SizeType mCurrentBlockSize;         ///< The number of allocations allocated to the current block
127
128   void* mDeletedObjects;              ///< Pointer to the head of the list of deleted objects. The addresses are stored in the allocated memory blocks.
129 };
130
131 FixedSizeMemoryPool::FixedSizeMemoryPool( SizeType fixedSize, SizeType initialCapacity, SizeType maximumBlockCapacity )
132 {
133   mImpl = new Impl( fixedSize, initialCapacity, maximumBlockCapacity );
134 }
135
136 FixedSizeMemoryPool::~FixedSizeMemoryPool()
137 {
138   delete mImpl;
139 }
140
141 void* FixedSizeMemoryPool::Allocate()
142 {
143   // First, recycle deleted objects
144   if( mImpl->mDeletedObjects )
145   {
146     void* recycled = mImpl->mDeletedObjects;
147     mImpl->mDeletedObjects = *( reinterpret_cast< void** >( mImpl->mDeletedObjects ) );  // Pop head off front of deleted objects list
148     return recycled;
149   }
150
151   // Check if current block is full
152   if( mImpl->mCurrentBlockSize >= mImpl->mCurrentBlockCapacity )
153   {
154     mImpl->AllocateNewBlock();
155   }
156
157   // Placement new the object in block memory
158   unsigned char* objectAddress = static_cast< unsigned char* >( mImpl->mCurrentBlock->blockMemory );
159   objectAddress += mImpl->mCurrentBlockSize * mImpl->mFixedSize;
160   mImpl->mCurrentBlockSize++;
161
162   return objectAddress;
163 }
164
165 void FixedSizeMemoryPool::Free( void* memory )
166 {
167   // Add memory to head of deleted objects list. Store next address in the same memory space as the old object.
168   *( reinterpret_cast< void** >( memory ) ) = mImpl->mDeletedObjects;
169   mImpl->mDeletedObjects = memory;
170 }
171
172 } // namespace Internal
173
174 } // namespace Dali