Skip to content

Instantly share code, notes, and snippets.

@nihilistzsche
Created June 16, 2011 05:06
Show Gist options
  • Save nihilistzsche/1028704 to your computer and use it in GitHub Desktop.
Save nihilistzsche/1028704 to your computer and use it in GitHub Desktop.
C struct box/unbox for Silver
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