]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
1 | /* |
2 | * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | ||
25 | // | |
26 | // alloc - abstract malloc-like allocator abstraction | |
27 | // | |
28 | #ifndef _H_ALLOC | |
29 | #define _H_ALLOC | |
30 | ||
31 | #include <security_utilities/utilities.h> | |
32 | #include <cstring> | |
33 | ||
34 | namespace Security | |
35 | { | |
36 | ||
37 | ||
38 | // | |
39 | // An abstract allocator superclass, based on the simple malloc/realloc/free paradigm | |
40 | // that CDSA loves so much. If you have an allocation strategy and want objects | |
41 | // to be allocated through it, inherit from this. | |
42 | // | |
43 | class Allocator { | |
44 | public: | |
45 | virtual ~Allocator(); | |
46 | virtual void *malloc(size_t) throw(std::bad_alloc) = 0; | |
47 | virtual void free(void *) throw() = 0; | |
48 | virtual void *realloc(void *, size_t) throw(std::bad_alloc) = 0; | |
49 | ||
50 | // | |
51 | // Template versions for added expressiveness. | |
52 | // Note that the integers are element counts, not byte sizes. | |
53 | // | |
54 | template <class T> T *alloc() throw(std::bad_alloc) | |
55 | { return reinterpret_cast<T *>(malloc(sizeof(T))); } | |
56 | ||
57 | template <class T> T *alloc(UInt32 count) throw(std::bad_alloc) | |
58 | { return reinterpret_cast<T *>(malloc(sizeof(T) * count)); } | |
59 | ||
60 | template <class T> T *alloc(T *old, UInt32 count) throw(std::bad_alloc) | |
61 | { return reinterpret_cast<T *>(realloc(old, sizeof(T) * count)); } | |
62 | ||
63 | ||
64 | // | |
65 | // Happier malloc/realloc for any type. Note that these still have | |
66 | // the original (byte-sized) argument profile. | |
67 | // | |
68 | template <class T> T *malloc(size_t size) throw(std::bad_alloc) | |
69 | { return reinterpret_cast<T *>(malloc(size)); } | |
70 | ||
71 | template <class T> T *realloc(void *addr, size_t size) throw(std::bad_alloc) | |
72 | { return reinterpret_cast<T *>(realloc(addr, size)); } | |
73 | ||
74 | // All right, if you *really* have to have calloc... | |
75 | void *calloc(size_t size, unsigned int count) throw(std::bad_alloc) | |
76 | { | |
77 | void *addr = malloc(size * count); | |
78 | memset(addr, 0, size * count); | |
79 | return addr; | |
80 | } | |
81 | ||
82 | // compare Allocators for identity | |
83 | virtual bool operator == (const Allocator &alloc) const throw(); | |
84 | ||
85 | public: | |
86 | // allocator chooser options | |
87 | enum { | |
88 | normal = 0x0000, | |
89 | sensitive = 0x0001 | |
90 | }; | |
91 | ||
92 | static Allocator &standard(UInt32 request = normal); | |
93 | }; | |
94 | ||
95 | ||
96 | // | |
97 | // You'd think that this is operator delete(const T *, Allocator &), but you'd | |
98 | // be wrong. Specialized operator delete is only called during constructor cleanup. | |
99 | // Use this to cleanly destroy things. | |
100 | // | |
101 | template <class T> | |
102 | inline void destroy(T *obj, Allocator &alloc) throw() | |
103 | { | |
104 | obj->~T(); | |
105 | alloc.free(obj); | |
106 | } | |
107 | ||
108 | // untyped (release memory only, no destructor call) | |
109 | inline void destroy(void *obj, Allocator &alloc) throw() | |
110 | { | |
111 | alloc.free(obj); | |
112 | } | |
113 | ||
114 | ||
115 | // | |
116 | // A mixin class to automagically manage your allocator. | |
117 | // To allow allocation (of your object) from any instance of Allocator, | |
118 | // inherit from CssmHeap. Your users can then create heap instances of your thing by | |
119 | // new (an-allocator) YourClass(...) | |
120 | // or (still) | |
121 | // new YourClass(...) | |
122 | // for the default allocation source. The beauty is that when someone does a | |
123 | // delete pointer-to-your-instance | |
124 | // then the magic fairies will find the allocator that created the object and ask it | |
125 | // to free the memory (by calling its free() method). | |
126 | // The price of all that glory is memory overhead - typically one pointer per object. | |
127 | // | |
128 | class CssmHeap { | |
129 | public: | |
130 | void *operator new (size_t size, Allocator *alloc = NULL) throw(std::bad_alloc); | |
131 | void operator delete (void *addr, size_t size) throw(); | |
132 | void operator delete (void *addr, size_t size, Allocator *alloc) throw(); | |
133 | }; | |
134 | ||
135 | ||
136 | // | |
137 | // Here is a version of auto_ptr that works with Allocators. It is designed | |
138 | // to be pretty much a drop-in replacement. It requires an allocator as a constructor | |
139 | // argument, of course. | |
140 | // Note that CssmAutoPtr<void> is perfectly valid, unlike its auto_ptr look-alike. | |
141 | // You can't dereference it, naturally. | |
142 | // | |
143 | template <class T> | |
144 | class CssmAutoPtr { | |
145 | public: | |
146 | Allocator &allocator; | |
147 | ||
148 | CssmAutoPtr(Allocator &alloc = Allocator::standard()) | |
149 | : allocator(alloc), mine(NULL) { } | |
150 | CssmAutoPtr(Allocator &alloc, T *p) | |
151 | : allocator(alloc), mine(p) { } | |
152 | CssmAutoPtr(T *p) | |
153 | : allocator(Allocator::standard()), mine(p) { } | |
154 | template <class T1> CssmAutoPtr(CssmAutoPtr<T1> &src) | |
155 | : allocator(src.allocator), mine(src.release()) { } | |
156 | template <class T1> CssmAutoPtr(Allocator &alloc, CssmAutoPtr<T1> &src) | |
157 | : allocator(alloc), mine(src.release()) { assert(allocator == src.allocator); } | |
158 | ||
159 | ~CssmAutoPtr() { allocator.free(mine); } | |
160 | ||
161 | T *get() const throw() { return mine; } | |
162 | T *release() { T *result = mine; mine = NULL; return result; } | |
163 | void reset() { allocator.free(mine); mine = NULL; } | |
164 | ||
165 | operator T * () const { return mine; } | |
166 | T *operator -> () const { return mine; } | |
167 | T &operator * () const { assert(mine); return *mine; } | |
168 | ||
169 | private: | |
170 | T *mine; | |
171 | }; | |
172 | ||
173 | // specialization for void (i.e. void *), omitting the troublesome dereferencing ops. | |
174 | template <> | |
175 | class CssmAutoPtr<void> { | |
176 | public: | |
177 | Allocator &allocator; | |
178 | ||
179 | CssmAutoPtr(Allocator &alloc) : allocator(alloc), mine(NULL) { } | |
180 | CssmAutoPtr(Allocator &alloc, void *p) : allocator(alloc), mine(p) { } | |
181 | template <class T1> CssmAutoPtr(CssmAutoPtr<T1> &src) | |
182 | : allocator(src.allocator), mine(src.release()) { } | |
183 | template <class T1> CssmAutoPtr(Allocator &alloc, CssmAutoPtr<T1> &src) | |
184 | : allocator(alloc), mine(src.release()) { assert(allocator == src.allocator); } | |
185 | ||
186 | ~CssmAutoPtr() { destroy(mine, allocator); } | |
187 | ||
188 | void *get() throw() { return mine; } | |
189 | void *release() { void *result = mine; mine = NULL; return result; } | |
190 | void reset() { allocator.free(mine); mine = NULL; } | |
191 | ||
192 | private: | |
193 | void *mine; | |
194 | }; | |
195 | ||
196 | ||
197 | // | |
198 | // Convenience forms of CssmAutoPtr that automatically make their (initial) object. | |
199 | // | |
200 | template <class T> | |
201 | class CssmNewAutoPtr : public CssmAutoPtr<T> { | |
202 | public: | |
203 | CssmNewAutoPtr(Allocator &alloc = Allocator::standard()) | |
204 | : CssmAutoPtr<T>(alloc, new(alloc) T) { } | |
205 | ||
206 | template <class A1> | |
207 | CssmNewAutoPtr(Allocator &alloc, A1 &arg1) : CssmAutoPtr<T>(alloc, new(alloc) T(arg1)) { } | |
208 | template <class A1> | |
209 | CssmNewAutoPtr(Allocator &alloc, const A1 &arg1) | |
210 | : CssmAutoPtr<T>(alloc, new(alloc) T(arg1)) { } | |
211 | ||
212 | template <class A1, class A2> | |
213 | CssmNewAutoPtr(Allocator &alloc, A1 &arg1, A2 &arg2) | |
214 | : CssmAutoPtr<T>(alloc, new(alloc) T(arg1, arg2)) { } | |
215 | template <class A1, class A2> | |
216 | CssmNewAutoPtr(Allocator &alloc, const A1 &arg1, A2 &arg2) | |
217 | : CssmAutoPtr<T>(alloc, new(alloc) T(arg1, arg2)) { } | |
218 | template <class A1, class A2> | |
219 | CssmNewAutoPtr(Allocator &alloc, A1 &arg1, const A2 &arg2) | |
220 | : CssmAutoPtr<T>(alloc, new(alloc) T(arg1, arg2)) { } | |
221 | template <class A1, class A2> | |
222 | CssmNewAutoPtr(Allocator &alloc, const A1 &arg1, const A2 &arg2) | |
223 | : CssmAutoPtr<T>(alloc, new(alloc) T(arg1, arg2)) { } | |
224 | }; | |
225 | ||
226 | ||
227 | } // end namespace Security | |
228 | ||
229 | ||
230 | // | |
231 | // Global C++ allocation hooks to use Allocators (global namespace) | |
232 | // | |
233 | inline void *operator new (size_t size, Allocator &allocator) throw (std::bad_alloc) | |
234 | { return allocator.malloc(size); } | |
235 | ||
236 | inline void *operator new[] (size_t size, Allocator &allocator) throw (std::bad_alloc) | |
237 | { return allocator.malloc(size); } | |
238 | ||
239 | ||
240 | #endif //_H_ALLOC |