SFObjCType.m
1 /* 2 * Copyright (c) 2017 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 #if __OBJC2__ 25 26 #import "SFObjCType.h" 27 28 static NSArray<SFObjCType *> *_SFObjCTypesByCode = nil; 29 30 31 #define OBJC_TYPE(_code, _encoding, _name, _size, _flags) \ 32 [[SFObjCType alloc] initWithCode:SFObjCType##_code encoding:_encoding name:_name className:nil size:_size flags:SFObjCTypeFlag##_flags] 33 34 @implementation SFObjCType 35 36 @synthesize code = _code; 37 @synthesize encoding = _encoding; 38 @synthesize name = _name; 39 @synthesize className = _className; 40 @synthesize size = _size; 41 @synthesize flags = _flags; 42 43 + (SFObjCType *)typeForEncoding:(const char *)encodingUTF8 { 44 NSString *encoding = @(encodingUTF8); 45 46 static dispatch_once_t once; 47 dispatch_once(&once, ^{ 48 _SFObjCTypesByCode = @[ 49 OBJC_TYPE(Char, @"c", @"char", sizeof(char), IntegerNumber), 50 OBJC_TYPE(Short, @"s", @"short", sizeof(short), IntegerNumber), 51 OBJC_TYPE(Int, @"i", @"int", sizeof(int), IntegerNumber), 52 OBJC_TYPE(Long, @"l", @"long", sizeof(long), IntegerNumber), 53 OBJC_TYPE(LongLong, @"q", @"long long", sizeof(long long), IntegerNumber), 54 OBJC_TYPE(UnsignedChar, @"C", @"unsigned char", sizeof(unsigned char), IntegerNumber), 55 OBJC_TYPE(UnsignedShort, @"S", @"unsigned short", sizeof(unsigned short), IntegerNumber), 56 OBJC_TYPE(UnsignedInt, @"I", @"unsigned int", sizeof(unsigned int), IntegerNumber), 57 OBJC_TYPE(UnsignedLong, @"L", @"unsigned long", sizeof(unsigned long), IntegerNumber), 58 OBJC_TYPE(UnsignedLongLong, @"Q", @"unsigned long long", sizeof(unsigned long long), IntegerNumber), 59 OBJC_TYPE(Float, @"f", @"float", sizeof(float), FloatingPointNumber), 60 OBJC_TYPE(Double, @"d", @"double", sizeof(double), FloatingPointNumber), 61 OBJC_TYPE(Bool, @"B", @"bool", sizeof(bool), IntegerNumber), 62 OBJC_TYPE(Void, @"v", @"void", sizeof(void), None), 63 OBJC_TYPE(CharPointer, @"*", @"char*", sizeof(char*), None), 64 OBJC_TYPE(Object, @"@", @"id", sizeof(id), None), 65 OBJC_TYPE(Class, @"#", @"Class", sizeof(Class), None), 66 ]; 67 }); 68 69 switch (encodingUTF8[0]) { 70 case 'c': return _SFObjCTypesByCode[SFObjCTypeChar]; 71 case 's': return _SFObjCTypesByCode[SFObjCTypeShort]; 72 case 'i': return _SFObjCTypesByCode[SFObjCTypeInt]; 73 case 'l': return _SFObjCTypesByCode[SFObjCTypeLong]; 74 case 'q': return _SFObjCTypesByCode[SFObjCTypeLongLong]; 75 case 'C': return _SFObjCTypesByCode[SFObjCTypeUnsignedChar]; 76 case 'S': return _SFObjCTypesByCode[SFObjCTypeUnsignedShort]; 77 case 'I': return _SFObjCTypesByCode[SFObjCTypeUnsignedInt]; 78 case 'L': return _SFObjCTypesByCode[SFObjCTypeUnsignedLong]; 79 case 'Q': return _SFObjCTypesByCode[SFObjCTypeUnsignedLongLong]; 80 case 'f': return _SFObjCTypesByCode[SFObjCTypeFloat]; 81 case 'd': return _SFObjCTypesByCode[SFObjCTypeDouble]; 82 case 'B': return _SFObjCTypesByCode[SFObjCTypeBool]; 83 case 'v': return _SFObjCTypesByCode[SFObjCTypeVoid]; 84 case '*': return _SFObjCTypesByCode[SFObjCTypeCharPointer]; 85 case '@': { 86 if (encoding.length > 3 && [encoding characterAtIndex:1] == '"' && [encoding characterAtIndex:encoding.length-1] == '"') { 87 NSString *className = [encoding substringWithRange:NSMakeRange(2, encoding.length-3)]; 88 NSString *name = [className stringByAppendingString:@"*"]; 89 return [[SFObjCType alloc] initWithCode:SFObjCTypeObject encoding:encoding name:name className:className size:sizeof(id) flags:SFObjCTypeFlagNone]; 90 } else { 91 return _SFObjCTypesByCode[SFObjCTypeObject]; 92 } 93 } 94 case '#': return _SFObjCTypesByCode[SFObjCTypeClass]; 95 case ':': return _SFObjCTypesByCode[SFObjCTypeSelector]; 96 case '[': return OBJC_TYPE(Array, encoding, @"array", 0, None); 97 case '{': return OBJC_TYPE(Structure, encoding, @"structure", 0, None); 98 case '(': return OBJC_TYPE(Union, encoding, @"union", 0, None); 99 case 'b': return OBJC_TYPE(Bitfield, encoding, @"bitfield", 0, None); 100 case '^': return OBJC_TYPE(Pointer, encoding, @"pointer", sizeof(void*), None); 101 case '?': 102 default: 103 return [[SFObjCType alloc] initWithCode:SFObjCTypeUnknown encoding:encoding name:@"unknown" className:nil size:0 flags:0]; 104 } 105 } 106 107 + (SFObjCType *)typeForValue:(NSValue *)value { 108 NS_VALID_UNTIL_END_OF_SCOPE NSValue *arcSafeValue = value; 109 return [SFObjCType typeForEncoding:[arcSafeValue objCType]]; 110 } 111 112 - (id)initWithCode:(SFObjCTypeCode)code encoding:(NSString *)encoding name:(NSString *)name className:(NSString *)className size:(NSUInteger)size flags:(NSUInteger)flags { 113 if ((self = [super init])) { 114 _code = code; 115 _encoding = encoding; 116 _name = name; 117 _className = className; 118 _size = size; 119 _flags = flags; 120 } 121 return self; 122 } 123 124 - (BOOL)isNumber { 125 return (_flags & SFObjCTypeFlagNumberMask) != 0; 126 } 127 128 - (BOOL)isIntegerNumber { 129 return (_flags & SFObjCTypeFlagIntegerNumber) != 0; 130 } 131 132 - (BOOL)isFloatingPointNumber { 133 return (_flags & SFObjCTypeFlagFloatingPointNumber) != 0; 134 } 135 136 - (BOOL)isObject { 137 return _code == SFObjCTypeObject; 138 } 139 140 - (id)objectWithBytes:(const void *)bytes { 141 switch (_code) { 142 case SFObjCTypeChar: return [NSNumber numberWithChar:*((const char *)bytes)]; 143 case SFObjCTypeShort: return [NSNumber numberWithShort:*((const short *)bytes)]; 144 case SFObjCTypeInt: return [NSNumber numberWithInt:*((const int *)bytes)]; 145 case SFObjCTypeLong: return [NSNumber numberWithLong:*((const long *)bytes)]; 146 case SFObjCTypeLongLong: return [NSNumber numberWithLongLong:*((const long long *)bytes)]; 147 case SFObjCTypeUnsignedChar: return [NSNumber numberWithUnsignedChar:*((const unsigned char *)bytes)]; 148 case SFObjCTypeUnsignedShort: return [NSNumber numberWithUnsignedShort:*((const unsigned short *)bytes)]; 149 case SFObjCTypeUnsignedInt: return [NSNumber numberWithUnsignedInt:*((const unsigned int *)bytes)]; 150 case SFObjCTypeUnsignedLong: return [NSNumber numberWithUnsignedLong:*((const unsigned long *)bytes)]; 151 case SFObjCTypeUnsignedLongLong: return [NSNumber numberWithUnsignedLongLong:*((const unsigned long long *)bytes)]; 152 case SFObjCTypeFloat: return [NSNumber numberWithFloat:*((const float *)bytes)]; 153 case SFObjCTypeDouble: return [NSNumber numberWithDouble:*((const double *)bytes)]; 154 case SFObjCTypeBool: return [NSNumber numberWithBool:(BOOL)*((const _Bool *)bytes)]; 155 case SFObjCTypeObject: return (__bridge id)((const void *)(*((uintptr_t *)bytes))); 156 default: 157 [NSException raise:NSInternalInconsistencyException format:@"For class %@, Unsupported boxing type: %@", _className, _name]; 158 return nil; 159 } 160 } 161 162 - (void)getBytes:(void *)bytes forObject:(id)object { 163 if ([object isKindOfClass:[NSValue class]]) { 164 [object getValue:bytes]; 165 } else { 166 [NSException raise:NSInternalInconsistencyException format:@"Unsupported unboxing type: %@", _name]; 167 } 168 } 169 170 @end 171 172 #endif