1/*
2 * Copyright (c) 2012-2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_APACHE_LICENSE_HEADER_START@
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * @APPLE_APACHE_LICENSE_HEADER_END@
19 */
20
21#include "internal.h"
22
23#if USE_OBJC
24
25#if !__OBJC2__
26#error "Cannot build with legacy ObjC runtime"
27#endif
28#if _OS_OBJECT_OBJC_ARC
29#error "Cannot build with ARC"
30#endif
31
32#include <Foundation/NSString.h>
33
34@interface DISPATCH_CLASS(data) ()
35- (id)initWithBytes:(void *)bytes length:(NSUInteger)length copy:(BOOL)copy
36		freeWhenDone:(BOOL)freeBytes bytesAreVM:(BOOL)vm;
37- (BOOL)_bytesAreVM;
38@end
39
40@interface DISPATCH_CLASS(data_empty) : DISPATCH_CLASS(data)
41@end
42
43@implementation DISPATCH_CLASS(data)
44
45+ (id)allocWithZone:(NSZone *) DISPATCH_UNUSED zone {
46	return _dispatch_objc_alloc(self, sizeof(struct dispatch_data_s));
47}
48
49- (id)init {
50    return [self initWithBytes:NULL length:0 copy:NO freeWhenDone:NO
51			bytesAreVM:NO];
52}
53
54- (id)initWithBytes:(void *)bytes length:(NSUInteger)length copy:(BOOL)copy
55		freeWhenDone:(BOOL)freeBytes bytesAreVM:(BOOL)vm {
56	dispatch_block_t destructor;
57	if (copy) {
58		destructor = DISPATCH_DATA_DESTRUCTOR_DEFAULT;
59	} else if (freeBytes) {
60		if (vm) {
61			destructor = DISPATCH_DATA_DESTRUCTOR_VM_DEALLOCATE;
62		} else {
63			destructor = DISPATCH_DATA_DESTRUCTOR_FREE;
64		}
65	} else {
66		destructor = DISPATCH_DATA_DESTRUCTOR_NONE;
67	}
68	dispatch_data_init(self, bytes, length, destructor);
69	return self;
70}
71
72#define _dispatch_data_objc_dispose(selector) \
73	struct dispatch_data_s *dd = (void*)self; \
74	_dispatch_data_dispose(self); \
75	dispatch_queue_t tq = dd->do_targetq; \
76	dispatch_function_t func = dd->finalizer; \
77	void *ctxt = dd->ctxt; \
78	[super selector]; \
79	if (func && ctxt) { \
80		if (!tq) { \
81			 tq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);\
82		} \
83		dispatch_async_f(tq, ctxt, func); \
84	} \
85	if (tq) { \
86		_dispatch_release(tq); \
87	}
88
89- (void)dealloc {
90	_dispatch_data_objc_dispose(dealloc);
91}
92
93- (void)finalize {
94	_dispatch_data_objc_dispose(finalize);
95}
96
97- (BOOL)_bytesAreVM {
98	struct dispatch_data_s *dd = (void*)self;
99	return dd->destructor == DISPATCH_DATA_DESTRUCTOR_VM_DEALLOCATE;
100}
101
102- (void)_setContext:(void*)context {
103	struct dispatch_data_s *dd = (void*)self;
104	dd->ctxt = context;
105}
106
107- (void*)_getContext {
108	struct dispatch_data_s *dd = (void*)self;
109	return dd->ctxt;
110}
111
112- (void)_setFinalizer:(dispatch_function_t)finalizer {
113	struct dispatch_data_s *dd = (void*)self;
114	dd->finalizer = finalizer;
115}
116
117- (void)_setTargetQueue:(dispatch_queue_t)queue {
118	struct dispatch_data_s *dd = (void*)self;
119	_dispatch_retain(queue);
120	dispatch_queue_t prev;
121	prev = dispatch_atomic_xchg2o(dd, do_targetq, queue, release);
122	if (prev) _dispatch_release(prev);
123}
124
125- (NSString *)debugDescription {
126	Class nsstring = objc_lookUpClass("NSString");
127	if (!nsstring) return nil;
128	char buf[2048];
129	_dispatch_data_debug(self, buf, sizeof(buf));
130	return [nsstring stringWithFormat:
131			[nsstring stringWithUTF8String:"<%s: %s>"],
132			class_getName([self class]), buf];
133}
134
135@end
136
137@implementation DISPATCH_CLASS(data_empty)
138
139// Force non-lazy class realization rdar://10640168
140+ (void)load {
141}
142
143- (id)retain {
144	return (id)self;
145}
146
147- (oneway void)release {
148}
149
150- (id)autorelease {
151	return (id)self;
152}
153
154- (NSUInteger)retainCount {
155	return ULONG_MAX;
156}
157
158+ (id)allocWithZone:(NSZone *) DISPATCH_UNUSED zone {
159	return (id)&_dispatch_data_empty;
160}
161
162- (void)_setContext:(void*) DISPATCH_UNUSED context {
163}
164
165- (void*)_getContext {
166	return NULL;
167}
168
169- (void)_setFinalizer:(dispatch_function_t) DISPATCH_UNUSED finalizer {
170}
171
172- (void)_setTargetQueue:(dispatch_queue_t) DISPATCH_UNUSED queue {
173}
174
175@end
176
177#endif // USE_OBJC
178