| /* |
| * Copyright (c) 2012-2013 Apple Inc. All rights reserved. |
| * |
| * @APPLE_APACHE_LICENSE_HEADER_START@ |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| * @APPLE_APACHE_LICENSE_HEADER_END@ |
| */ |
| |
| #include "internal.h" |
| |
| #if DISPATCH_DATA_IS_BRIDGED_TO_NSDATA |
| |
| #if _OS_OBJECT_OBJC_ARC |
| #error "Cannot build with ARC" |
| #endif |
| |
| #include <Foundation/NSString.h> |
| |
| @interface DISPATCH_CLASS(data) () <DISPATCH_CLASS(data)> |
| @property (readonly,nonatomic) NSUInteger length; |
| @property (readonly,nonatomic) const void *bytes NS_RETURNS_INNER_POINTER; |
| |
| - (id)initWithBytes:(void *)bytes length:(NSUInteger)length copy:(BOOL)copy |
| freeWhenDone:(BOOL)freeBytes bytesAreVM:(BOOL)vm; |
| - (BOOL)_bytesAreVM; |
| - (BOOL)_isCompact; |
| @end |
| |
| @interface DISPATCH_CLASS(data_empty) : DISPATCH_CLASS(data) |
| @end |
| |
| @implementation DISPATCH_CLASS(data) |
| |
| + (id)allocWithZone:(NSZone *) DISPATCH_UNUSED zone { |
| return _dispatch_objc_alloc(self, sizeof(struct dispatch_data_s)); |
| } |
| |
| - (id)init { |
| return [self initWithBytes:NULL length:0 copy:NO freeWhenDone:NO |
| bytesAreVM:NO]; |
| } |
| |
| - (id)initWithBytes:(void *)bytes length:(NSUInteger)length copy:(BOOL)copy |
| freeWhenDone:(BOOL)freeBytes bytesAreVM:(BOOL)vm { |
| dispatch_block_t destructor; |
| if (copy) { |
| destructor = DISPATCH_DATA_DESTRUCTOR_DEFAULT; |
| } else if (freeBytes) { |
| if (vm) { |
| destructor = DISPATCH_DATA_DESTRUCTOR_VM_DEALLOCATE; |
| } else { |
| destructor = DISPATCH_DATA_DESTRUCTOR_FREE; |
| } |
| } else { |
| destructor = DISPATCH_DATA_DESTRUCTOR_NONE; |
| } |
| dispatch_data_init(self, bytes, length, destructor); |
| return self; |
| } |
| |
| #define _dispatch_data_objc_dispose(selector) \ |
| struct dispatch_data_s *dd = (void*)self; \ |
| _dispatch_data_dispose(self); \ |
| dispatch_queue_t tq = dd->do_targetq; \ |
| dispatch_function_t func = dd->finalizer; \ |
| void *ctxt = dd->ctxt; \ |
| [super selector]; \ |
| if (func && ctxt) { \ |
| if (!tq) { \ |
| tq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);\ |
| } \ |
| dispatch_async_f(tq, ctxt, func); \ |
| } \ |
| if (tq) { \ |
| _os_object_release_internal((_os_object_t)tq); \ |
| } |
| |
| - (void)dealloc { |
| _dispatch_data_objc_dispose(dealloc); |
| } |
| |
| - (BOOL)_bytesAreVM { |
| struct dispatch_data_s *dd = (void*)self; |
| return dd->destructor == DISPATCH_DATA_DESTRUCTOR_VM_DEALLOCATE; |
| } |
| |
| - (void)_setContext:(void*)context { |
| struct dispatch_data_s *dd = (void*)self; |
| dd->ctxt = context; |
| } |
| |
| - (void*)_getContext { |
| struct dispatch_data_s *dd = (void*)self; |
| return dd->ctxt; |
| } |
| |
| - (void)_setFinalizer:(dispatch_function_t)finalizer { |
| struct dispatch_data_s *dd = (void*)self; |
| dd->finalizer = finalizer; |
| } |
| |
| - (void)_setTargetQueue:(dispatch_queue_t)queue { |
| struct dispatch_data_s *dd = (void*)self; |
| _os_object_retain_internal((_os_object_t)queue); |
| dispatch_queue_t prev; |
| prev = os_atomic_xchg2o(dd, do_targetq, queue, release); |
| if (prev) _os_object_release_internal((_os_object_t)prev); |
| } |
| |
| - (NSString *)debugDescription { |
| Class nsstring = objc_lookUpClass("NSString"); |
| if (!nsstring) return nil; |
| char buf[2048]; |
| _dispatch_data_debug(self, buf, sizeof(buf)); |
| NSString *format = [nsstring stringWithUTF8String:"<%s: %s>"]; |
| if (!format) return nil; |
| return [nsstring stringWithFormat:format, class_getName([self class]), buf]; |
| } |
| |
| - (NSUInteger)length { |
| struct dispatch_data_s *dd = (void*)self; |
| return dd->size; |
| } |
| |
| - (const void *)bytes { |
| struct dispatch_data_s *dd = (void*)self; |
| return _dispatch_data_get_flattened_bytes(dd); |
| } |
| |
| - (BOOL)_isCompact { |
| struct dispatch_data_s *dd = (void*)self; |
| return !dd->size || _dispatch_data_map_direct(dd, 0, NULL, NULL) != NULL; |
| } |
| |
| - (void)_suspend { |
| } |
| |
| - (void)_resume { |
| } |
| |
| - (void)_activate { |
| } |
| |
| @end |
| |
| @implementation DISPATCH_CLASS(data_empty) |
| |
| // Force non-lazy class realization rdar://10640168 |
| + (void)load { |
| } |
| |
| - (id)retain { |
| return (id)self; |
| } |
| |
| - (oneway void)release { |
| } |
| |
| - (id)autorelease { |
| return (id)self; |
| } |
| |
| - (NSUInteger)retainCount { |
| return ULONG_MAX; |
| } |
| |
| + (id)allocWithZone:(NSZone *) DISPATCH_UNUSED zone { |
| return (id)&_dispatch_data_empty; |
| } |
| |
| - (void)_setContext:(void*) DISPATCH_UNUSED context { |
| } |
| |
| - (void*)_getContext { |
| return NULL; |
| } |
| |
| - (void)_setFinalizer:(dispatch_function_t) DISPATCH_UNUSED finalizer { |
| } |
| |
| - (void)_setTargetQueue:(dispatch_queue_t) DISPATCH_UNUSED queue { |
| } |
| |
| - (void)_suspend { |
| } |
| |
| - (void)_resume { |
| } |
| |
| - (void)_activate { |
| } |
| |
| @end |
| |
| #endif // USE_OBJC |