]>
Commit | Line | Data |
---|---|---|
9ce05555 | 1 | /* |
d8925383 | 2 | * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. |
9ce05555 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
9ce05555 A |
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 | /* CFRuntime.h | |
d8925383 | 24 | Copyright (c) 1999-2005, Apple, Inc. All rights reserved. |
9ce05555 A |
25 | */ |
26 | ||
27 | #if !defined(__COREFOUNDATION_CFRUNTIME__) | |
28 | #define __COREFOUNDATION_CFRUNTIME__ 1 | |
29 | ||
30 | #include <CoreFoundation/CFBase.h> | |
31 | #include <CoreFoundation/CFDictionary.h> | |
32 | ||
33 | #if defined(__cplusplus) | |
34 | extern "C" { | |
35 | #endif | |
36 | ||
d8925383 A |
37 | // GC: until we link against ObjC must use indirect functions. Overridden in CFSetupFoundationBridging |
38 | extern bool kCFUseCollectableAllocator; | |
39 | extern bool (*__CFObjCIsCollectable)(void *); | |
40 | extern const void* (*__CFObjCAssignIvar)(const void *value, const void *base, const void **slot); | |
41 | extern const void* (*__CFObjCStrongAssign)(const void *value, const void **slot); | |
42 | extern void* (*__CFObjCMemmoveCollectable)(void *dest, const void *src, unsigned); | |
43 | extern void (*__CFObjCWriteBarrierRange)(void *, unsigned); | |
44 | ||
45 | // GC: primitives. | |
46 | // is GC on? | |
47 | #define CF_USING_COLLECTABLE_MEMORY (kCFUseCollectableAllocator) | |
48 | // is GC on and is this the GC allocator? | |
49 | #define CF_IS_COLLECTABLE_ALLOCATOR(allocator) (CF_USING_COLLECTABLE_MEMORY && (NULL == (allocator) || kCFAllocatorSystemDefault == (allocator))) | |
50 | // is this allocated by the collector? | |
51 | #define CF_IS_COLLECTABLE(obj) (__CFObjCIsCollectable ? __CFObjCIsCollectable((void*)obj) : false) | |
52 | ||
53 | // XXX_PCB for generational GC support. | |
54 | ||
55 | CF_INLINE const void* __CFAssignIvar(CFAllocatorRef allocator, const void *rvalue, const void *base, const void **lvalue) { | |
56 | if (rvalue && CF_IS_COLLECTABLE_ALLOCATOR(allocator)) | |
57 | return __CFObjCAssignIvar(rvalue, base, lvalue); | |
58 | else | |
59 | return (*lvalue = rvalue); | |
60 | } | |
61 | ||
62 | CF_INLINE const void* __CFStrongAssign(CFAllocatorRef allocator, const void *rvalue, const void **lvalue) { | |
63 | if (rvalue && CF_IS_COLLECTABLE_ALLOCATOR(allocator)) | |
64 | return __CFObjCStrongAssign(rvalue, lvalue); | |
65 | else | |
66 | return (*lvalue = rvalue); | |
67 | } | |
68 | ||
69 | // Use this form when the base pointer to the object is known. | |
70 | #define CF_WRITE_BARRIER_BASE_ASSIGN(allocator, base, lvalue, rvalue) __CFAssignIvar(allocator, (const void*)rvalue, (const void*)base, (const void**)&(lvalue)) | |
71 | ||
72 | // Use this form when the base pointer to the object isn't known. | |
73 | #define CF_WRITE_BARRIER_ASSIGN(allocator, lvalue, rvalue) __CFStrongAssign(allocator, (const void*)rvalue, (const void**)&(lvalue)) | |
74 | ||
75 | // Write-barrier memory move. | |
76 | #define CF_WRITE_BARRIER_MEMMOVE(dst, src, size) __CFObjCMemmoveCollectable(dst, src, size) | |
77 | ||
78 | // Used by frameworks to assert they "KNOW WHAT THEY'RE DOING under GC." | |
79 | CF_EXPORT CFAllocatorRef _CFAllocatorCreateGC(CFAllocatorRef allocator, CFAllocatorContext *context); | |
80 | ||
81 | // Zero-retain count CFAllocator functions, i.e. memory that will be collected, no dealloc necessary | |
82 | CF_EXPORT void *_CFAllocatorAllocateGC(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint); | |
83 | CF_EXPORT void *_CFAllocatorReallocateGC(CFAllocatorRef allocator, void *ptr, CFIndex newsize, CFOptionFlags hint); | |
84 | CF_EXPORT void _CFAllocatorDeallocateGC(CFAllocatorRef allocator, void *ptr); | |
85 | ||
9ce05555 | 86 | enum { |
d8925383 A |
87 | _kCFRuntimeNotATypeID = 0, |
88 | _kCFRuntimeScannedObject = (1 << 0) | |
9ce05555 A |
89 | }; |
90 | ||
91 | typedef struct __CFRuntimeClass { // Version 0 struct | |
92 | CFIndex version; | |
93 | const char *className; | |
94 | void (*init)(CFTypeRef cf); | |
95 | CFTypeRef (*copy)(CFAllocatorRef allocator, CFTypeRef cf); | |
96 | #if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED | |
97 | void (*finalize)(CFTypeRef cf); | |
98 | #else | |
99 | void (*dealloc)(CFTypeRef cf); | |
100 | #endif | |
101 | Boolean (*equal)(CFTypeRef cf1, CFTypeRef cf2); | |
102 | CFHashCode (*hash)(CFTypeRef cf); | |
103 | CFStringRef (*copyFormattingDesc)(CFTypeRef cf, CFDictionaryRef formatOptions); // str with retain | |
104 | CFStringRef (*copyDebugDesc)(CFTypeRef cf); // str with retain | |
105 | } CFRuntimeClass; | |
106 | ||
107 | /* Note that CF runtime class registration and unregistration is not currently | |
108 | * thread-safe, which should not currently be a problem, as long as unregistration | |
109 | * is done only when valid to do so. | |
110 | */ | |
111 | ||
112 | CF_EXPORT CFTypeID _CFRuntimeRegisterClass(const CFRuntimeClass * const cls); | |
113 | /* Registers a new class with the CF runtime. Pass in a | |
114 | * pointer to a CFRuntimeClass structure. The pointer is | |
115 | * remembered by the CF runtime -- the structure is NOT | |
116 | * copied. | |
117 | * | |
118 | * - version field must be zero currently. | |
119 | * - className field points to a null-terminated C string | |
120 | * containing only ASCII (0 - 127) characters; this field | |
121 | * may NOT be NULL. | |
122 | * - init field points to a function which classes can use to | |
123 | * apply some generic initialization to instances as they | |
124 | * are created; this function is called by both | |
125 | * _CFRuntimeCreateInstance and _CFRuntimeInitInstance; if | |
126 | * this field is NULL, no function is called; the instance | |
127 | * has been initialized enough that the polymorphic funcs | |
128 | * CFGetTypeID(), CFRetain(), CFRelease(), CFGetRetainCount(), | |
129 | * and CFGetAllocator() are valid on it when the init | |
130 | * function if any is called. | |
131 | * - finalize field points to a function which destroys an | |
132 | * instance when the retain count has fallen to zero; if | |
133 | * this is NULL, finalization does nothing. Note that if | |
134 | * the class-specific functions which create or initialize | |
135 | * instances more fully decide that a half-initialized | |
136 | * instance must be destroyed, the finalize function for | |
137 | * that class has to be able to deal with half-initialized | |
138 | * instances. The finalize function should NOT destroy the | |
139 | * memory for the instance itself; that is done by the | |
140 | * CF runtime after this finalize callout returns. | |
141 | * - equal field points to an equality-testing function; this | |
142 | * field may be NULL, in which case only pointer/reference | |
143 | * equality is performed on instances of this class. | |
144 | * Pointer equality is tested, and the type IDs are checked | |
145 | * for equality, before this function is called (so, the | |
146 | * two instances are not pointer-equal but are of the same | |
147 | * class before this function is called). | |
148 | * NOTE: the equal function must implement an immutable | |
149 | * equality relation, satisfying the reflexive, symmetric, | |
150 | * and transitive properties, and remains the same across | |
151 | * time and immutable operations (that is, if equal(A,B) at | |
152 | * some point, then later equal(A,B) provided neither | |
153 | * A or B has been mutated). | |
154 | * - hash field points to a hash-code-computing function for | |
155 | * instances of this class; this field may be NULL in which | |
156 | * case the pointer value of an instance is converted into | |
157 | * a hash. | |
158 | * NOTE: the hash function and equal function must satisfy | |
159 | * the relationship "equal(A,B) implies hash(A) == hash(B)"; | |
160 | * that is, if two instances are equal, their hash codes must | |
161 | * be equal too. (However, the converse is not true!) | |
162 | * - copyFormattingDesc field points to a function returning a | |
163 | * CFStringRef with a human-readable description of the | |
164 | * instance; if this is NULL, the type does not have special | |
165 | * human-readable string-formats. | |
166 | * - copyDebugDesc field points to a function returning a | |
167 | * CFStringRef with a debugging description of the instance; | |
168 | * if this is NULL, a simple description is generated. | |
169 | * | |
170 | * This function returns _kCFRuntimeNotATypeID on failure, or | |
171 | * on success, returns the CFTypeID for the new class. This | |
172 | * CFTypeID is what the class uses to allocate or initialize | |
173 | * instances of the class. It is also returned from the | |
174 | * conventional *GetTypeID() function, which returns the | |
175 | * class's CFTypeID so that clients can compare the | |
176 | * CFTypeID of instances with that of a class. | |
177 | * | |
178 | * The function to compute a human-readable string is very | |
179 | * optional, and is really only interesting for classes, | |
180 | * like strings or numbers, where it makes sense to format | |
181 | * the instance using just its contents. | |
182 | */ | |
183 | ||
184 | CF_EXPORT const CFRuntimeClass * _CFRuntimeGetClassWithTypeID(CFTypeID typeID); | |
185 | /* Returns the pointer to the CFRuntimeClass which was | |
186 | * assigned the specified CFTypeID. | |
187 | */ | |
188 | ||
189 | CF_EXPORT void _CFRuntimeUnregisterClassWithTypeID(CFTypeID typeID); | |
190 | /* Unregisters the class with the given type ID. It is | |
191 | * undefined whether type IDs are reused or not (expect | |
192 | * that they will be). | |
193 | * | |
194 | * Whether or not unregistering the class is a good idea or | |
195 | * not is not CF's responsibility. In particular you must | |
196 | * be quite sure all instances are gone, and there are no | |
197 | * valid weak refs to such in other threads. | |
198 | */ | |
199 | ||
200 | /* All CF "instances" start with this structure. Never refer to | |
201 | * these fields directly -- they are for CF's use and may be added | |
202 | * to or removed or change format without warning. Binary | |
203 | * compatibility for uses of this struct is not guaranteed from | |
204 | * release to release. | |
205 | */ | |
206 | typedef struct __CFRuntimeBase { | |
207 | void *_isa; | |
d8925383 | 208 | #if defined(__ppc__) || defined(__ppc64__) |
9ce05555 A |
209 | uint16_t _rc; |
210 | uint16_t _info; | |
211 | #elif defined(__i386__) | |
212 | uint16_t _info; | |
213 | uint16_t _rc; | |
214 | #else | |
215 | #error unknown architecture | |
216 | #endif | |
217 | } CFRuntimeBase; | |
218 | ||
d8925383 | 219 | #if defined(__ppc__) || defined(__ppc64__) |
9ce05555 A |
220 | #define INIT_CFRUNTIME_BASE(isa, info, rc) { isa, info, rc } |
221 | #elif defined(__i386__) | |
222 | #define INIT_CFRUNTIME_BASE(isa, info, rc) { isa, rc, info } | |
d8925383 | 223 | #else |
9ce05555 A |
224 | #error unknown architecture |
225 | #endif | |
226 | ||
227 | CF_EXPORT CFTypeRef _CFRuntimeCreateInstance(CFAllocatorRef allocator, CFTypeID typeID, uint32_t extraBytes, unsigned char *category); | |
228 | /* Creates a new CF instance of the class specified by the | |
229 | * given CFTypeID, using the given allocator, and returns it. | |
230 | * If the allocator returns NULL, this function returns NULL. | |
231 | * A CFRuntimeBase structure is initialized at the beginning | |
232 | * of the returned instance. extraBytes is the additional | |
233 | * number of bytes to allocate for the instance (BEYOND that | |
234 | * needed for the CFRuntimeBase). If the specified CFTypeID | |
235 | * is unknown to the CF runtime, this function returns NULL. | |
236 | * No part of the new memory other than base header is | |
237 | * initialized (the extra bytes are not zeroed, for example). | |
238 | * All instances created with this function must be destroyed | |
239 | * only through use of the CFRelease() function -- instances | |
240 | * must not be destroyed by using CFAllocatorDeallocate() | |
241 | * directly, even in the initialization or creation functions | |
242 | * of a class. Pass NULL for the category parameter. | |
243 | */ | |
244 | ||
245 | CF_EXPORT void _CFRuntimeSetInstanceTypeID(CFTypeRef cf, CFTypeID typeID); | |
246 | /* This function changes the typeID of the given instance. | |
247 | * If the specified CFTypeID is unknown to the CF runtime, | |
248 | * this function does nothing. This function CANNOT be used | |
249 | * to initialize an instance. It is for advanced usages such | |
250 | * as faulting. | |
251 | */ | |
252 | ||
253 | #if 0 | |
254 | // ========================= EXAMPLE ========================= | |
255 | ||
256 | // Example: EXRange -- a "range" object, which keeps the starting | |
257 | // location and length of the range. ("EX" as in "EXample"). | |
258 | ||
259 | // ---- API ---- | |
260 | ||
261 | typedef const struct __EXRange * EXRangeRef; | |
262 | ||
263 | CFTypeID EXRangeGetTypeID(void); | |
264 | ||
265 | EXRangeRef EXRangeCreate(CFAllocatorRef allocator, uint32_t location, uint32_t length); | |
266 | ||
267 | uint32_t EXRangeGetLocation(EXRangeRef rangeref); | |
268 | uint32_t EXRangeGetLength(EXRangeRef rangeref); | |
269 | ||
270 | ||
271 | // ---- implementation ---- | |
272 | ||
273 | #include <CoreFoundation/CFBase.h> | |
274 | #include <CoreFoundation/CFString.h> | |
275 | ||
276 | struct __EXRange { | |
277 | CFRuntimeBase _base; | |
278 | uint32_t _location; | |
279 | uint32_t _length; | |
280 | }; | |
281 | ||
282 | static Boolean __EXRangeEqual(CFTypeRef cf1, CFTypeRef cf2) { | |
283 | EXRangeRef rangeref1 = (EXRangeRef)cf1; | |
284 | EXRangeRef rangeref2 = (EXRangeRef)cf2; | |
285 | if (rangeref1->_location != rangeref2->_location) return false; | |
286 | if (rangeref1->_length != rangeref2->_length) return false; | |
287 | return true; | |
288 | } | |
289 | ||
290 | static CFHashCode __EXRangeHash(CFTypeRef cf) { | |
291 | EXRangeRef rangeref = (EXRangeRef)cf; | |
292 | return (CFHashCode)(rangeref->_location + rangeref->_length); | |
293 | } | |
294 | ||
295 | static CFStringRef __EXRangeCopyFormattingDesc(CFTypeRef cf, CFDictionaryRef formatOpts) { | |
296 | EXRangeRef rangeref = (EXRangeRef)cf; | |
297 | return CFStringCreateWithFormat(CFGetAllocator(rangeref), formatOpts, | |
298 | CFSTR("[%u, %u)"), | |
299 | rangeref->_location, | |
300 | rangeref->_location + rangeref->_length); | |
301 | } | |
302 | ||
303 | static CFStringRef __EXRangeCopyDebugDesc(CFTypeRef cf) { | |
304 | EXRangeRef rangeref = (EXRangeRef)cf; | |
305 | return CFStringCreateWithFormat(CFGetAllocator(rangeref), NULL, | |
306 | CFSTR("<EXRange %p [%p]>{loc = %u, len = %u}"), | |
307 | rangeref, | |
308 | CFGetAllocator(rangeref), | |
309 | rangeref->_location, | |
310 | rangeref->_length); | |
311 | } | |
312 | ||
313 | static void __EXRangeEXRangeFinalize(CFTypeRef cf) { | |
314 | EXRangeRef rangeref = (EXRangeRef)cf; | |
315 | // nothing to finalize | |
316 | } | |
317 | ||
318 | static CFTypeID _kEXRangeID = _kCFRuntimeNotATypeID; | |
319 | ||
320 | static CFRuntimeClass _kEXRangeClass = {0}; | |
321 | ||
322 | /* Something external to this file is assumed to call this | |
323 | * before the EXRange class is used. | |
324 | */ | |
325 | void __EXRangeClassInitialize(void) { | |
326 | _kEXRangeClass.version = 0; | |
327 | _kEXRangeClass.className = "EXRange"; | |
328 | _kEXRangeClass.init = NULL; | |
329 | _kEXRangeClass.copy = NULL; | |
330 | _kEXRangeClass.finalize = __EXRangeEXRangeFinalize; | |
331 | _kEXRangeClass.equal = __EXRangeEqual; | |
332 | _kEXRangeClass.hash = __EXRangeHash; | |
333 | _kEXRangeClass.copyFormattingDesc = __EXRangeCopyFormattingDesc; | |
334 | _kEXRangeClass.copyDebugDesc = __EXRangeCopyDebugDesc; | |
335 | _kEXRangeID = _CFRuntimeRegisterClass((const CFRuntimeClass * const)&_kEXRangeClass); | |
336 | } | |
337 | ||
338 | CFTypeID EXRangeGetTypeID(void) { | |
339 | return _kEXRangeID; | |
340 | } | |
341 | ||
342 | EXRangeRef EXRangeCreate(CFAllocatorRef allocator, uint32_t location, uint32_t length) { | |
343 | struct __EXRange *newrange; | |
344 | uint32_t extra = sizeof(struct __EXRange) - sizeof(CFRuntimeBase); | |
d8925383 | 345 | newrange = (struct __EXRange *)_CFRuntimeCreateInstance(allocator, _kEXRangeID, extra, NULL); |
9ce05555 A |
346 | if (NULL == newrange) { |
347 | return NULL; | |
348 | } | |
349 | newrange->_location = location; | |
350 | newrange->_length = length; | |
351 | return (EXRangeRef)newrange; | |
352 | } | |
353 | ||
354 | uint32_t EXRangeGetLocation(EXRangeRef rangeref) { | |
355 | return rangeref->_location; | |
356 | } | |
357 | ||
358 | uint32_t EXRangeGetLength(EXRangeRef rangeref) { | |
359 | return rangeref->_length; | |
360 | } | |
361 | ||
362 | #endif | |
363 | ||
364 | #if defined(__cplusplus) | |
365 | } | |
366 | #endif | |
367 | ||
368 | #endif /* ! __COREFOUNDATION_CFRUNTIME__ */ |