]> git.saurik.com Git - apple/cf.git/blob - CFRuntime.h
CF-744.12.tar.gz
[apple/cf.git] / CFRuntime.h
1 /*
2 * Copyright (c) 2012 Apple 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 /* CFRuntime.h
25 Copyright (c) 1999-2012, Apple Inc. All rights reserved.
26 */
27
28 #if !defined(__COREFOUNDATION_CFRUNTIME__)
29 #define __COREFOUNDATION_CFRUNTIME__ 1
30
31 #include <CoreFoundation/CFBase.h>
32 #include <CoreFoundation/CFDictionary.h>
33 #include <stddef.h>
34
35 CF_EXTERN_C_BEGIN
36
37 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
38
39 // GC: until we link against ObjC must use indirect functions. Overridden in CFSetupFoundationBridging
40 CF_EXPORT bool kCFUseCollectableAllocator;
41 CF_EXPORT bool (*__CFObjCIsCollectable)(void *);
42
43 // Only CoreFoundation and Foundation should use these *GCRefZero constants;
44 // do not listen to anyone who tells you otherwise.
45
46 CF_EXPORT
47 const CFAllocatorRef kCFAllocatorSystemDefaultGCRefZero; // DO NOT USE THIS
48 CF_EXPORT
49 const CFAllocatorRef kCFAllocatorDefaultGCRefZero; // DO NOT USE THIS
50
51 CF_INLINE CFAllocatorRef _CFConvertAllocatorToNonGCRefZeroEquivalent(CFAllocatorRef allocator) {
52 if (kCFAllocatorSystemDefaultGCRefZero == allocator) {
53 allocator = kCFAllocatorSystemDefault;
54 } else if (kCFAllocatorDefaultGCRefZero == allocator || NULL == allocator || kCFAllocatorDefault == allocator) {
55 allocator = CFAllocatorGetDefault();
56 }
57 return allocator;
58 }
59
60 CF_INLINE CFAllocatorRef _CFConvertAllocatorToGCRefZeroEquivalent(CFAllocatorRef allocator) { // DO NOT USE THIS
61 if (!kCFUseCollectableAllocator) return allocator;
62 if (kCFAllocatorDefault == allocator || NULL == allocator) {
63 allocator = CFAllocatorGetDefault();
64 }
65 if (kCFAllocatorSystemDefault == allocator) {
66 allocator = kCFAllocatorSystemDefaultGCRefZero;
67 } else if (CFAllocatorGetDefault() == allocator) {
68 allocator = kCFAllocatorDefaultGCRefZero;
69 }
70 return allocator;
71 }
72
73 CF_INLINE Boolean _CFAllocatorIsSystemDefault(CFAllocatorRef allocator) {
74 if (allocator == kCFAllocatorSystemDefaultGCRefZero || allocator == kCFAllocatorSystemDefault) return true;
75 if (kCFAllocatorDefaultGCRefZero == allocator || NULL == allocator || kCFAllocatorDefault == allocator) {
76 return (kCFAllocatorSystemDefault == CFAllocatorGetDefault());
77 }
78 return false;
79 }
80
81 CF_INLINE Boolean _CFAllocatorIsGCRefZero(CFAllocatorRef allocator) {
82 // not intended as a literal test, but as a behavioral test
83 if (!kCFUseCollectableAllocator) return false;
84 return (kCFAllocatorSystemDefaultGCRefZero == allocator || kCFAllocatorDefaultGCRefZero == allocator);
85 }
86
87 // is GC on?
88 #define CF_USING_COLLECTABLE_MEMORY (kCFUseCollectableAllocator)
89 // is GC on and is this the GC allocator?
90 #define CF_IS_COLLECTABLE_ALLOCATOR(allocator) (kCFUseCollectableAllocator && (NULL == (allocator) || kCFAllocatorSystemDefault == (allocator) || _CFAllocatorIsGCRefZero(allocator)))
91 // is this allocated by the collector?
92 #define CF_IS_COLLECTABLE(obj) (__CFObjCIsCollectable ? __CFObjCIsCollectable((void*)obj) : false)
93
94 #else
95
96 #define kCFUseCollectableAllocator 0
97 #define __CFObjCIsCollectable 0
98 #define kCFAllocatorSystemDefaultGCRefZero kCFAllocatorSystemDefault
99 #define kCFAllocatorDefaultGCRefZero kCFAllocatorDefault
100
101 #define _CFConvertAllocatorToNonGCRefZeroEquivalent(A) (A)
102 #define _CFConvertAllocatorToGCRefZeroEquivalent(A) (A)
103
104 CF_INLINE Boolean _CFAllocatorIsSystemDefault(CFAllocatorRef allocator) {
105 if (allocator == kCFAllocatorSystemDefault) return true;
106 if (NULL == allocator || kCFAllocatorDefault == allocator) {
107 return (kCFAllocatorSystemDefault == CFAllocatorGetDefault());
108 }
109 return false;
110 }
111
112 #define _CFAllocatorIsGCRefZero(A) (0)
113 #define CF_USING_COLLECTABLE_MEMORY 0
114 #define CF_IS_COLLECTABLE_ALLOCATOR(allocator) 0
115 #define CF_IS_COLLECTABLE(obj) 0
116 #endif
117
118 enum {
119 _kCFRuntimeNotATypeID = 0
120 };
121
122 enum { // Version field constants
123 _kCFRuntimeScannedObject = (1UL << 0),
124 _kCFRuntimeResourcefulObject = (1UL << 2), // tells CFRuntime to make use of the reclaim field
125 _kCFRuntimeCustomRefCount = (1UL << 3), // tells CFRuntime to make use of the refcount field
126 };
127
128 typedef struct __CFRuntimeClass {
129 CFIndex version;
130 const char *className; // must be a pure ASCII string, nul-terminated
131 void (*init)(CFTypeRef cf);
132 CFTypeRef (*copy)(CFAllocatorRef allocator, CFTypeRef cf);
133 void (*finalize)(CFTypeRef cf);
134 Boolean (*equal)(CFTypeRef cf1, CFTypeRef cf2);
135 CFHashCode (*hash)(CFTypeRef cf);
136 CFStringRef (*copyFormattingDesc)(CFTypeRef cf, CFDictionaryRef formatOptions); // return str with retain
137 CFStringRef (*copyDebugDesc)(CFTypeRef cf); // return str with retain
138
139 #define CF_RECLAIM_AVAILABLE 1
140 void (*reclaim)(CFTypeRef cf); // Set _kCFRuntimeResourcefulObject in the .version to indicate this field should be used
141
142 #define CF_REFCOUNT_AVAILABLE 1
143 uint32_t (*refcount)(intptr_t op, CFTypeRef cf); // Set _kCFRuntimeCustomRefCount in the .version to indicate this field should be used
144 // this field must be non-NULL when _kCFRuntimeCustomRefCount is in the .version field
145 // - if the callback is passed 1 in 'op' it should increment the 'cf's reference count and return 0
146 // - if the callback is passed 0 in 'op' it should return the 'cf's reference count, up to 32 bits
147 // - if the callback is passed -1 in 'op' it should decrement the 'cf's reference count; if it is now zero, 'cf' should be cleaned up and deallocated (the finalize callback above will NOT be called unless the process is running under GC, and CF does not deallocate the memory for you; if running under GC, finalize should do the object tear-down and free the object memory); then return 0
148 // remember to use saturation arithmetic logic and stop incrementing and decrementing when the ref count hits UINT32_MAX, or you will have a security bug
149 // remember that reference count incrementing/decrementing must be done thread-safely/atomically
150 // objects should be created/initialized with a custom ref-count of 1 by the class creation functions
151 // do not attempt to use any bits within the CFRuntimeBase for your reference count; store that in some additional field in your CF object
152
153 } CFRuntimeClass;
154
155 #define RADAR_5115468_FIXED 1
156
157 /* Note that CF runtime class registration and unregistration is not currently
158 * thread-safe, which should not currently be a problem, as long as unregistration
159 * is done only when valid to do so.
160 */
161
162 CF_EXPORT CFTypeID _CFRuntimeRegisterClass(const CFRuntimeClass * const cls);
163 /* Registers a new class with the CF runtime. Pass in a
164 * pointer to a CFRuntimeClass structure. The pointer is
165 * remembered by the CF runtime -- the structure is NOT
166 * copied.
167 *
168 * - version field must be zero currently.
169 * - className field points to a null-terminated C string
170 * containing only ASCII (0 - 127) characters; this field
171 * may NOT be NULL.
172 * - init field points to a function which classes can use to
173 * apply some generic initialization to instances as they
174 * are created; this function is called by both
175 * _CFRuntimeCreateInstance and _CFRuntimeInitInstance; if
176 * this field is NULL, no function is called; the instance
177 * has been initialized enough that the polymorphic funcs
178 * CFGetTypeID(), CFRetain(), CFRelease(), CFGetRetainCount(),
179 * and CFGetAllocator() are valid on it when the init
180 * function if any is called.
181 * - finalize field points to a function which destroys an
182 * instance when the retain count has fallen to zero; if
183 * this is NULL, finalization does nothing. Note that if
184 * the class-specific functions which create or initialize
185 * instances more fully decide that a half-initialized
186 * instance must be destroyed, the finalize function for
187 * that class has to be able to deal with half-initialized
188 * instances. The finalize function should NOT destroy the
189 * memory for the instance itself; that is done by the
190 * CF runtime after this finalize callout returns.
191 * - equal field points to an equality-testing function; this
192 * field may be NULL, in which case only pointer/reference
193 * equality is performed on instances of this class.
194 * Pointer equality is tested, and the type IDs are checked
195 * for equality, before this function is called (so, the
196 * two instances are not pointer-equal but are of the same
197 * class before this function is called).
198 * NOTE: the equal function must implement an immutable
199 * equality relation, satisfying the reflexive, symmetric,
200 * and transitive properties, and remains the same across
201 * time and immutable operations (that is, if equal(A,B) at
202 * some point, then later equal(A,B) provided neither
203 * A or B has been mutated).
204 * - hash field points to a hash-code-computing function for
205 * instances of this class; this field may be NULL in which
206 * case the pointer value of an instance is converted into
207 * a hash.
208 * NOTE: the hash function and equal function must satisfy
209 * the relationship "equal(A,B) implies hash(A) == hash(B)";
210 * that is, if two instances are equal, their hash codes must
211 * be equal too. (However, the converse is not true!)
212 * - copyFormattingDesc field points to a function returning a
213 * CFStringRef with a human-readable description of the
214 * instance; if this is NULL, the type does not have special
215 * human-readable string-formats.
216 * - copyDebugDesc field points to a function returning a
217 * CFStringRef with a debugging description of the instance;
218 * if this is NULL, a simple description is generated.
219 *
220 * This function returns _kCFRuntimeNotATypeID on failure, or
221 * on success, returns the CFTypeID for the new class. This
222 * CFTypeID is what the class uses to allocate or initialize
223 * instances of the class. It is also returned from the
224 * conventional *GetTypeID() function, which returns the
225 * class's CFTypeID so that clients can compare the
226 * CFTypeID of instances with that of a class.
227 *
228 * The function to compute a human-readable string is very
229 * optional, and is really only interesting for classes,
230 * like strings or numbers, where it makes sense to format
231 * the instance using just its contents.
232 */
233
234 CF_EXPORT const CFRuntimeClass * _CFRuntimeGetClassWithTypeID(CFTypeID typeID);
235 /* Returns the pointer to the CFRuntimeClass which was
236 * assigned the specified CFTypeID.
237 */
238
239 CF_EXPORT void _CFRuntimeUnregisterClassWithTypeID(CFTypeID typeID);
240 /* Unregisters the class with the given type ID. It is
241 * undefined whether type IDs are reused or not (expect
242 * that they will be).
243 *
244 * Whether or not unregistering the class is a good idea or
245 * not is not CF's responsibility. In particular you must
246 * be quite sure all instances are gone, and there are no
247 * valid weak refs to such in other threads.
248 */
249
250 /* All CF "instances" start with this structure. Never refer to
251 * these fields directly -- they are for CF's use and may be added
252 * to or removed or change format without warning. Binary
253 * compatibility for uses of this struct is not guaranteed from
254 * release to release.
255 */
256 typedef struct __CFRuntimeBase {
257 uintptr_t _cfisa;
258 uint8_t _cfinfo[4];
259 #if __LP64__
260 uint32_t _rc;
261 #endif
262 } CFRuntimeBase;
263
264 #if __BIG_ENDIAN__
265 #define INIT_CFRUNTIME_BASE(...) {0, {0, 0, 0, 0x80}}
266 #else
267 #define INIT_CFRUNTIME_BASE(...) {0, {0x80, 0, 0, 0}}
268 #endif
269
270 CF_EXPORT CFTypeRef _CFRuntimeCreateInstance(CFAllocatorRef allocator, CFTypeID typeID, CFIndex extraBytes, unsigned char *category);
271 /* Creates a new CF instance of the class specified by the
272 * given CFTypeID, using the given allocator, and returns it.
273 * If the allocator returns NULL, this function returns NULL.
274 * A CFRuntimeBase structure is initialized at the beginning
275 * of the returned instance. extraBytes is the additional
276 * number of bytes to allocate for the instance (BEYOND that
277 * needed for the CFRuntimeBase). If the specified CFTypeID
278 * is unknown to the CF runtime, this function returns NULL.
279 * No part of the new memory other than base header is
280 * initialized (the extra bytes are not zeroed, for example).
281 * All instances created with this function must be destroyed
282 * only through use of the CFRelease() function -- instances
283 * must not be destroyed by using CFAllocatorDeallocate()
284 * directly, even in the initialization or creation functions
285 * of a class. Pass NULL for the category parameter.
286 */
287
288 CF_EXPORT void _CFRuntimeSetInstanceTypeID(CFTypeRef cf, CFTypeID typeID);
289 /* This function changes the typeID of the given instance.
290 * If the specified CFTypeID is unknown to the CF runtime,
291 * this function does nothing. This function CANNOT be used
292 * to initialize an instance. It is for advanced usages such
293 * as faulting. You cannot change the CFTypeID of an object
294 * of a _kCFRuntimeCustomRefCount class, or to a
295 * _kCFRuntimeCustomRefCount class.
296 */
297
298 CF_EXPORT void _CFRuntimeInitStaticInstance(void *memory, CFTypeID typeID);
299 /* This function initializes a memory block to be a constant
300 * (unreleaseable) CF object of the given typeID.
301 * If the specified CFTypeID is unknown to the CF runtime,
302 * this function does nothing. The memory block should
303 * be a chunk of in-binary writeable static memory, and at
304 * least as large as sizeof(CFRuntimeBase) on the platform
305 * the code is being compiled for. The init function of the
306 * CFRuntimeClass is invoked on the memory as well, if the
307 * class has one. Static instances cannot be initialized to
308 * _kCFRuntimeCustomRefCount classes.
309 */
310 #define CF_HAS_INIT_STATIC_INSTANCE 1
311
312 #if 0
313 // ========================= EXAMPLE =========================
314
315 // Example: EXRange -- a "range" object, which keeps the starting
316 // location and length of the range. ("EX" as in "EXample").
317
318 // ---- API ----
319
320 typedef const struct __EXRange * EXRangeRef;
321
322 CFTypeID EXRangeGetTypeID(void);
323
324 EXRangeRef EXRangeCreate(CFAllocatorRef allocator, uint32_t location, uint32_t length);
325
326 uint32_t EXRangeGetLocation(EXRangeRef rangeref);
327 uint32_t EXRangeGetLength(EXRangeRef rangeref);
328
329
330 // ---- implementation ----
331
332 #include <CoreFoundation/CFBase.h>
333 #include <CoreFoundation/CFString.h>
334
335 struct __EXRange {
336 CFRuntimeBase _base;
337 uint32_t _location;
338 uint32_t _length;
339 };
340
341 static Boolean __EXRangeEqual(CFTypeRef cf1, CFTypeRef cf2) {
342 EXRangeRef rangeref1 = (EXRangeRef)cf1;
343 EXRangeRef rangeref2 = (EXRangeRef)cf2;
344 if (rangeref1->_location != rangeref2->_location) return false;
345 if (rangeref1->_length != rangeref2->_length) return false;
346 return true;
347 }
348
349 static CFHashCode __EXRangeHash(CFTypeRef cf) {
350 EXRangeRef rangeref = (EXRangeRef)cf;
351 return (CFHashCode)(rangeref->_location + rangeref->_length);
352 }
353
354 static CFStringRef __EXRangeCopyFormattingDesc(CFTypeRef cf, CFDictionaryRef formatOpts) {
355 EXRangeRef rangeref = (EXRangeRef)cf;
356 return CFStringCreateWithFormat(CFGetAllocator(rangeref), formatOpts,
357 CFSTR("[%u, %u)"),
358 rangeref->_location,
359 rangeref->_location + rangeref->_length);
360 }
361
362 static CFStringRef __EXRangeCopyDebugDesc(CFTypeRef cf) {
363 EXRangeRef rangeref = (EXRangeRef)cf;
364 return CFStringCreateWithFormat(CFGetAllocator(rangeref), NULL,
365 CFSTR("<EXRange %p [%p]>{loc = %u, len = %u}"),
366 rangeref,
367 CFGetAllocator(rangeref),
368 rangeref->_location,
369 rangeref->_length);
370 }
371
372 static void __EXRangeEXRangeFinalize(CFTypeRef cf) {
373 EXRangeRef rangeref = (EXRangeRef)cf;
374 // nothing to finalize
375 }
376
377 static CFTypeID _kEXRangeID = _kCFRuntimeNotATypeID;
378
379 static CFRuntimeClass _kEXRangeClass = {0};
380
381 /* Something external to this file is assumed to call this
382 * before the EXRange class is used.
383 */
384 void __EXRangeClassInitialize(void) {
385 _kEXRangeClass.version = 0;
386 _kEXRangeClass.className = "EXRange";
387 _kEXRangeClass.init = NULL;
388 _kEXRangeClass.copy = NULL;
389 _kEXRangeClass.finalize = __EXRangeEXRangeFinalize;
390 _kEXRangeClass.equal = __EXRangeEqual;
391 _kEXRangeClass.hash = __EXRangeHash;
392 _kEXRangeClass.copyFormattingDesc = __EXRangeCopyFormattingDesc;
393 _kEXRangeClass.copyDebugDesc = __EXRangeCopyDebugDesc;
394 _kEXRangeID = _CFRuntimeRegisterClass((const CFRuntimeClass * const)&_kEXRangeClass);
395 }
396
397 CFTypeID EXRangeGetTypeID(void) {
398 return _kEXRangeID;
399 }
400
401 EXRangeRef EXRangeCreate(CFAllocatorRef allocator, uint32_t location, uint32_t length) {
402 struct __EXRange *newrange;
403 uint32_t extra = sizeof(struct __EXRange) - sizeof(CFRuntimeBase);
404 newrange = (struct __EXRange *)_CFRuntimeCreateInstance(allocator, _kEXRangeID, extra, NULL);
405 if (NULL == newrange) {
406 return NULL;
407 }
408 newrange->_location = location;
409 newrange->_length = length;
410 return (EXRangeRef)newrange;
411 }
412
413 uint32_t EXRangeGetLocation(EXRangeRef rangeref) {
414 return rangeref->_location;
415 }
416
417 uint32_t EXRangeGetLength(EXRangeRef rangeref) {
418 return rangeref->_length;
419 }
420
421 #endif
422
423 CF_EXTERN_C_END
424
425 #endif /* ! __COREFOUNDATION_CFRUNTIME__ */