Created
June 16, 2011 05:06
-
-
Save nihilistzsche/1028704 to your computer and use it in GitHub Desktop.
C struct box/unbox for Silver
This file contains hidden or 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
id sv_vm_box(SVStructBoxData* boxData, void* objc_value) { | |
id object = class_createInstance(NSClassFromString(boxData.name), 0); | |
for(SVStructOffsetData* offset in boxData.offsetData) { | |
void* data = objc_value+offset.offset; | |
id f_value = get_sv_value_from_objc_value(data, [offset.typeEncoding UTF8String]); | |
object_setInstanceVariable(object, [offset.fieldName UTF8String], f_value); | |
} | |
return object; | |
} | |
void * sv_vm_unbox(void* objc_value,SVStructBoxData* boxData,id sv_value) { | |
void * object = malloc(boxData.size); | |
for(SVStructOffsetData* offset in boxData.offsetData) { | |
id val; | |
object_getInstanceVariable(sv_value, [offset.fieldName UTF8String], (void**)&val); | |
void * c_val = value_buffer_for_objc_type([offset.typeEncoding UTF8String]); | |
set_objc_value_from_sv_value(c_val, val, [offset.typeEncoding UTF8String]); | |
void * ptr = object + offset.offset; | |
ptr = c_val; | |
} | |
return object; | |
} | |
void sv_vm_create_box_for_struct_type( NSString * typeEncoding ) { | |
if(!sv_struct_box_data) | |
sv_struct_box_data = [NSMutableDictionary dictionary]; | |
if([typeEncoding rangeOfString:@"\""].location == NSNotFound) | |
return; | |
typeEncoding = [typeEncoding substringFromIndex:1]; | |
NSScanner * typeScanner = [NSScanner scannerWithString:typeEncoding]; | |
NSString * typeName = nil; | |
NSString * className = nil; | |
[typeScanner scanUpToString:@"=" intoString:&typeName]; | |
[typeScanner scanString:@"=" intoString:NULL]; | |
if([sv_struct_box_data objectForKey:typeName]) | |
return; | |
className = [typeName hasPrefix:@"_"] ? [typeName substringFromIndex:1] : typeName; | |
if(NSClassFromString(className)) | |
return; | |
long currentOffset = 0; | |
NSMutableArray * boxData = [NSMutableArray array]; | |
Class _boxClass = objc_allocateClassPair([NSObject class], [className UTF8String], 0); | |
while(![typeScanner isAtEnd]) { | |
NSString * fieldName = nil; | |
NSString * fieldEncoding = nil; | |
[typeScanner scanString:@"\"" intoString:NULL]; | |
[typeScanner scanUpToString:@"\"" intoString:&fieldName]; | |
[typeScanner scanString:@"\"" intoString:NULL]; | |
NSString * fieldData = [[typeScanner string] substringFromIndex:[typeScanner scanLocation]]; | |
if([fieldData hasPrefix:@"{"]) { | |
fieldData = [fieldData substringFromIndex:1]; | |
int bcount = 1; | |
NSMutableString * sdata = [NSMutableString stringWithString:@"{"]; | |
while(bcount) { | |
NSString * temp; | |
[typeScanner scanUpToString:@"}" intoString:&temp]; | |
[sdata appendString:temp]; | |
while([temp rangeOfString:@"{"].location != NSNotFound) { | |
bcount++; | |
temp = [temp substringFromIndex:([temp rangeOfString:@"{"].location + 1)]; | |
} | |
[typeScanner scanString:@"}" intoString:&temp]; | |
[sdata appendString:temp]; | |
bcount--; | |
} | |
fieldEncoding = sdata; | |
} else { | |
[typeScanner scanUpToString:@"\"" intoString:&fieldEncoding]; | |
if([typeScanner isAtEnd]) | |
fieldEncoding = [fieldEncoding substringToIndex:[fieldEncoding length]-1]; | |
} | |
ffi_type* type = ffi_type_for_objc_type([fieldEncoding UTF8String]); | |
long size = size_for_objc_type([fieldEncoding UTF8String]); | |
if(!class_addIvar(_boxClass, [fieldName UTF8String], sizeof(id), log2(sizeof(id)), @encode(id))) { | |
OCLog(@"silver",warning,@"Failed to add ivar %@ to boxing class...",fieldName); | |
} | |
if (!class_addMethod(_boxClass, NSSelectorFromString(fieldName), (IMP)__sv_stubPropertyGetter, "@@:")) { | |
OCLog(@"silver",warning,@"Failed to add get property for %@ to boxing class...",fieldName); | |
} | |
if (!class_addMethod(_boxClass, | |
NSSelectorFromString([NSString stringWithFormat:@"set%@:", | |
[fieldName capitalizedString]]), (IMP)__sv_stubPropertySetter, "v@:@")) { | |
OCLog(@"silver",warning,@"Failed to add set property %@ to boxing class...",fieldName); | |
} | |
SVStructOffsetData * offsetData = [[SVStructOffsetData alloc] init]; | |
offsetData.fieldName = fieldName; | |
offsetData.typeEncoding = fieldEncoding; | |
offsetData.offset = currentOffset; | |
offsetData.type = type; | |
currentOffset += size; | |
[boxData addObject:offsetData]; | |
} | |
objc_registerClassPair(_boxClass); | |
SVStructBoxData* data = [[SVStructBoxData alloc] init]; | |
data.name = typeName; | |
data.offsetData = boxData; | |
// Create the FFI type for the structure from the offset datas | |
ffi_type * ffi_st_type = (ffi_type*)malloc(sizeof(ffi_type*)); | |
[[NSGarbageCollector defaultCollector] disableCollectorForPointer:ffi_st_type]; | |
ffi_st_type->size = 0; | |
ffi_st_type->alignment = 0; | |
ffi_st_type->elements = (ffi_type**)malloc((boxData.count + 1) * sizeof(ffi_type*)); | |
int ix; | |
for(ix = 0; ix < boxData.count; ix++) { | |
if([(SVStructOffsetData*)[boxData objectAtIndex:ix] type]) | |
ffi_st_type->elements[ix] = [(SVStructOffsetData*)[boxData objectAtIndex:ix] type]; | |
else | |
ffi_st_type->elements[ix] = &ffi_type_void; | |
} | |
ffi_st_type->elements[ix] = NULL; | |
data.size = currentOffset; | |
data.type = ffi_st_type; | |
[sv_struct_box_data setObject:data forKey:typeName]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment