| Index: third_party/ocmock/OCMock/NSValue+OCMAdditions.m
|
| diff --git a/third_party/ocmock/OCMock/NSValue+OCMAdditions.m b/third_party/ocmock/OCMock/NSValue+OCMAdditions.m
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..15ea17ad4587131cfcac4fb0aac93f3a013d9257
|
| --- /dev/null
|
| +++ b/third_party/ocmock/OCMock/NSValue+OCMAdditions.m
|
| @@ -0,0 +1,152 @@
|
| +/*
|
| + * Copyright (c) 2014-2015 Erik Doernenburg and contributors
|
| + *
|
| + * Licensed under the Apache License, Version 2.0 (the "License"); you may
|
| + * not use these files 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.
|
| + */
|
| +
|
| +#import "NSValue+OCMAdditions.h"
|
| +
|
| +@implementation NSValue (OCMAdditions)
|
| +
|
| +static CFNumberType OCMNumberTypeForObjCType(const char* objcType) {
|
| + switch (objcType[0]) {
|
| + case 'c':
|
| + return kCFNumberCharType;
|
| + case 'C':
|
| + return kCFNumberCharType;
|
| + case 'B':
|
| + return kCFNumberCharType;
|
| + case 's':
|
| + return kCFNumberShortType;
|
| + case 'S':
|
| + return kCFNumberShortType;
|
| + case 'i':
|
| + return kCFNumberIntType;
|
| + case 'I':
|
| + return kCFNumberIntType;
|
| + case 'l':
|
| + return kCFNumberLongType;
|
| + case 'L':
|
| + return kCFNumberLongType;
|
| + case 'q':
|
| + return kCFNumberLongLongType;
|
| + case 'Q':
|
| + return kCFNumberLongLongType;
|
| + case 'f':
|
| + return kCFNumberFloatType;
|
| + case 'd':
|
| + return kCFNumberDoubleType;
|
| + default:
|
| + return 0;
|
| + }
|
| +}
|
| +
|
| +static NSNumber* OCMNumberForValue(NSValue* value) {
|
| +#define CREATE_NUM(_type) \
|
| + ({ \
|
| + _type _v; \
|
| + [value getValue:&_v]; \
|
| + @(_v); \
|
| + })
|
| + switch ([value objCType][0]) {
|
| + case 'c':
|
| + return CREATE_NUM(char);
|
| + case 'C':
|
| + return CREATE_NUM(unsigned char);
|
| + case 'B':
|
| + return CREATE_NUM(bool);
|
| + case 's':
|
| + return CREATE_NUM(short);
|
| + case 'S':
|
| + return CREATE_NUM(unsigned short);
|
| + case 'i':
|
| + return CREATE_NUM(int);
|
| + case 'I':
|
| + return CREATE_NUM(unsigned int);
|
| + case 'l':
|
| + return CREATE_NUM(long);
|
| + case 'L':
|
| + return CREATE_NUM(unsigned long);
|
| + case 'q':
|
| + return CREATE_NUM(long long);
|
| + case 'Q':
|
| + return CREATE_NUM(unsigned long long);
|
| + case 'f':
|
| + return CREATE_NUM(float);
|
| + case 'd':
|
| + return CREATE_NUM(double);
|
| + default:
|
| + return nil;
|
| + }
|
| +}
|
| +
|
| +- (BOOL)getBytes:(void*)outputBuf objCType:(const char*)targetType {
|
| + /*
|
| + * See if they are similar number types, and if we can convert losslessly
|
| + * between them.
|
| + * For the most part, we set things up to use CFNumberGetValue, which returns
|
| + * false if
|
| + * conversion will be lossy.
|
| + */
|
| + CFNumberType inputType = OCMNumberTypeForObjCType([self objCType]);
|
| + CFNumberType outputType = OCMNumberTypeForObjCType(targetType);
|
| +
|
| + if (inputType == 0 || outputType == 0) // one or both are non-number types
|
| + return NO;
|
| +
|
| + NSNumber* inputNumber = [self isKindOfClass:[NSNumber class]]
|
| + ? (NSNumber*)self
|
| + : OCMNumberForValue(self);
|
| +
|
| + /*
|
| + * Due to some legacy, back-compatible requirements in CFNumber.c,
|
| + * CFNumberGetValue can return true for
|
| + * some conversions which should not be allowed (by reading source,
|
| + * conversions from integer types to
|
| + * 8-bit or 16-bit integer types). So, check ourselves.
|
| + */
|
| + long long min;
|
| + long long max;
|
| + long long val = [inputNumber longLongValue];
|
| + switch (targetType[0]) {
|
| + case 'B':
|
| + case 'c':
|
| + min = CHAR_MIN;
|
| + max = CHAR_MAX;
|
| + break;
|
| + case 'C':
|
| + min = 0;
|
| + max = UCHAR_MAX;
|
| + break;
|
| + case 's':
|
| + min = SHRT_MIN;
|
| + max = SHRT_MAX;
|
| + break;
|
| + case 'S':
|
| + min = 0;
|
| + max = USHRT_MAX;
|
| + break;
|
| + default:
|
| + min = LLONG_MIN;
|
| + max = LLONG_MAX;
|
| + break;
|
| + }
|
| + if (val < min || val > max)
|
| + return NO;
|
| +
|
| + /* Get the number, and return NO if the value was out of range or conversion
|
| + * was lossy */
|
| + return CFNumberGetValue((CFNumberRef)inputNumber, outputType, outputBuf);
|
| +}
|
| +
|
| +@end
|
|
|