Last active
August 29, 2015 13:56
-
-
Save KosmicTask/9198239 to your computer and use it in GitHub Desktop.
NSNumber subclass example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// DBNumber.h | |
// Dubrovnik | |
// | |
// Created by Jonathan Mitchell on 24/02/2014. | |
// | |
// | |
#import <Foundation/Foundation.h> | |
#import "DBMonoIncludes.h" | |
@interface DBNumber : NSNumber | |
/*! | |
Factory methods | |
*/ | |
+ (instancetype)dbNumberWithChar:(char)value; | |
+ (instancetype)dbNumberWithUnsignedChar:(unsigned char)value; | |
+ (instancetype)dbNumberWithShort:(short)value; | |
+ (instancetype)dbNumberWithUnsignedShort:(unsigned short)value; | |
+ (instancetype)dbNumberWithInt:(int)value; | |
+ (instancetype)dbNumberWithUnsignedInt:(unsigned int)value; | |
+ (instancetype)dbNumberWithLong:(long)value; | |
+ (instancetype)dbNumberWithUnsignedLong:(unsigned long)value; | |
+ (instancetype)dbNumberWithLongLong:(long long)value; | |
+ (instancetype)dbNumberWithUnsignedLongLong:(unsigned long long)value; | |
+ (instancetype)dbNumberWithFloat:(float)value; | |
+ (instancetype)dbNumberWithDouble:(double)value; | |
+ (instancetype)dbNumberWithBool:(BOOL)value; | |
+ (instancetype)dbNumberWithInteger:(NSInteger)value; | |
+ (instancetype)dbNumberWithUnsignedInteger:(NSUInteger)value; | |
/*! | |
Return a pointer to the stored value. | |
The pointed to value will be of encoded type -monoObjCType | |
*/ | |
- (const void *)valuePointer NS_RETURNS_INNER_POINTER; | |
- (void *)monoValue; | |
@property (assign, nonatomic, readonly) MonoObject *monoObject; | |
@property (assign, nonatomic, readonly) const char *monoObjCType; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// DBNumber.m | |
// Dubrovnik | |
// | |
// Created by Jonathan Mitchell on 24/02/2014. | |
// | |
// | |
#import "DBNumber.h" | |
#import "DBBoxing.h" | |
#define DB_INIT_INSTANCE \ | |
self = [super init]; \ | |
if (self) { self.monoObjCType = @encode(typeof(value)); self.number = @(value);}\ | |
return self; | |
typedef NS_ENUM(NSUInteger, DBNumberTypeID) { | |
DBNumberTypeBool, | |
DBNumberTypeChar, | |
DBNumberTypeUnsignedChar, | |
DBNumberTypeShort, | |
DBNumberTypeUnsignedShort, | |
DBNumberTypeInt, | |
DBNumberTypeUnsignedInt, | |
DBNumberTypeLong, | |
DBNumberTypeUnsignedLong, | |
DBNumberTypeLongLong, | |
DBNumberTypeUnsignedLongLong, | |
DBNumberTypeFloat, | |
DBNumberTypeDouble, | |
}; | |
@interface DBNumber() | |
@property (strong) NSNumber *number; | |
@property (strong) NSString *typeName; | |
@property (strong) NSData *valueData; | |
@property (assign, nonatomic, readwrite) const char *monoObjCType; | |
@property (assign, nonatomic, readwrite) MonoObject *monoObject; | |
@end | |
@implementation DBNumber | |
#pragma mark + | |
#pragma mark Factory | |
+ (instancetype)dbNumberWithChar:(char)value | |
{ | |
return [[self alloc] initWithChar:value]; | |
} | |
+ (instancetype)dbNumberWithUnsignedChar:(unsigned char)value | |
{ | |
return [[self alloc] initWithUnsignedChar:value]; | |
} | |
+ (instancetype)dbNumberWithShort:(short)value | |
{ | |
return [[self alloc] initWithShort:value]; | |
} | |
+ (instancetype)dbNumberWithUnsignedShort:(unsigned short)value | |
{ | |
return [[self alloc] initWithUnsignedShort:value]; | |
} | |
+ (instancetype)dbNumberWithInt:(int)value | |
{ | |
return [[self alloc] initWithInt:value]; | |
} | |
+ (instancetype)dbNumberWithUnsignedInt:(unsigned int)value | |
{ | |
return [[self alloc] initWithUnsignedInt:value]; | |
} | |
+ (instancetype)dbNumberWithLong:(long)value | |
{ | |
return [[self alloc] initWithLong:value]; | |
} | |
+ (instancetype)dbNumberWithUnsignedLong:(unsigned long)value | |
{ | |
return [[self alloc] initWithUnsignedLong:value]; | |
} | |
+ (instancetype)dbNumberWithLongLong:(long long)value | |
{ | |
return [[self alloc] initWithLongLong:value]; | |
} | |
+ (instancetype)dbNumberWithUnsignedLongLong:(unsigned long long)value | |
{ | |
return [[self alloc] initWithUnsignedLongLong:value]; | |
} | |
+ (instancetype)dbNumberWithFloat:(float)value | |
{ | |
return [[self alloc] initWithFloat:value]; | |
} | |
+ (instancetype)dbNumberWithDouble:(double)value | |
{ | |
return [[self alloc] initWithDouble:value]; | |
} | |
+ (instancetype)dbNumberWithBool:(BOOL)value | |
{ | |
return [[self alloc] initWithBool:value]; | |
} | |
+ (instancetype)dbNumberWithInteger:(NSInteger)value | |
{ | |
return [[self alloc] initWithInteger:value]; | |
} | |
+ (instancetype)dbNumberWithUnsignedInteger:(NSUInteger)value | |
{ | |
return [[self alloc] initWithUnsignedInteger:value]; | |
} | |
#pragma mark - | |
#pragma mark Type support | |
+ (NSDictionary *)typeIndexDictionary | |
{ | |
static NSDictionary *dict = nil; | |
if (!dict) { | |
dict = @{ | |
@(@encode(BOOL)): @(DBNumberTypeBool), | |
@(@encode(char)): @(DBNumberTypeChar), | |
@(@encode(unsigned char)): @(DBNumberTypeUnsignedChar), | |
@(@encode(short)): @(DBNumberTypeShort), | |
@(@encode(unsigned short)): @(DBNumberTypeUnsignedShort), | |
@(@encode(int)): @(DBNumberTypeInt), | |
@(@encode(unsigned int)): @(DBNumberTypeUnsignedInt), | |
@(@encode(long)): @(DBNumberTypeLong), | |
@(@encode(unsigned long)): @(DBNumberTypeUnsignedLong), | |
@(@encode(long long)): @(DBNumberTypeLongLong), | |
@(@encode(unsigned long long)): @(DBNumberTypeUnsignedLongLong), | |
@(@encode(float)): @(DBNumberTypeFloat), | |
@(@encode(double)): @(DBNumberTypeDouble), | |
}; | |
} | |
return dict; | |
} | |
+ (DBNumberTypeID)numberTypeIDForTypeName:(NSString *)typeName | |
{ | |
NSNumber *typeID = [self typeIndexDictionary][typeName]; | |
if (!typeID) { | |
[NSException raise:@"Type exception" format:@"Invalid type name encoding: %@", typeName]; | |
} | |
return [typeID unsignedIntegerValue]; | |
} | |
#pragma mark - | |
#pragma mark NSValue primitive methods | |
- (void)getValue:(void *)value | |
{ | |
[self.number getValue:value]; | |
} | |
- (const char *)objCType | |
{ | |
return [self.number objCType]; | |
} | |
#pragma mark - | |
#pragma mark NSNumber primitive methods | |
- (char)charValue | |
{ | |
return [self.number charValue]; | |
} | |
- (unsigned char)unsignedCharValue | |
{ | |
return [self.number unsignedCharValue]; | |
} | |
- (short)shortValue | |
{ | |
return [self.number shortValue]; | |
} | |
- (unsigned short)unsignedShortValue | |
{ | |
return [self.number unsignedShortValue]; | |
} | |
- (int)intValue | |
{ | |
return [self.number intValue]; | |
} | |
- (unsigned int)unsignedIntValue | |
{ | |
return [self.number unsignedIntValue]; | |
} | |
- (long)longValue | |
{ | |
return [self.number longValue]; | |
} | |
- (unsigned long)unsignedLongValue | |
{ | |
return [self.number unsignedLongValue]; | |
} | |
- (long long)longLongValue | |
{ | |
return [self.number unsignedLongValue]; | |
} | |
- (unsigned long long)unsignedLongLongValue | |
{ | |
return [self.number unsignedLongLongValue]; | |
} | |
- (float)floatValue | |
{ | |
return [self.number floatValue]; | |
} | |
- (double)doubleValue | |
{ | |
return [self.number doubleValue]; | |
} | |
- (BOOL)boolValue | |
{ | |
return [self.number boolValue]; | |
} | |
- (NSInteger)integerValue | |
{ | |
return [self.number integerValue]; | |
} | |
- (NSUInteger)unsignedIntegerValue | |
{ | |
return [self.number integerValue]; | |
} | |
#pragma mark - | |
#pragma mark NSNumber primitive initialisers | |
- (id)initWithChar:(char)value | |
{ | |
DB_INIT_INSTANCE | |
} | |
- (id)initWithUnsignedChar:(unsigned char)value | |
{ | |
DB_INIT_INSTANCE | |
} | |
- (id)initWithShort:(short)value | |
{ | |
DB_INIT_INSTANCE | |
} | |
- (id)initWithUnsignedShort:(unsigned short)value | |
{ | |
DB_INIT_INSTANCE | |
} | |
- (id)initWithInt:(int)value | |
{ | |
DB_INIT_INSTANCE | |
} | |
- (id)initWithUnsignedInt:(unsigned int)value | |
{ | |
DB_INIT_INSTANCE | |
} | |
- (id)initWithLong:(long)value | |
{ | |
DB_INIT_INSTANCE | |
} | |
- (id)initWithUnsignedLong:(unsigned long)value | |
{ | |
DB_INIT_INSTANCE | |
} | |
- (id)initWithLongLong:(long long)value | |
{ | |
DB_INIT_INSTANCE | |
} | |
- (id)initWithUnsignedLongLong:(unsigned long long)value | |
{ | |
DB_INIT_INSTANCE | |
} | |
- (id)initWithFloat:(float)value | |
{ | |
DB_INIT_INSTANCE | |
} | |
- (id)initWithDouble:(double)value | |
{ | |
DB_INIT_INSTANCE | |
} | |
- (id)initWithBool:(BOOL)value | |
{ | |
DB_INIT_INSTANCE | |
} | |
- (id)initWithInteger:(NSInteger)value | |
{ | |
DB_INIT_INSTANCE | |
} | |
- (id)initWithUnsignedInteger:(NSUInteger)value | |
{ | |
DB_INIT_INSTANCE | |
} | |
#pragma mark - | |
#pragma mark NSNumber primitives | |
- (NSComparisonResult)compare:(NSNumber *)otherNumber | |
{ | |
return [self.number compare:otherNumber]; | |
} | |
- (BOOL)isEqualToNumber:(NSNumber *)number | |
{ | |
return [self.number isEqualToNumber:number]; | |
} | |
- (NSString *)descriptionWithLocale:(id)locale | |
{ | |
return [self.number descriptionWithLocale:locale]; | |
} | |
#pragma mark - | |
#pragma mark Mono support | |
- (const void *)valuePointer | |
{ | |
if (!self.valueData) { | |
void *valuePtr = NULL; | |
// get type identifier | |
DBNumberTypeID typeID = [[self class] numberTypeIDForTypeName:self.typeName]; | |
switch (typeID) { | |
case DBNumberTypeBool: | |
{ | |
BOOL value = [self boolValue]; | |
valuePtr = &value; | |
break; | |
} | |
case DBNumberTypeChar: | |
{ | |
char value = [self charValue]; | |
valuePtr = &value; | |
break; | |
} | |
case DBNumberTypeUnsignedChar: | |
{ | |
unsigned char value = [self unsignedCharValue]; | |
valuePtr = &value; | |
break; | |
} | |
case DBNumberTypeShort: | |
{ | |
short value = [self shortValue]; | |
valuePtr = &value; | |
break; | |
} | |
case DBNumberTypeUnsignedShort: | |
{ | |
unsigned short value = [self unsignedShortValue]; | |
valuePtr = &value; | |
break; | |
} | |
case DBNumberTypeInt: | |
{ | |
int value = [self intValue]; | |
valuePtr = &value; | |
break; | |
} | |
case DBNumberTypeUnsignedInt: | |
{ | |
unsigned int value = [self unsignedIntValue]; | |
valuePtr = &value; | |
break; | |
} | |
case DBNumberTypeLong: | |
{ | |
long value = [self longValue]; | |
valuePtr = &value; | |
break; | |
} | |
case DBNumberTypeUnsignedLong: | |
{ | |
unsigned long value = [self unsignedLongValue]; | |
valuePtr = &value; | |
break; | |
} | |
case DBNumberTypeLongLong: | |
{ | |
long long value = [self longLongValue]; | |
valuePtr = &value; | |
break; | |
} | |
case DBNumberTypeUnsignedLongLong: | |
{ | |
unsigned long long value = [self unsignedLongLongValue]; | |
valuePtr = &value; | |
break; | |
} | |
case DBNumberTypeFloat: | |
{ | |
float value = [self floatValue]; | |
valuePtr = &value; | |
break; | |
} | |
case DBNumberTypeDouble: | |
{ | |
double value = [self doubleValue]; | |
valuePtr = &value; | |
break; | |
} | |
default: | |
{ | |
[NSException raise:@"Type exception" format:@"Cannot create MonoObject for type name: %@", self.typeName]; | |
} | |
} | |
// copy to buffer | |
NSUInteger typeSize; | |
NSGetSizeAndAlignment(self.monoObjCType, &typeSize, NULL); | |
self.valueData = [NSData dataWithBytes:valuePtr length:typeSize]; | |
} | |
// return interior pointer | |
return [self.valueData bytes]; | |
} | |
- (void *)monoValue | |
{ | |
return (void *)[self valuePointer]; | |
} | |
- (MonoObject *)monoObject | |
{ | |
if (!_monoObject) { | |
DBNumberTypeID typeID = [[self class] numberTypeIDForTypeName:self.typeName]; | |
switch (typeID) { | |
case DBNumberTypeBool: | |
{ | |
BOOL value = [self boolValue]; | |
self.monoObject = DB_BOX_BOOLEAN(value); | |
break; | |
} | |
case DBNumberTypeChar: | |
{ | |
char value = [self charValue]; | |
self.monoObject = DB_BOX_INT8(value); | |
break; | |
} | |
case DBNumberTypeUnsignedChar: | |
{ | |
unsigned char value = [self unsignedCharValue]; | |
self.monoObject = DB_BOX_UINT8(value); | |
break; | |
} | |
case DBNumberTypeShort: | |
{ | |
short value = [self shortValue]; | |
self.monoObject = DB_BOX_INT16(value); | |
break; | |
} | |
case DBNumberTypeUnsignedShort: | |
{ | |
unsigned short value = [self unsignedShortValue]; | |
self.monoObject = DB_BOX_UINT16(value); | |
break; | |
} | |
case DBNumberTypeInt: | |
{ | |
int value = [self intValue]; | |
self.monoObject = DB_BOX_INT32(value); | |
break; | |
} | |
case DBNumberTypeUnsignedInt: | |
{ | |
unsigned int value = [self unsignedIntValue]; | |
self.monoObject = DB_BOX_UINT32(value); | |
break; | |
} | |
case DBNumberTypeLong: | |
{ | |
long value = [self longValue]; | |
self.monoObject = DB_BOX_INT32(value); | |
break; | |
} | |
case DBNumberTypeUnsignedLong: | |
{ | |
unsigned long value = [self unsignedLongValue]; | |
self.monoObject = DB_BOX_UINT32(value); | |
break; | |
} | |
case DBNumberTypeLongLong: | |
{ | |
long long value = [self longLongValue]; | |
self.monoObject = DB_BOX_INT64(value); | |
break; | |
} | |
case DBNumberTypeUnsignedLongLong: | |
{ | |
unsigned long long value = [self unsignedLongLongValue]; | |
self.monoObject = DB_BOX_UINT64(value); | |
break; | |
} | |
case DBNumberTypeFloat: | |
{ | |
float value = [self floatValue]; | |
self.monoObject = DB_BOX_FLOAT(value); | |
break; | |
} | |
case DBNumberTypeDouble: | |
{ | |
double value = [self doubleValue]; | |
self.monoObject = DB_BOX_DOUBLE(value); | |
break; | |
} | |
default: | |
{ | |
[NSException raise:@"Type exception" format:@"Cannot create MonoObject for type name: %@", self.typeName]; | |
} | |
} | |
} | |
return _monoObject; | |
} | |
#pragma mark - | |
#pragma mark Accessors | |
-(void)setMonoObjCType:(const char *)monoObjCType | |
{ | |
_monoObjCType = monoObjCType; | |
self.typeName = @(_monoObjCType); | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment