1 ////////////////////////////////////////////////////////////////////////////////
2 // The Loki Library
3 // Copyright (c) 2001 by Andrei Alexandrescu
4 // This code accompanies the book:
5 // Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
6 // Patterns Applied". Copyright (c) 2001. Addison-Wesley.
7 // Permission to use, copy, modify, distribute and sell this software for any
8 // purpose is hereby granted without fee, provided that the above copyright
9 // notice appear in all copies and that both that copyright notice and this
10 // permission notice appear in supporting documentation.
11 // The author or Addison-Welsey Longman make no representations about the
12 // suitability of this software for any purpose. It is provided "as is"
13 // without express or implied warranty.
14 ////////////////////////////////////////////////////////////////////////////////
15
16 // Last update: June 20, 2001
17
18 #ifndef SMALLOBJ_INC_
19 #define SMALLOBJ_INC_
20
21 #include "Threads.h"
22 #include "Singleton.h"
23 #include <cstddef>
24 #include <vector>
25
26 #ifndef DEFAULT_CHUNK_SIZE
27 #define DEFAULT_CHUNK_SIZE 4096
28 #endif
29
30 #ifndef MAX_SMALL_OBJECT_SIZE
31 #define MAX_SMALL_OBJECT_SIZE 64
32 #endif
33
34 namespace Loki
35 {
36 ////////////////////////////////////////////////////////////////////////////////
37 // class FixedAllocator
38 // Offers services for allocating fixed-sized objects
39 ////////////////////////////////////////////////////////////////////////////////
40
41 class FixedAllocator
42 {
43 private:
44 struct Chunk
45 {
46 void Init(std::size_t blockSize, unsigned char blocks);
47 void* Allocate(std::size_t blockSize);
48 void Deallocate(void* p, std::size_t blockSize);
49 void Reset(std::size_t blockSize, unsigned char blocks);
50 void Release();
51 unsigned char* pData_;
52 unsigned char
53 firstAvailableBlock_,
54 blocksAvailable_;
55 };
56
57 // Internal functions
58 void DoDeallocate(void* p);
59 Chunk* VicinityFind(void* p);
60
61 // Data
62 std::size_t blockSize_;
63 unsigned char numBlocks_;
64 typedef std::vector<Chunk> Chunks;
65 Chunks chunks_;
66 Chunk* allocChunk_;
67 Chunk* deallocChunk_;
68 // For ensuring proper copy semantics
69 mutable const FixedAllocator* prev_;
70 mutable const FixedAllocator* next_;
71
72 public:
73 // Create a FixedAllocator able to manage blocks of 'blockSize' size
74 explicit FixedAllocator(std::size_t blockSize = 0);
75 FixedAllocator(const FixedAllocator&);
76 FixedAllocator& operator=(const FixedAllocator&);
77 ~FixedAllocator();
78
79 void Swap(FixedAllocator& rhs);
80
81 // Allocate a memory block
82 void* Allocate();
83 // Deallocate a memory block previously allocated with Allocate()
84 // (if that's not the case, the behavior is undefined)
85 void Deallocate(void* p);
86 // Returns the block size with which the FixedAllocator was initialized
87 std::size_t BlockSize() const
88 { return blockSize_; }
89 // Comparison operator for sorting
90 bool operator<(std::size_t rhs) const
91 { return BlockSize() < rhs; }
92 };
93
94 ////////////////////////////////////////////////////////////////////////////////
95 // class SmallObjAllocator
96 // Offers services for allocating small-sized objects
97 ////////////////////////////////////////////////////////////////////////////////
98
99 class SmallObjAllocator
100 {
101 public:
102 SmallObjAllocator(
103 std::size_t chunkSize,
104 std::size_t maxObjectSize);
105
106 void* Allocate(std::size_t numBytes);
107 void Deallocate(void* p, std::size_t size);
108
109 private:
110 SmallObjAllocator(const SmallObjAllocator&);
111 SmallObjAllocator& operator=(const SmallObjAllocator&);
112
113 typedef std::vector<FixedAllocator> Pool;
114 Pool pool_;
115 FixedAllocator* pLastAlloc_;
116 FixedAllocator* pLastDealloc_;
117 std::size_t chunkSize_;
118 std::size_t maxObjectSize_;
119 };
120
121 ////////////////////////////////////////////////////////////////////////////////
122 // class SmallObject
123 // Base class for polymorphic small objects, offers fast
124 // allocations/deallocations
125 ////////////////////////////////////////////////////////////////////////////////
126
127 template
128 <
129 template <class> class ThreadingModel = DEFAULT_THREADING,
130 std::size_t chunkSize = DEFAULT_CHUNK_SIZE,
131 std::size_t maxSmallObjectSize = MAX_SMALL_OBJECT_SIZE
132 >
133 class SmallObject : public ThreadingModel<
134 SmallObject<ThreadingModel, chunkSize, maxSmallObjectSize> >
135 {
136 typedef ThreadingModel< SmallObject<ThreadingModel,
137 chunkSize, maxSmallObjectSize> > MyThreadingModel;
138
139 struct MySmallObjAllocator : public SmallObjAllocator
140 {
141 MySmallObjAllocator()
142 : SmallObjAllocator(chunkSize, maxSmallObjectSize)
143 {}
144 };
145 // The typedef below would make things much simpler,
146 // but MWCW won't like it
147 // typedef SingletonHolder<MySmallObjAllocator/*, CreateStatic,
148 // DefaultLifetime, ThreadingModel*/> MyAllocator;
149
150 public:
151 static void* operator new(std::size_t size)
152 {
153 #if (MAX_SMALL_OBJECT_SIZE != 0) && (DEFAULT_CHUNK_SIZE != 0)
154 typename MyThreadingModel::Lock lock;
155 (void)lock; // get rid of warning
156
157 return SingletonHolder<MySmallObjAllocator, CreateStatic,
158 PhoenixSingleton>::Instance().Allocate(size);
159 #else
160 return ::operator new(size);
161 #endif
162 }
163 static void operator delete(void* p, std::size_t size)
164 {
165 #if (MAX_SMALL_OBJECT_SIZE != 0) && (DEFAULT_CHUNK_SIZE != 0)
166 typename MyThreadingModel::Lock lock;
167 (void)lock; // get rid of warning
168
169 SingletonHolder<MySmallObjAllocator, CreateStatic,
170 PhoenixSingleton>::Instance().Deallocate(p, size);
171 #else
172 ::operator delete(p, size);
173 #endif
174 }
175 virtual ~SmallObject() {}
176 };
177 } // namespace Loki
178
179 ////////////////////////////////////////////////////////////////////////////////
180 // Change log:
181 // June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
182 ////////////////////////////////////////////////////////////////////////////////
183
184 #endif // SMALLOBJ_INC_