1 /*
2  * Copyright 2012 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef GrMemoryPool_DEFINED
9 #define GrMemoryPool_DEFINED
10 
11 #include "GrTypes.h"
12 
13 /**
14  * Allocates memory in blocks and parcels out space in the blocks for allocation
15  * requests. It is optimized for allocate / release speed over memory
16  * effeciency. The interface is designed to be used to implement operator new
17  * and delete overrides. All allocations are expected to be released before the
18  * pool's destructor is called. Allocations will be 8-byte aligned.
19  */
20 class GrMemoryPool {
21 public:
22     /**
23      * Prealloc size is the amount of space to make available at pool creation
24      * time and keep around until pool destruction. The min alloc size is the
25      * smallest allowed size of additional allocations.
26      */
27     GrMemoryPool(size_t preallocSize, size_t minAllocSize);
28 
29     ~GrMemoryPool();
30 
31     /**
32      * Allocates memory. The memory must be freed with release().
33      */
34     void* allocate(size_t size);
35 
36     /**
37      * p must have been returned by allocate()
38      */
39     void release(void* p);
40 
41     /**
42      * Returns true if there are no unreleased allocations.
43      */
isEmpty()44     bool isEmpty() const { return fTail == fHead && !fHead->fLiveCount; }
45 
46     /**
47      * Returns the total allocated size of the GrMemoryPool minus any preallocated amount
48      */
size()49     size_t size() const { return fSize; }
50 
51 private:
52     struct BlockHeader;
53 
54     static BlockHeader* CreateBlock(size_t size);
55 
56     static void DeleteBlock(BlockHeader* block);
57 
58     void validate();
59 
60     struct BlockHeader {
61 #ifdef SK_DEBUG
62         uint32_t     fBlockSentinal;  ///< known value to check for bad back pointers to blocks
63 #endif
64         BlockHeader* fNext;      ///< doubly-linked list of blocks.
65         BlockHeader* fPrev;
66         int          fLiveCount; ///< number of outstanding allocations in the
67                                  ///< block.
68         intptr_t     fCurrPtr;   ///< ptr to the start of blocks free space.
69         intptr_t     fPrevPtr;   ///< ptr to the last allocation made
70         size_t       fFreeSize;  ///< amount of free space left in the block.
71         size_t       fSize;      ///< total allocated size of the block
72     };
73 
74     static const uint32_t kAssignedMarker = 0xCDCDCDCD;
75     static const uint32_t kFreedMarker    = 0xEFEFEFEF;
76 
77     struct AllocHeader {
78 #ifdef SK_DEBUG
79         uint32_t fSentinal;      ///< known value to check for memory stomping (e.g., (CD)*)
80 #endif
81         BlockHeader* fHeader;    ///< pointer back to the block header in which an alloc resides
82     };
83 
84     enum {
85         // We assume this alignment is good enough for everybody.
86         kAlignment    = 8,
87         kHeaderSize   = GR_CT_ALIGN_UP(sizeof(BlockHeader), kAlignment),
88         kPerAllocPad  = GR_CT_ALIGN_UP(sizeof(AllocHeader), kAlignment),
89     };
90     size_t                            fSize;
91     size_t                            fPreallocSize;
92     size_t                            fMinAllocSize;
93     BlockHeader*                      fHead;
94     BlockHeader*                      fTail;
95 #ifdef SK_DEBUG
96     int                               fAllocationCnt;
97     int                               fAllocBlockCnt;
98 #endif
99 };
100 
101 #endif
102