1 /*========================== begin_copyright_notice ============================
2 
3 Copyright (C) 2019-2021 Intel Corporation
4 
5 SPDX-License-Identifier: MIT
6 
7 ============================= end_copyright_notice ===========================*/
8 
9 #pragma once
10 
11 #include "Object.h"
12 #include "Threading.h"
13 
14 namespace iSTD
15 {
16 
17 /*****************************************************************************\
18 
19 Class:
20     CLinearAllocator
21 
22 Description:
23     Manages a memory buffer via linear allocation
24 
25 \*****************************************************************************/
26 template<class CAllocatorType>
27 class CLinearAllocator : public CObject<CAllocatorType>
28 {
29 public:
30 
31     CLinearAllocator( void* pBaseAddress, const DWORD size );
32     virtual ~CLinearAllocator( void );
33 
34     DWORD   GetAvailableSpace( void ) const;
35     DWORD   GetUsedSpace( void ) const;
36 
37     void*   GetSpace( const DWORD size );
38     void*   GetSpaceAligned( const DWORD size, const DWORD alignSize );
39 
40     bool    IsEmpty( void ) const;
41     bool    IsFull( void ) const;
42 
43     void    Align( const DWORD alignSize );
44 
45     void    PutSpace( const DWORD size );
46     void    PutAllSpace( void );
47 
48     void*   ReserveSpace( const DWORD size );
49 
50     virtual void    Resize( const DWORD size );
51 
52 protected:
53 
54     void*   m_pBaseAddress;
55     DWORD   m_Size;             // Total size of memory
56     DWORD   m_SizeUsed;         // Size of used memory
57     DWORD   m_SizeReserved;     // Size of reserved memory
58 
59     DECL_DEBUG_MUTEX( m_InstanceNotThreadSafe )
60 };
61 
62 /*****************************************************************************\
63 
64 Function:
65     CLinearAllocator Constructor
66 
67 Description:
68     Initializes internal data
69 
70 Input:
71     void* pBaseAddress
72     const DWORD size
73 
74 Output:
75     none
76 
77 \*****************************************************************************/
78 template<class CAllocatorType>
CLinearAllocator(void * pBaseAddress,const DWORD size)79 inline CLinearAllocator<CAllocatorType>::CLinearAllocator(
80     void* pBaseAddress,
81     const DWORD size )
82     : CObject<CAllocatorType>()
83 {
84     m_pBaseAddress = pBaseAddress;
85     m_Size = size;
86     m_SizeUsed = 0;
87     m_SizeReserved = 0;
88 
89     INIT_DEBUG_MUTEX( m_InstanceNotThreadSafe );
90 }
91 
92 /*****************************************************************************\
93 
94 Function:
95     CLinearAllocator Destructor
96 
97 Description:
98     Deletes internal data
99 
100 Input:
101     none
102 
103 Output:
104     none
105 
106 \*****************************************************************************/
107 template<class CAllocatorType>
~CLinearAllocator(void)108 inline CLinearAllocator<CAllocatorType>::~CLinearAllocator( void )
109 {
110     DELETE_DEBUG_MUTEX( m_InstanceNotThreadSafe );
111 }
112 
113 /*****************************************************************************\
114 
115 Function:
116     CLinearAllocator::GetAvailableSpace
117 
118 Description:
119     Gets the amount of space available in the buffer
120 
121 Input:
122     none
123 
124 Output:
125     DWORD - size in bytes
126 
127 \*****************************************************************************/
128 template<class CAllocatorType>
GetAvailableSpace(void)129 inline DWORD CLinearAllocator<CAllocatorType>::GetAvailableSpace( void ) const
130 {
131     const DWORD size = m_Size - GetUsedSpace();
132     return size;
133 }
134 
135 /*****************************************************************************\
136 
137 Function:
138     CLinearAllocator::GetUsedSpace
139 
140 Description:
141     Gets the amount of space used in the buffer
142 
143 Input:
144     none
145 
146 Output:
147     DWORD - size in bytes
148 
149 \*****************************************************************************/
150 template<class CAllocatorType>
GetUsedSpace(void)151 inline DWORD CLinearAllocator<CAllocatorType>::GetUsedSpace( void ) const
152 {
153     const DWORD size = m_SizeUsed + m_SizeReserved;
154     return size;
155 }
156 
157 /*****************************************************************************\
158 
159 Function:
160     CLinearAllocator::GetSpace
161 
162 Description:
163     Gets space from the top of the buffer
164 
165 Input:
166     const DWORD size - size in bytes
167 
168 Output:
169     void* - linear address of space
170 
171 \*****************************************************************************/
172 template<class CAllocatorType>
GetSpace(const DWORD size)173 inline void* CLinearAllocator<CAllocatorType>::GetSpace( const DWORD size )
174 {
175     ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe );
176     void* pAddress = NULL;
177 
178     if( GetAvailableSpace() >= size )
179     {
180         pAddress = (BYTE*)m_pBaseAddress + m_SizeUsed;
181         m_SizeUsed += size;
182     }
183 
184     RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe );
185     return pAddress;
186 }
187 
188 /*****************************************************************************\
189 
190 Function:
191     CLinearAllocator::GetSpaceAligned
192 
193 Description:
194     Gets space from the top of the buffer
195 
196 Input:
197     const DWORD size - size in bytes
198     const DWORD alignSize - alignment in bytes
199 
200 Output:
201     void* - linear address of space
202 
203 \*****************************************************************************/
204 template<class CAllocatorType>
GetSpaceAligned(const DWORD size,const DWORD alignSize)205 inline void* CLinearAllocator<CAllocatorType>::GetSpaceAligned(
206     const DWORD size,
207     const DWORD alignSize )
208 {
209     ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe );
210     void* pAddress = NULL;
211 
212     if( GetAvailableSpace() >= size )
213     {
214         // Determine the number of bytes required to
215         // align the allocation
216         const DWORD offset = GetAlignmentOffset(
217             (BYTE*)m_pBaseAddress + m_SizeUsed,
218             alignSize );
219 
220         if( offset )
221         {
222             if( ( GetAvailableSpace() >= offset ) &&
223                 ( GetAvailableSpace() >= offset + size ) )
224             {
225                 pAddress = (BYTE*)m_pBaseAddress + m_SizeUsed + offset;
226                 m_SizeUsed += size + offset;
227             }
228         }
229         else
230         {
231             pAddress = (BYTE*)m_pBaseAddress + m_SizeUsed;
232             m_SizeUsed += size;
233         }
234     }
235 
236     RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe );
237     return pAddress;
238 }
239 
240 /*****************************************************************************\
241 
242 Function:
243     CLinearAllocator::IsEmpty
244 
245 Description:
246     Determines if the buffer is empty
247 
248 Input:
249     void
250 
251 Output:
252     bool
253 
254 \*****************************************************************************/
255 template<class CAllocatorType>
IsEmpty(void)256 inline bool CLinearAllocator<CAllocatorType>::IsEmpty( void ) const
257 {
258     const bool isEmpty = ( m_SizeUsed == 0 ) && ( m_SizeReserved == 0 );
259     return isEmpty;
260 }
261 
262 /*****************************************************************************\
263 
264 Function:
265     CLinearAllocator::IsFull
266 
267 Description:
268     Determines if the buffer is full
269 
270 Input:
271     void
272 
273 Output:
274     bool
275 
276 \*****************************************************************************/
277 template<class CAllocatorType>
IsFull(void)278 inline bool CLinearAllocator<CAllocatorType>::IsFull( void ) const
279 {
280     const bool isFull = ( GetAvailableSpace() == 0 );
281     return isFull;
282 }
283 
284 /*****************************************************************************\
285 
286 Function:
287     CLinearAllocator::Align
288 
289 Description:
290     Aligns the buffer and pads with zeros
291 
292 Input:
293     const DWORD alignSize - alignment in bytes
294 
295 Output:
296     void
297 
298 \*****************************************************************************/
299 template<class CAllocatorType>
Align(const DWORD alignSize)300 inline void CLinearAllocator<CAllocatorType>::Align( const DWORD alignSize )
301 {
302     ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe );
303 
304     const DWORD offset = GetAlignmentOffset(
305         (BYTE*)m_pBaseAddress + m_SizeUsed,
306         alignSize );
307 
308     if( offset )
309     {
310         if( m_Size >= m_SizeUsed + offset )
311         {
312             m_SizeUsed += offset;
313         }
314     }
315 
316     RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe );
317 }
318 
319 /*****************************************************************************\
320 
321 Function:
322     CLinearAllocator::PutSpace
323 
324 Description:
325     Puts space back at the top of the buffer
326 
327 Input:
328     const DWORD size - size in bytes
329 
330 Output:
331     none
332 
333 \*****************************************************************************/
334 template<class CAllocatorType>
PutSpace(const DWORD size)335 inline void CLinearAllocator<CAllocatorType>::PutSpace( const DWORD size )
336 {
337     ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe );
338 
339     m_SizeUsed -= size;
340 
341     RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe );
342 }
343 
344 /*****************************************************************************\
345 
346 Function:
347     CLinearAllocator::PutAllSpace
348 
349 Description:
350     Puts all space back
351 
352 Input:
353     none
354 
355 Output:
356     none
357 
358 \*****************************************************************************/
359 template<class CAllocatorType>
PutAllSpace(void)360 inline void CLinearAllocator<CAllocatorType>::PutAllSpace( void )
361 {
362     ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe );
363 
364     m_SizeUsed = 0;
365     m_SizeReserved = 0;
366 
367     RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe );
368 }
369 
370 /*****************************************************************************\
371 
372 Function:
373     CLinearAllocator::ReserveSpace
374 
375 Description:
376     Reserves space at the bottom of the buffer
377 
378 Input:
379     const DWORD size - size in bytes
380 
381 Output:
382     void* - linear address of reserved space
383 
384 \*****************************************************************************/
385 template<class CAllocatorType>
ReserveSpace(const DWORD size)386 inline void* CLinearAllocator<CAllocatorType>::ReserveSpace( const DWORD size )
387 {
388     ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe );
389     void* pAddress = NULL;
390 
391     if( GetAvailableSpace() >= size )
392     {
393         pAddress = (BYTE*)m_pBaseAddress + m_Size -
394             ( m_SizeReserved + size );
395         m_SizeReserved += size;
396     }
397 
398     RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe );
399     return pAddress;
400 }
401 
402 /*****************************************************************************\
403 
404 Function:
405     CLinearAllocator::Resize
406 
407 Description:
408     Changes the size of the buffer
409 
410 Input:
411     const DWORD size - size in bytes
412 
413 Output:
414     none
415 
416 \*****************************************************************************/
417 template<class CAllocatorType>
Resize(const DWORD size)418 void CLinearAllocator<CAllocatorType>::Resize( const DWORD size )
419 {
420     ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe );
421 
422     m_Size = size;
423 
424     RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe );
425 }
426 
427 } // iSTD
428