使用FastCoder写缓存单例
FastCoder可以存储字典,数组,鄙人将FastCoder封装,CoreData可以缓存的东西,用这个都可以缓存,但是只适合缓存少量的数据(不适合存储几万条数据)。
使用详情:
源码:
使用的缓存文件
SharedFile.h 与 SharedFile.m
//
// SharedFile.h
// Array
//
// Created by YouXianMing on 14/12/1.
// Copyright (c) 2014年 YouXianMing. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface SharedFile : NSObject
/**
* 存储数组
*
* @return YES,成功,NO,失败
*/
+ (BOOL)storeArray;
/**
* 返回原始的可以修改的数组
*
* @return 原始可以修改的数组
*/
+ (NSMutableArray *)sharedOriginalArray;
/**
* 返回原始数组的拷贝
*
* @return 原始数组的拷贝
*/
+ (NSMutableArray *)sharedCopiedArray;
@end
//
// SharedFile.m
// Array
//
// Created by YouXianMing on 14/12/1.
// Copyright (c) 2014年 YouXianMing. All rights reserved.
//
#import "SharedFile.h"
#import "NSString+File.h"
#import "NSObject+FastCoder.h"
static NSString *filePath = @"/Library/Caches/YouXianMing";
NSMutableArray *storedArray = nil;
@implementation SharedFile
+ (void)initialize {
if (self == [SharedFile class]) {
if ([filePath exist] == NO) {
storedArray = [NSMutableArray array];
} else {
storedArray = [@"SharedFile" useFastCoderToRecoverFromFilePath:[filePath path]];
}
}
}
+ (BOOL)storeArray {
return [storedArray useFastCoderToWriteToFilePath:[filePath path]];
}
+ (NSMutableArray *)sharedOriginalArray {
return storedArray;
}
+ (NSMutableArray *)sharedCopiedArray {
return [NSMutableArray arrayWithArray:storedArray];
}
@end
FastCoder.h 与 FastCoder.m
//
// FastCoding.h
//
// Version 3.0.2
//
// Created by Nick Lockwood on 09/12/2013.
// Copyright (c) 2013 Charcoal Design
//
// Distributed under the permissive zlib License
// Get the latest version from here:
//
// https://github.com/nicklockwood/FastCoding
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
#import <Foundation/Foundation.h>
extern NSString *const FastCodingException;
@interface NSObject (FastCoding)
+ (NSArray *)fastCodingKeys;
- (id)awakeAfterFastCoding;
- (Class)classForFastCoding;
- (BOOL)preferFastCoding;
@end
@interface FastCoder : NSObject
+ (id)objectWithData:(NSData *)data;
+ (id)propertyListWithData:(NSData *)data;
+ (NSData *)dataWithRootObject:(id)object;
@end
//
// FastCoding.m
//
// Version 3.0.2
//
// Created by Nick Lockwood on 09/12/2013.
// Copyright (c) 2013 Charcoal Design
//
// Distributed under the permissive zlib License
// Get the latest version from here:
//
// https://github.com/nicklockwood/FastCoding
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
#import "FastCoder.h"
#import <objc/runtime.h>
#import <CoreGraphics/CoreGraphics.h>
#import <Availability.h>
#if __has_feature(objc_arc)
#pragma clang diagnostic ignored "-Wpedantic"
#warning FastCoding runs slower under ARC. It is recommended that you disable it for this file
#endif
#pragma clang diagnostic ignored "-Wgnu"
#pragma clang diagnostic ignored "-Wpointer-arith"
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#pragma clang diagnostic ignored "-Wfour-char-constants"
#pragma clang diagnostic ignored "-Wobjc-missing-property-synthesis"
#pragma clang diagnostic ignored "-Wdirect-ivar-access"
NSString *const FastCodingException = @"FastCodingException";
static const uint32_t FCIdentifier = 'FAST';
static const uint16_t FCMajorVersion = 3;
static const uint16_t FCMinorVersion = 0;
typedef struct
{
uint32_t identifier;
uint16_t majorVersion;
uint16_t minorVersion;
}
FCHeader;
typedef NS_ENUM(uint8_t, FCType)
{
FCTypeNil = 0,
FCTypeNull,
FCTypeObjectAlias8,
FCTypeObjectAlias16,
FCTypeObjectAlias32,
FCTypeStringAlias8,
FCTypeStringAlias16,
FCTypeStringAlias32,
FCTypeString,
FCTypeDictionary,
FCTypeArray,
FCTypeSet,
FCTypeOrderedSet,
FCTypeTrue,
FCTypeFalse,
FCTypeInt8,
FCTypeInt16,
FCTypeInt32,
FCTypeInt64,
FCTypeFloat32,
FCTypeFloat64,
FCTypeData,
FCTypeDate,
FCTypeMutableString,
FCTypeMutableDictionary,
FCTypeMutableArray,
FCTypeMutableSet,
FCTypeMutableOrderedSet,
FCTypeMutableData,
FCTypeClassDefinition,
FCTypeObject8,
FCTypeObject16,
FCTypeObject32,
FCTypeURL,
FCTypePoint,
FCTypeSize,
FCTypeRect,
FCTypeRange,
FCTypeVector,
FCTypeAffineTransform,
FCType3DTransform,
FCTypeMutableIndexSet,
FCTypeIndexSet,
FCTypeNSCodedObject,
FCTypeCount // sentinel value
};
#if !__has_feature(objc_arc)
#define FC_AUTORELEASE(x) [(x) autorelease]
#else
#define FC_AUTORELEASE(x) (x)
#endif
#import <TargetConditionals.h>
#if TARGET_OS_IPHONE
#define OR_IF_MAC(x)
#else
#define OR_IF_MAC(x) || (x)
#endif
#define FC_ASSERT_FITS(length, offset, total) { if ((NSUInteger)((offset) + (length)) > (total)) \
[NSException raise:FastCodingException format:@"Unexpected EOF when parsing object starting at %i", (int32_t)(offset)]; }
#define FC_READ_VALUE(type, offset, input, total) type value; { \
FC_ASSERT_FITS (sizeof(type), offset, total); \
value = *(type *)(input + offset); \
offset += sizeof(value); }
#define FC_ALIGN_INPUT(type, offset) { \
unsigned long align = offset % sizeof(type); \
if (align) offset += sizeof(type) - align; }
#define FC_ALIGN_OUTPUT(type, output) { \
unsigned long align = [output length] % sizeof(type); \
if (align) [output increaseLengthBy:sizeof(type) - align]; }
@interface FCNSCoder : NSCoder
@end
@interface FCNSCoder ()
{
@public
__unsafe_unretained id _rootObject;
__unsafe_unretained NSMutableData *_output;
__unsafe_unretained NSMutableDictionary *_objectCache;
__unsafe_unretained NSMutableDictionary *_classCache;
__unsafe_unretained NSMutableDictionary *_stringCache;
__unsafe_unretained NSMutableDictionary *_classesByName;
}
@end
@interface FCNSDecoder : NSCoder
@end
typedef id FCTypeConstructor(FCNSDecoder *);
@interface FCNSDecoder ()
{
@public
NSUInteger *_offset;
const void *_input;
NSUInteger _total;
FCTypeConstructor **_constructors;
__unsafe_unretained NSData *_objectCache;
__unsafe_unretained NSData *_classCache;
__unsafe_unretained NSData *_stringCache;
__unsafe_unretained NSMutableArray *_propertyDictionaryPool;
__unsafe_unretained NSMutableDictionary *_properties;
}
@end
@interface FCClassDefinition : NSObject
@end
@interface FCClassDefinition ()
{
@public
__unsafe_unretained NSString *_className;
__unsafe_unretained NSArray *_propertyKeys;
}
@end
@interface NSObject (FastCoding_Private)
- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder;
@end
static inline NSUInteger FCCacheReadObject(__unsafe_unretained id object, __unsafe_unretained NSData *cache)
{
NSUInteger offset = (NSUInteger)CFDataGetLength((__bridge CFMutableDataRef)cache);
CFDataAppendBytes((__bridge CFMutableDataRef)cache, (void *)&object, sizeof(id));
return offset;
}
static inline void FCReplaceCachedObject(NSUInteger index, __unsafe_unretained id object, __unsafe_unretained NSData *cache)
{
CFDataReplaceBytes((__bridge CFMutableDataRef)cache, CFRangeMake((CFIndex)index, sizeof(id)), (void *)&object, sizeof(id));
}
static inline id FCCachedObjectAtIndex(NSUInteger index, __unsafe_unretained NSData *cache)
{
return ((__unsafe_unretained id *)(void *)CFDataGetBytePtr((__bridge CFMutableDataRef)cache))[index];
}
static id FCReadObject(__unsafe_unretained FCNSDecoder *decoder);
static id FCReadObject_2_3(__unsafe_unretained FCNSDecoder *decoder);
static inline uint8_t FCReadType(__unsafe_unretained FCNSDecoder *decoder)
{
FC_READ_VALUE(uint8_t, *decoder->_offset, decoder->_input, decoder->_total);
return value;
}
static inline uint8_t FCReadRawUInt8(__unsafe_unretained FCNSDecoder *decoder)
{
FC_READ_VALUE(uint8_t, *decoder->_offset, decoder->_input, decoder->_total);
return value;
}
static inline uint16_t FCReadRawUInt16(__unsafe_unretained FCNSDecoder *decoder)
{
FC_READ_VALUE(uint16_t, *decoder->_offset, decoder->_input, decoder->_total);
return value;
}
static inline uint32_t FCReadRawUInt32(__unsafe_unretained FCNSDecoder *decoder)
{
FC_READ_VALUE(uint32_t, *decoder->_offset, decoder->_input, decoder->_total);
return value;
}
static inline double FCReadRawDouble(__unsafe_unretained FCNSDecoder *decoder)
{
FC_READ_VALUE(double_t, *decoder->_offset, decoder->_input, decoder->_total);
return value;
}
static id FCReadRawString(__unsafe_unretained FCNSDecoder *decoder)
{
__autoreleasing NSString *string = nil;
NSUInteger length = strlen(decoder->_input + *decoder->_offset) + 1;
FC_ASSERT_FITS(length, *decoder->_offset, decoder->_total);
if (length > 1)
{
string = CFBridgingRelease(CFStringCreateWithBytes(NULL, decoder->_input + *decoder->_offset,
(CFIndex)length - 1, kCFStringEncodingUTF8, false));
}
else
{
string = @"";
}
*decoder->_offset += length;
return string;
}
static id FCReadNil(__unused __unsafe_unretained FCNSDecoder *decoder)
{
return nil;
}
static id FCReadNull(__unused __unsafe_unretained FCNSDecoder *decoder)
{
return [NSNull null];
}
static id FCReadAlias8(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(uint8_t, *decoder->_offset);
return FCCachedObjectAtIndex(FCReadRawUInt8(decoder), decoder->_objectCache);
}
static id FCReadAlias16(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(uint16_t, *decoder->_offset);
return FCCachedObjectAtIndex(FCReadRawUInt16(decoder), decoder->_objectCache);
}
static id FCReadAlias32(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(uint32_t, *decoder->_offset);
return FCCachedObjectAtIndex(FCReadRawUInt32(decoder), decoder->_objectCache);
}
static id FCReadStringAlias8(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(uint8_t, *decoder->_offset);
return FCCachedObjectAtIndex(FCReadRawUInt8(decoder), decoder->_stringCache);
}
static id FCReadStringAlias16(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(uint16_t, *decoder->_offset);
return FCCachedObjectAtIndex(FCReadRawUInt16(decoder), decoder->_stringCache);
}
static id FCReadStringAlias32(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(uint32_t, *decoder->_offset);
return FCCachedObjectAtIndex(FCReadRawUInt32(decoder), decoder->_stringCache);
}
static id FCReadString(__unsafe_unretained FCNSDecoder *decoder)
{
NSString *string = FCReadRawString(decoder);
FCCacheReadObject(string, decoder->_stringCache);
return string;
}
static id FCReadMutableString(__unsafe_unretained FCNSDecoder *decoder)
{
__autoreleasing NSMutableString *string = nil;
NSUInteger length = strlen(decoder->_input + *decoder->_offset) + 1;
FC_ASSERT_FITS(length, *decoder->_offset, decoder->_total);
if (length > 1)
{
string = FC_AUTORELEASE([[NSMutableString alloc] initWithBytes:decoder->_input + *decoder->_offset length:length - 1 encoding:NSUTF8StringEncoding]);
}
else
{
string = [NSMutableString string];
}
*decoder->_offset += length;
FCCacheReadObject(string, decoder->_objectCache);
return string;
}
static id FCReadDictionary(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(uint32_t, *decoder->_offset);
uint32_t count = FCReadRawUInt32(decoder);
__autoreleasing NSDictionary *dict = nil;
if (count)
{
__autoreleasing id *keys = (__autoreleasing id *)malloc(count * sizeof(id));
__autoreleasing id *objects = (__autoreleasing id *)malloc(count * sizeof(id));
for (uint32_t i = 0; i < count; i++)
{
objects[i] = FCReadObject(decoder);
keys[i] = FCReadObject(decoder);
}
dict = [NSDictionary dictionaryWithObjects:objects forKeys:keys count:count];
free(objects);
free(keys);
}
else
{
dict = @{};
}
FCCacheReadObject(dict, decoder->_objectCache);
return dict;
}
static id FCReadMutableDictionary(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(uint32_t, *decoder->_offset);
uint32_t count = FCReadRawUInt32(decoder);
__autoreleasing NSMutableDictionary *dict = CFBridgingRelease(CFDictionaryCreateMutable(NULL, (CFIndex)count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
FCCacheReadObject(dict, decoder->_objectCache);
for (uint32_t i = 0; i < count; i++)
{
__autoreleasing id object = FCReadObject(decoder);
__autoreleasing id key = FCReadObject(decoder);
CFDictionarySetValue((__bridge CFMutableDictionaryRef)dict, (__bridge const void *)key, (__bridge const void *)object);
}
return dict;
}
static id FCReadArray(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(uint32_t, *decoder->_offset);
uint32_t count = FCReadRawUInt32(decoder);
__autoreleasing NSArray *array = nil;
if (count)
{
__autoreleasing id *objects = (__autoreleasing id *)malloc(count * sizeof(id));
for (uint32_t i = 0; i < count; i++)
{
objects[i] = FCReadObject(decoder);
}
array = [NSArray arrayWithObjects:objects count:count];
free(objects);
}
else
{
array = @[];
}
FCCacheReadObject(array, decoder->_objectCache);
return array;
}
static id FCReadMutableArray(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(uint32_t, *decoder->_offset);
uint32_t count = FCReadRawUInt32(decoder);
__autoreleasing NSMutableArray *array = [NSMutableArray arrayWithCapacity:count];
FCCacheReadObject(array, decoder->_objectCache);
for (uint32_t i = 0; i < count; i++)
{
CFArrayAppendValue((__bridge CFMutableArrayRef)array, (__bridge void *)FCReadObject(decoder));
}
return array;
}
static id FCReadSet(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(uint32_t, *decoder->_offset);
uint32_t count = FCReadRawUInt32(decoder);
__autoreleasing NSSet *set = nil;
if (count)
{
__autoreleasing id *objects = (__autoreleasing id *)malloc(count * sizeof(id));
for (uint32_t i = 0; i < count; i++)
{
objects[i] = FCReadObject(decoder);
}
set = [NSSet setWithObjects:objects count:count];
free(objects);
}
else
{
set = [NSSet set];
}
FCCacheReadObject(set, decoder->_objectCache);
return set;
}
static id FCReadMutableSet(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(uint32_t, *decoder->_offset);
uint32_t count = FCReadRawUInt32(decoder);
__autoreleasing NSMutableSet *set = [NSMutableSet setWithCapacity:count];
FCCacheReadObject(set, decoder->_objectCache);
for (uint32_t i = 0; i < count; i++)
{
[set addObject:FCReadObject(decoder)];
}
return set;
}
static id FCReadOrderedSet(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(uint32_t, *decoder->_offset);
uint32_t count = FCReadRawUInt32(decoder);
__autoreleasing NSOrderedSet *set = nil;
if (count)
{
__autoreleasing id *objects = (__autoreleasing id *)malloc(count * sizeof(id));
for (uint32_t i = 0; i < count; i++)
{
objects[i] = FCReadObject(decoder);
}
set = [NSOrderedSet orderedSetWithObjects:objects count:count];
free(objects);
}
else
{
set = [NSOrderedSet orderedSet];
}
FCCacheReadObject(set, decoder->_objectCache);
return set;
}
static id FCReadMutableOrderedSet(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(uint32_t, *decoder->_offset);
uint32_t count = FCReadRawUInt32(decoder);
__autoreleasing NSMutableOrderedSet *set = [NSMutableOrderedSet orderedSetWithCapacity:count];
FCCacheReadObject(set, decoder->_objectCache);
for (uint32_t i = 0; i < count; i++)
{
[set addObject:FCReadObject(decoder)];
}
return set;
}
static id FCReadTrue(__unused __unsafe_unretained FCNSDecoder *decoder)
{
return @YES;
}
static id FCReadFalse(__unused __unsafe_unretained FCNSDecoder *decoder)
{
return @NO;
}
static id FCReadInt8(__unsafe_unretained FCNSDecoder *decoder)
{
FC_READ_VALUE(int8_t, *decoder->_offset, decoder->_input, decoder->_total);
__autoreleasing NSNumber *number = @(value);
return number;
}
static id FCReadInt16(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(int16_t, *decoder->_offset);
FC_READ_VALUE(int16_t, *decoder->_offset, decoder->_input, decoder->_total);
__autoreleasing NSNumber *number = @(value);
return number;
}
static id FCReadInt32(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(int32_t, *decoder->_offset);
FC_READ_VALUE(int32_t, *decoder->_offset, decoder->_input, decoder->_total);
__autoreleasing NSNumber *number = @(value);
return number;
}
static id FCReadInt64(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(int64_t, *decoder->_offset);
FC_READ_VALUE(int64_t, *decoder->_offset, decoder->_input, decoder->_total);
__autoreleasing NSNumber *number = @(value);
return number;
}
static id FCReadFloat32(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(float_t, *decoder->_offset);
FC_READ_VALUE(float_t, *decoder->_offset, decoder->_input, decoder->_total);
__autoreleasing NSNumber *number = @(value);
return number;
}
static id FCReadFloat64(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(double_t, *decoder->_offset);
FC_READ_VALUE(double_t, *decoder->_offset, decoder->_input, decoder->_total);
__autoreleasing NSNumber *number = @(value);
return number;
}
static id FCReadData(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(uint32_t, *decoder->_offset);
uint32_t length = FCReadRawUInt32(decoder);
NSUInteger paddedLength = length + (4 - ((length % 4) ?: 4));
FC_ASSERT_FITS(paddedLength, *decoder->_offset, decoder->_total);
__autoreleasing NSData *data = [NSData dataWithBytes:(decoder->_input + *decoder->_offset) length:length];
*decoder->_offset += paddedLength;
FCCacheReadObject(data, decoder->_objectCache);
return data;
}
static id FCReadMutableData(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(uint32_t, *decoder->_offset);
uint32_t length = FCReadRawUInt32(decoder);
NSUInteger paddedLength = length + (4 - ((length % 4) ?: 4));
FC_ASSERT_FITS(paddedLength, *decoder->_offset, decoder->_total);
__autoreleasing NSMutableData *data = [NSMutableData dataWithBytes:(decoder->_input + *decoder->_offset) length:length];
*decoder->_offset += paddedLength;
FCCacheReadObject(data, decoder->_objectCache);
return data;
}
static id FCReadDate(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(NSTimeInterval, *decoder->_offset);
FC_READ_VALUE(NSTimeInterval, *decoder->_offset, decoder->_input, decoder->_total);
__autoreleasing NSDate *date = [NSDate dateWithTimeIntervalSince1970:value];
return date;
}
static id FCReadClassDefinition(__unsafe_unretained FCNSDecoder *decoder)
{
__autoreleasing FCClassDefinition *definition = FC_AUTORELEASE([[FCClassDefinition alloc] init]);
FCCacheReadObject(definition, decoder->_classCache);
definition->_className = FCReadRawString(decoder);
FC_ALIGN_INPUT(uint32_t, *decoder->_offset);
uint32_t count = FCReadRawUInt32(decoder);
if (count)
{
__autoreleasing id *objects = (__autoreleasing id *)malloc(count * sizeof(id));
for (uint32_t i = 0; i < count; i++)
{
objects[i] = FCReadRawString(decoder);
}
__autoreleasing NSArray *propertyKeys = [NSArray arrayWithObjects:objects count:count];
definition->_propertyKeys = propertyKeys;
free(objects);
}
//now return the actual object instance
return FCReadObject(decoder);
}
static id FCReadObjectInstance(__unsafe_unretained FCNSDecoder *decoder, NSUInteger classIndex)
{
__autoreleasing FCClassDefinition *definition = FCCachedObjectAtIndex(classIndex, decoder->_classCache);
__autoreleasing Class objectClass = NSClassFromString(definition->_className);
__autoreleasing id object = nil;
if (objectClass)
{
object = FC_AUTORELEASE([[objectClass alloc] init]);
}
else if (definition->_className)
{
object = [NSMutableDictionary dictionaryWithObject:definition->_className forKey:@"$class"];
}
else if (object)
{
object = [NSMutableDictionary dictionary];
}
NSUInteger cacheIndex = FCCacheReadObject(object, decoder->_objectCache);
for (__unsafe_unretained NSString *key in definition->_propertyKeys)
{
[object setValue:FCReadObject(decoder) forKey:key];
}
id newObject = [object awakeAfterFastCoding];
if (newObject != object)
{
//TODO: this is only a partial solution, as any objects that referenced
//this object between when it was created and now will have received incorrect instance
FCReplaceCachedObject(cacheIndex, newObject, decoder->_objectCache);
}
return newObject;
}
static id FCReadObject8(__unsafe_unretained FCNSDecoder *decoder)
{
return FCReadObjectInstance(decoder, FCReadRawUInt8(decoder));
}
static id FCReadObject16(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(uint16_t, *decoder->_offset);
return FCReadObjectInstance(decoder, FCReadRawUInt16(decoder));
}
static id FCReadObject32(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(uint32_t, *decoder->_offset);
return FCReadObjectInstance(decoder, FCReadRawUInt32(decoder));
}
static id FCReadURL(__unsafe_unretained FCNSDecoder *decoder)
{
__autoreleasing NSURL *URL = [NSURL URLWithString:FCReadObject(decoder) relativeToURL:FCReadObject(decoder)];
FCCacheReadObject(URL, decoder->_stringCache);
return URL;
}
static id FCReadPoint(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(double_t, *decoder->_offset);
CGPoint point = {(CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder)};
NSValue *value = [NSValue valueWithBytes:&point objCType:@encode(CGPoint)];
return value;
}
static id FCReadSize(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(double_t, *decoder->_offset);
CGSize size = {(CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder)};
NSValue *value = [NSValue valueWithBytes:&size objCType:@encode(CGSize)];
return value;
}
static id FCReadRect(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(double_t, *decoder->_offset);
CGRect rect =
{
{(CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder)},
{(CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder)}
};
NSValue *value = [NSValue valueWithBytes:&rect objCType:@encode(CGRect)];
return value;
}
static id FCReadRange(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(uint32_t, *decoder->_offset);
NSRange range = {FCReadRawUInt32(decoder), FCReadRawUInt32(decoder)};
NSValue *value = [NSValue valueWithBytes:&range objCType:@encode(NSRange)];
return value;
}
static id FCReadVector(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(double_t, *decoder->_offset);
CGVector point = {(CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder)};
NSValue *value = [NSValue valueWithBytes:&point objCType:@encode(CGVector)];
return value;
}
static id FCReadAffineTransform(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(double_t, *decoder->_offset);
CGAffineTransform transform =
{
(CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder),
(CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder),
(CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder)
};
NSValue *value = [NSValue valueWithBytes:&transform objCType:@encode(CGAffineTransform)];
return value;
}
static id FCRead3DTransform(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(double_t, *decoder->_offset);
CGFloat transform[] =
{
(CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder),
(CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder),
(CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder),
(CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder),
(CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder),
(CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder),
(CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder),
(CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder)
};
NSValue *value = [NSValue valueWithBytes:&transform objCType:@encode(CGFloat[16])];
return value;
}
static id FCReadMutableIndexSet(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(uint32_t, *decoder->_offset);
uint32_t rangeCount = FCReadRawUInt32(decoder);
__autoreleasing NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
FCCacheReadObject(indexSet, decoder->_objectCache);
for (uint32_t i = 0; i < rangeCount; i++)
{
NSRange range = {FCReadRawUInt32(decoder), FCReadRawUInt32(decoder)};
[indexSet addIndexesInRange:range];
}
return indexSet;
}
static id FCReadIndexSet(__unsafe_unretained FCNSDecoder *decoder)
{
FC_ALIGN_INPUT(uint32_t, *decoder->_offset);
uint32_t rangeCount = FCReadRawUInt32(decoder);
__autoreleasing NSIndexSet *indexSet;
if (rangeCount == 1)
{
//common case optimisation
NSRange range = {FCReadRawUInt32(decoder), FCReadRawUInt32(decoder)};
indexSet = [NSIndexSet indexSetWithIndexesInRange:range];
}
else
{
indexSet = [NSMutableIndexSet indexSet];
for (uint32_t i = 0; i < rangeCount; i++)
{
NSRange range = {FCReadRawUInt32(decoder), FCReadRawUInt32(decoder)};
[(NSMutableIndexSet *)indexSet addIndexesInRange:range];
}
indexSet = [indexSet copy];
}
FCCacheReadObject(indexSet, decoder->_objectCache);
return indexSet;
}
static id FCReadNSCodedObject(__unsafe_unretained FCNSDecoder *decoder)
{
NSString *className = FCReadObject(decoder);
NSMutableDictionary *oldProperties = decoder->_properties;
if ([decoder->_propertyDictionaryPool count])
{
decoder->_properties = [decoder->_propertyDictionaryPool lastObject];
[decoder->_propertyDictionaryPool removeLastObject];
[decoder->_properties removeAllObjects];
}
else
{
const CFDictionaryKeyCallBacks stringKeyCallbacks =
{
0,
NULL,
NULL,
NULL,
CFEqual,
CFHash
};
decoder->_properties = CFBridgingRelease(CFDictionaryCreateMutable(NULL, 0, &stringKeyCallbacks, NULL));
}
while (true)
{
id object = FCReadObject(decoder);
if (!object) break;
NSString *key = FCReadObject(decoder);
decoder->_properties[key] = object;
}
id object = [[NSClassFromString(className) alloc] initWithCoder:decoder];
[decoder->_propertyDictionaryPool addObject:decoder->_properties];
decoder->_properties = oldProperties;
FCCacheReadObject(object, decoder->_objectCache);
return object;
}
static id FCReadObject(__unsafe_unretained FCNSDecoder *decoder)
{
FCType type = FCReadType(decoder);
FCTypeConstructor *constructor = NULL;
if (type < FCTypeCount)
{
constructor = decoder->_constructors[type];
}
if (!constructor)
{
[NSException raise:FastCodingException format:@"FastCoding cannot decode object of type: %i", type];
return nil;
}
return constructor(decoder);
}
id FCParseData(NSData *data, FCTypeConstructor *constructors[])
{
NSUInteger length = [data length];
if (length < sizeof(FCHeader))
{
//not a valid FastArchive
return nil;
}
//read header
FCHeader header;
const void *input = data.bytes;
memcpy(&header, input, sizeof(header));
if (header.identifier != FCIdentifier)
{
//not a FastArchive
return nil;
}
if (header.majorVersion < 2 || header.majorVersion > FCMajorVersion)
{
//not compatible
NSLog(@"This version of the FastCoding library doesn't support FastCoding version %i.%i files", header.majorVersion, header.minorVersion);
return nil;
}
//create decoder
NSUInteger offset = sizeof(header);
FCNSDecoder *decoder = FC_AUTORELEASE([[FCNSDecoder alloc] init]);
decoder->_constructors = constructors;
decoder->_input = input;
decoder->_offset = &offset;
decoder->_total = length;
//read data
__autoreleasing NSMutableData *objectCache = [NSMutableData dataWithCapacity:FCReadRawUInt32(decoder) * sizeof(id)];
decoder->_objectCache = objectCache;
if (header.majorVersion < 3)
{
return FCReadObject_2_3(decoder);
}
else
{
__autoreleasing NSMutableData *classCache = [NSMutableData dataWithCapacity:FCReadRawUInt32(decoder) * sizeof(id)];
__autoreleasing NSMutableData *stringCache = [NSMutableData dataWithCapacity:FCReadRawUInt32(decoder) * sizeof(id)];
__autoreleasing NSMutableArray *propertyDictionaryPool = CFBridgingRelease(CFArrayCreateMutable(NULL, 0, NULL));
decoder->_classCache = classCache;
decoder->_stringCache = stringCache;
decoder->_propertyDictionaryPool = propertyDictionaryPool;
@try
{
return FCReadObject(decoder);
}
@catch (NSException *exception)
{
NSLog(@"%@", [exception reason]);
return nil;
}
}
}
static inline NSUInteger FCCacheWrittenObject(__unsafe_unretained id object, __unsafe_unretained NSMutableDictionary *cache)
{
NSUInteger count = (NSUInteger)CFDictionaryGetCount((CFMutableDictionaryRef)cache);
CFDictionarySetValue((CFMutableDictionaryRef)cache, (__bridge const void *)(object), (const void *)(count + 1));
return count;
}
static inline NSUInteger FCIndexOfCachedObject(__unsafe_unretained id object, __unsafe_unretained NSMutableDictionary *cache)
{
const void *index = CFDictionaryGetValue((__bridge CFMutableDictionaryRef)cache, (__bridge const void *)object);
if (index)
{
return ((NSUInteger)index) - 1;
}
return NSNotFound;
}
static inline void FCWriteType(FCType value, __unsafe_unretained NSMutableData *output)
{
[output appendBytes:&value length:sizeof(value)];
}
static inline void FCWriteUInt8(uint8_t value, __unsafe_unretained NSMutableData *output)
{
[output appendBytes:&value length:sizeof(value)];
}
static inline void FCWriteUInt16(uint16_t value, __unsafe_unretained NSMutableData *output)
{
[output appendBytes:&value length:sizeof(value)];
}
static inline void FCWriteUInt32(uint32_t value, __unsafe_unretained NSMutableData *output)
{
[output appendBytes:&value length:sizeof(value)];
}
static inline void FCWriteDouble(double_t value, __unsafe_unretained NSMutableData *output)
{
[output appendBytes:&value length:sizeof(value)];
}
static inline void FCWriteString(__unsafe_unretained NSString *string, __unsafe_unretained NSMutableData *output)
{
const char *utf8 = [string UTF8String];
NSUInteger length = strlen(utf8) + 1;
[output appendBytes:utf8 length:length];
}
static inline BOOL FCWriteObjectAlias(__unsafe_unretained id object, __unsafe_unretained FCNSCoder *coder)
{
NSUInteger index = FCIndexOfCachedObject(object, coder->_objectCache);
if (index <= UINT8_MAX)
{
FCWriteType(FCTypeObjectAlias8, coder->_output);
FCWriteUInt8((uint8_t)index, coder->_output);
return YES;
}
else if (index <= UINT16_MAX)
{
FCWriteType(FCTypeObjectAlias16, coder->_output);
FC_ALIGN_OUTPUT(uint16_t, coder->_output);
FCWriteUInt16((uint16_t)index, coder->_output);
return YES;
}
else if (index != NSNotFound)
{
FCWriteType(FCTypeObjectAlias32, coder->_output);
FC_ALIGN_OUTPUT(uint32_t, coder->_output);
FCWriteUInt32((uint32_t)index, coder->_output);
return YES;
}
else
{
return NO;
}
}
static inline BOOL FCWriteStringAlias(__unsafe_unretained id object, __unsafe_unretained FCNSCoder *coder)
{
NSUInteger index = FCIndexOfCachedObject(object, coder->_stringCache);
if (index <= UINT8_MAX)
{
FCWriteType(FCTypeStringAlias8, coder->_output);
FCWriteUInt8((uint8_t)index, coder->_output);
return YES;
}
else if (index <= UINT16_MAX)
{
FCWriteType(FCTypeStringAlias16, coder->_output);
FC_ALIGN_OUTPUT(uint16_t, coder->_output);
FCWriteUInt16((uint16_t)index, coder->_output);
return YES;
}
else if (index != NSNotFound)
{
FCWriteType(FCTypeStringAlias32, coder->_output);
FC_ALIGN_OUTPUT(uint32_t, coder->_output);
FCWriteUInt32((uint32_t)index, coder->_output);
return YES;
}
else
{
return NO;
}
}
static void FCWriteObject(__unsafe_unretained id object, __unsafe_unretained FCNSCoder *coder)
{
if (object)
{
[object FC_encodeWithCoder:coder];
}
else
{
FCWriteType(FCTypeNil, coder->_output);
}
}
@implementation FastCoder
+ (id)objectWithData:(NSData *)data
{
static FCTypeConstructor *constructors[] =
{
FCReadNil,
FCReadNull,
FCReadAlias8,
FCReadAlias16,
FCReadAlias32,
FCReadStringAlias8,
FCReadStringAlias16,
FCReadStringAlias32,
FCReadString,
FCReadDictionary,
FCReadArray,
FCReadSet,
FCReadOrderedSet,
FCReadTrue,
FCReadFalse,
FCReadInt8,
FCReadInt16,
FCReadInt32,
FCReadInt64,
FCReadFloat32,
FCReadFloat64,
FCReadData,
FCReadDate,
FCReadMutableString,
FCReadMutableDictionary,
FCReadMutableArray,
FCReadMutableSet,
FCReadMutableOrderedSet,
FCReadMutableData,
FCReadClassDefinition,
FCReadObject8,
FCReadObject16,
FCReadObject32,
FCReadURL,
FCReadPoint,
FCReadSize,
FCReadRect,
FCReadRange,
FCReadVector,
FCReadAffineTransform,
FCRead3DTransform,
FCReadMutableIndexSet,
FCReadIndexSet,
FCReadNSCodedObject
};
return FCParseData(data, constructors);
}
+ (id)propertyListWithData:(NSData *)data
{
static FCTypeConstructor *constructors[] =
{
NULL,
FCReadNull,
FCReadAlias8,
FCReadAlias16,
FCReadAlias32,
FCReadStringAlias8,
FCReadStringAlias16,
FCReadStringAlias32,
FCReadString,
FCReadDictionary,
FCReadArray,
FCReadSet,
FCReadOrderedSet,
FCReadTrue,
FCReadFalse,
FCReadInt8,
FCReadInt16,
FCReadInt32,
FCReadInt64,
FCReadFloat32,
FCReadFloat64,
FCReadData,
FCReadDate,
FCReadMutableString,
FCReadMutableDictionary,
FCReadMutableArray,
FCReadMutableSet,
FCReadMutableOrderedSet,
FCReadMutableData,
NULL,
NULL,
NULL,
NULL,
FCReadURL,
FCReadPoint,
FCReadSize,
FCReadRect,
FCReadRange,
FCReadVector,
FCReadAffineTransform,
FCRead3DTransform,
FCReadIndexSet,
FCReadIndexSet,
NULL
};
return FCParseData(data, constructors);
}
+ (NSData *)dataWithRootObject:(id)object
{
if (object)
{
//write header
FCHeader header = {FCIdentifier, FCMajorVersion, FCMinorVersion};
NSMutableData *output = [NSMutableData dataWithLength:sizeof(header)];
memcpy(output.mutableBytes, &header, sizeof(header));
//object count placeholders
FCWriteUInt32(0, output);
FCWriteUInt32(0, output);
FCWriteUInt32(0, output);
//set up cache
const CFDictionaryKeyCallBacks stringKeyCallbacks =
{
0,
NULL,
NULL,
NULL,
CFEqual,
CFHash
};
@autoreleasepool
{
__autoreleasing id objectCache = CFBridgingRelease(CFDictionaryCreateMutable(NULL, 0, NULL, NULL));
__autoreleasing id classCache = CFBridgingRelease(CFDictionaryCreateMutable(NULL, 0, NULL, NULL));
__autoreleasing id stringCache = CFBridgingRelease(CFDictionaryCreateMutable(NULL, 0, &stringKeyCallbacks, NULL));
__autoreleasing id classesByName = CFBridgingRelease(CFDictionaryCreateMutable(NULL, 0, &stringKeyCallbacks, NULL));
//create coder
FCNSCoder *coder = FC_AUTORELEASE([[FCNSCoder alloc] init]);
coder->_rootObject = object;
coder->_output = output;
coder->_objectCache = objectCache;
coder->_classCache = classCache;
coder->_stringCache = stringCache;
coder->_classesByName = classesByName;
//write object
FCWriteObject(object, coder);
//set object count
uint32_t objectCount = (uint32_t)[objectCache count];
[output replaceBytesInRange:NSMakeRange(sizeof(header), sizeof(uint32_t)) withBytes:&objectCount];
//set class count
uint32_t classCount = (uint32_t)[classCache count];
[output replaceBytesInRange:NSMakeRange(sizeof(header) + sizeof(uint32_t), sizeof(uint32_t)) withBytes:&classCount];
//set string count
uint32_t stringCount = (uint32_t)[stringCache count];
[output replaceBytesInRange:NSMakeRange(sizeof(header) + sizeof(uint32_t) * 2, sizeof(uint32_t)) withBytes:&stringCount];
return output;
}
}
return nil;
}
@end
@implementation FCNSCoder
- (BOOL)allowsKeyedCoding
{
return YES;
}
- (void)encodeObject:(__unsafe_unretained id)objv forKey:(__unsafe_unretained NSString *)key
{
FCWriteObject(objv, self);
FCWriteObject(key, self);
}
- (void)encodeConditionalObject:(id)objv forKey:(__unsafe_unretained NSString *)key
{
if (FCIndexOfCachedObject(objv, _objectCache) != NSNotFound)
{
FCWriteObject(objv, self);
FCWriteObject(key, self);
}
}
- (void)encodeBool:(BOOL)boolv forKey:(__unsafe_unretained NSString *)key
{
FCWriteObject(@(boolv), self);
FCWriteObject(key, self);
}
- (void)encodeInt:(int)intv forKey:(__unsafe_unretained NSString *)key
{
FCWriteObject(@(intv), self);
FCWriteObject(key, self);
}
- (void)encodeInteger:(NSInteger)intv forKey:(__unsafe_unretained NSString *)key
{
FCWriteObject(@(intv), self);
FCWriteObject(key, self);
}
- (void)encodeInt32:(int32_t)intv forKey:(__unsafe_unretained NSString *)key
{
FCWriteObject(@(intv), self);
FCWriteObject(key, self);
}
- (void)encodeInt64:(int64_t)intv forKey:(__unsafe_unretained NSString *)key
{
FCWriteObject(@(intv), self);
FCWriteObject(key, self);
}
- (void)encodeFloat:(float)realv forKey:(__unsafe_unretained NSString *)key
{
FCWriteObject(@(realv), self);
FCWriteObject(key, self);
}
- (void)encodeDouble:(double)realv forKey:(__unsafe_unretained NSString *)key
{
FCWriteObject(@(realv), self);
FCWriteObject(key, self);
}
- (void)encodeBytes:(const uint8_t *)bytesp length:(NSUInteger)lenv forKey:(__unsafe_unretained NSString *)key
{
FCWriteObject([NSData dataWithBytes:bytesp length:lenv], self);
FCWriteObject(key, self);
}
@end
@implementation FCNSDecoder
- (BOOL)containsValueForKey:(NSString *)key
{
return _properties[key] != nil;
}
- (id)decodeObjectForKey:(__unsafe_unretained NSString *)key
{
return _properties[key];
}
- (BOOL)decodeBoolForKey:(__unsafe_unretained NSString *)key
{
return [_properties[key] boolValue];
}
- (int)decodeIntForKey:(__unsafe_unretained NSString *)key
{
return [_properties[key] intValue];
}
- (NSInteger)decodeIntegerForKey:(__unsafe_unretained NSString *)key
{
return [_properties[key] integerValue];
}
- (int32_t)decodeInt32ForKey:(__unsafe_unretained NSString *)key
{
return (int32_t)[_properties[key] longValue];
}
- (int64_t)decodeInt64ForKey:(__unsafe_unretained NSString *)key
{
return [_properties[key] longLongValue];
}
- (float)decodeFloatForKey:(__unsafe_unretained NSString *)key
{
return [_properties[key] floatValue];
}
- (double)decodeDoubleForKey:(__unsafe_unretained NSString *)key
{
return [_properties[key] doubleValue];
}
- (const uint8_t *)decodeBytesForKey:(__unsafe_unretained NSString *)key returnedLength:(NSUInteger *)lengthp
{
__autoreleasing NSData *data = _properties[key];
*lengthp = [data length];
return data.bytes;
}
@end
@implementation FCClassDefinition : NSObject
//no encoding implementation needed
@end
@implementation NSObject (FastCoding)
+ (NSArray *)fastCodingKeys
{
__autoreleasing NSMutableArray *codableKeys = [NSMutableArray array];
unsigned int propertyCount;
objc_property_t *properties = class_copyPropertyList(self, &propertyCount);
for (unsigned int i = 0; i < propertyCount; i++)
{
//get property
objc_property_t property = properties[i];
const char *propertyName = property_getName(property);
NSString *key = @(propertyName);
//see if there is a backing ivar
char *ivar = property_copyAttributeValue(property, "V");
if (ivar)
{
//check if ivar has KVC-compliant name
NSString *ivarName = @(ivar);
if ([ivarName isEqualToString:key] || [ivarName isEqualToString:[@"_" stringByAppendingString:key]])
{
//setValue:forKey: will work
[codableKeys addObject:key];
}
free(ivar);
}
}
free(properties);
return codableKeys;
}
+ (NSArray *)FC_aggregatePropertyKeys
{
__autoreleasing NSArray *codableKeys = nil;
codableKeys = objc_getAssociatedObject(self, _cmd);
if (codableKeys == nil)
{
codableKeys = [NSMutableArray array];
Class subclass = [self class];
while (subclass != [NSObject class])
{
[(NSMutableArray *)codableKeys addObjectsFromArray:[subclass fastCodingKeys]];
subclass = [subclass superclass];
}
codableKeys = [NSArray arrayWithArray:codableKeys];
//make the association atomically so that we don't need to bother with an @synchronize
objc_setAssociatedObject(self, _cmd, codableKeys, OBJC_ASSOCIATION_RETAIN);
}
return codableKeys;
}
- (id)awakeAfterFastCoding
{
return self;
}
- (Class)classForFastCoding
{
return [self classForCoder];
}
- (BOOL)preferFastCoding
{
return NO;
}
- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder
{
if (FCWriteObjectAlias(self, coder)) return;
//handle NSCoding
if (![self preferFastCoding] && [self conformsToProtocol:@protocol(NSCoding)])
{
//write object
FCWriteType(FCTypeNSCodedObject, coder->_output);
FCWriteObject(NSStringFromClass([self classForCoder]), coder);
[(id <NSCoding>)self encodeWithCoder:coder];
FCWriteType(FCTypeNil, coder->_output);
FCCacheWrittenObject(self, coder->_objectCache);
return;
}
//write class definition
Class objectClass = [self classForFastCoding];
NSUInteger classIndex = FCIndexOfCachedObject(objectClass, coder->_classCache);
__autoreleasing NSArray *propertyKeys = [objectClass FC_aggregatePropertyKeys];
if (classIndex == NSNotFound)
{
classIndex = FCCacheWrittenObject(objectClass, coder->_classCache);
FCWriteType(FCTypeClassDefinition, coder->_output);
FCWriteString(NSStringFromClass(objectClass), coder->_output);
FC_ALIGN_OUTPUT(uint32_t, coder->_output);
FCWriteUInt32((uint32_t)[propertyKeys count], coder->_output);
for (__unsafe_unretained id value in propertyKeys)
{
FCWriteString(value, coder->_output);
}
}
//write object
FCCacheWrittenObject(self, coder->_objectCache);
if (classIndex <= UINT8_MAX)
{
FCWriteType(FCTypeObject8, coder->_output);
FCWriteUInt8((uint8_t)classIndex, coder->_output);
}
else if (classIndex <= UINT16_MAX)
{
FCWriteType(FCTypeObject16, coder->_output);
FC_ALIGN_OUTPUT(uint16_t, coder->_output);
FCWriteUInt16((uint16_t)classIndex, coder->_output);
}
else
{
FCWriteType(FCTypeObject32, coder->_output);
FC_ALIGN_OUTPUT(uint32_t, coder->_output);
FCWriteUInt32((uint32_t)classIndex, coder->_output);
}
for (__unsafe_unretained NSString *key in propertyKeys)
{
FCWriteObject([self valueForKey:key], coder);
}
}
@end
@implementation NSString (FastCoding)
- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder
{
if ([self classForCoder] == [NSMutableString class])
{
if (FCWriteObjectAlias(self, coder)) return;
FCCacheWrittenObject(self, coder->_objectCache);
FCWriteType(FCTypeMutableString, coder->_output);
}
else
{
if (FCWriteStringAlias(self, coder)) return;
FCCacheWrittenObject(self, coder->_stringCache);
FCWriteType(FCTypeString, coder->_output);
}
FCWriteString(self, coder->_output);
}
@end
@implementation NSNumber (FastCoding)
- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder
{
switch (CFNumberGetType((CFNumberRef)self))
{
case kCFNumberFloat32Type:
case kCFNumberFloatType:
{
FCWriteType(FCTypeFloat32, coder->_output);
float_t value = [self floatValue];
FC_ALIGN_OUTPUT(float_t, coder->_output);
[coder->_output appendBytes:&value length:sizeof(value)];
break;
}
case kCFNumberFloat64Type:
case kCFNumberDoubleType:
case kCFNumberCGFloatType:
{
FCWriteType(FCTypeFloat64, coder->_output);
double_t value = [self doubleValue];
FC_ALIGN_OUTPUT(double_t, coder->_output);
[coder->_output appendBytes:&value length:sizeof(value)];
break;
}
case kCFNumberSInt64Type:
case kCFNumberLongLongType:
case kCFNumberNSIntegerType:
{
int64_t value = [self longLongValue];
if (value > (int64_t)INT32_MAX || value < (int64_t)INT32_MIN)
{
FCWriteType(FCTypeInt64, coder->_output);
FC_ALIGN_OUTPUT(int64_t, coder->_output);
[coder->_output appendBytes:&value length:sizeof(value)];
break;
}
//otherwise treat as 32-bit
}
case kCFNumberSInt32Type:
case kCFNumberIntType:
case kCFNumberLongType:
case kCFNumberCFIndexType:
{
int32_t value = (int32_t)[self intValue];
if (value > (int32_t)INT16_MAX || value < (int32_t)INT16_MIN)
{
FCWriteType(FCTypeInt32, coder->_output);
FC_ALIGN_OUTPUT(int32_t, coder->_output);
[coder->_output appendBytes:&value length:sizeof(value)];
break;
}
//otherwise treat as 16-bit
}
case kCFNumberSInt16Type:
case kCFNumberShortType:
{
int16_t value = (int16_t)[self intValue];
if (value > (int16_t)INT8_MAX || value < (int16_t)INT8_MIN)
{
FCWriteType(FCTypeInt16, coder->_output);
FC_ALIGN_OUTPUT(int16_t, coder->_output);
[coder->_output appendBytes:&value length:sizeof(value)];
break;
}
//otherwise treat as 8-bit
}
case kCFNumberSInt8Type:
case kCFNumberCharType:
{
int8_t value = (int8_t)[self intValue];
if (value == 1)
{
FCWriteType(FCTypeTrue, coder->_output);
}
else if (value == 0)
{
FCWriteType(FCTypeFalse, coder->_output);
}
else
{
FCWriteType(FCTypeInt8, coder->_output);
[coder->_output appendBytes:&value length:sizeof(value)];
}
}
}
}
@end
@implementation NSDate (FastCoding)
- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder
{
FCCacheWrittenObject(self, coder->_objectCache);
FCWriteType(FCTypeDate, coder->_output);
NSTimeInterval value = [self timeIntervalSince1970];
FC_ALIGN_OUTPUT(NSTimeInterval, coder->_output);
[coder->_output appendBytes:&value length:sizeof(value)];
}
@end
@implementation NSData (FastCoding)
- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder
{
if (FCWriteObjectAlias(self, coder)) return;
FCCacheWrittenObject(self, coder->_objectCache);
FCWriteType(([self classForCoder] == [NSMutableData class])? FCTypeMutableData: FCTypeData, coder->_output);
uint32_t length = (uint32_t)[self length];
FC_ALIGN_OUTPUT(uint32_t, coder->_output);
FCWriteUInt32(length, coder->_output);
[coder->_output appendData:self];
coder->_output.length += (4 - ((length % 4) ?: 4));
}
@end
@implementation NSNull (FastCoding)
- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder
{
FCWriteType(FCTypeNull, coder->_output);
}
@end
@implementation NSDictionary (FastCoding)
- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder
{
if (FCWriteObjectAlias(self, coder)) return;
//alias keypath
__autoreleasing NSString *aliasKeypath = self[@"$alias"];
if ([self count] == 1 && aliasKeypath)
{
__autoreleasing id node = coder->_rootObject;
NSArray *parts = [aliasKeypath componentsSeparatedByString:@"."];
for (__unsafe_unretained NSString *key in parts)
{
if ([node isKindOfClass:[NSArray class]])
{
node = ((NSArray *)node)[(NSUInteger)[key integerValue]];
}
else
{
node = [node valueForKey:key];
}
}
FCWriteObject(node, coder);
return;
}
//object bootstrapping
__autoreleasing NSString *className = self[@"$class"];
if (className)
{
//get class definition
__autoreleasing NSArray *propertyKeys = [[self allKeys] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"self != '$class'"]];
__autoreleasing FCClassDefinition *objectClass = coder->_classesByName[className];
if (objectClass)
{
//check that existing class definition contains all keys
__autoreleasing NSMutableArray *keys = nil;
for (__unsafe_unretained id key in propertyKeys)
{
if (![objectClass->_propertyKeys containsObject:key])
{
keys = keys ?: [NSMutableArray array];
[keys addObject:key];
}
}
propertyKeys = objectClass->_propertyKeys;
if (keys)
{
//we need to create a new class definition that includes extra keys
propertyKeys = [propertyKeys arrayByAddingObjectsFromArray:keys];
objectClass = nil;
}
}
if (!objectClass)
{
//create class definition
objectClass = FC_AUTORELEASE([[FCClassDefinition alloc] init]);
objectClass->_className = className;
objectClass->_propertyKeys = propertyKeys;
coder->_classesByName[className] = objectClass;
}
//write class definition
NSUInteger classIndex = FCIndexOfCachedObject(objectClass, coder->_classCache);
if (classIndex == NSNotFound)
{
classIndex = FCCacheWrittenObject(objectClass, coder->_classCache);
FCWriteType(FCTypeClassDefinition, coder->_output);
FCWriteString(objectClass->_className, coder->_output);
FC_ALIGN_OUTPUT(uint32_t, coder->_output);
FCWriteUInt32((uint32_t)[propertyKeys count], coder->_output);
for (__unsafe_unretained id key in propertyKeys)
{
//convert each to a string using -description, just in case
FCWriteString([key description], coder->_output);
}
}
//write object
FCCacheWrittenObject(self, coder->_objectCache);
if (classIndex <= UINT8_MAX)
{
FCWriteType(FCTypeObject8, coder->_output);
FCWriteUInt8((uint8_t)classIndex, coder->_output);
}
else if (classIndex <= UINT16_MAX)
{
FCWriteType(FCTypeObject16, coder->_output);
FC_ALIGN_OUTPUT(uint16_t, coder->_output);
FCWriteUInt16((uint16_t)classIndex, coder->_output);
}
else
{
FCWriteType(FCTypeObject32, coder->_output);
FC_ALIGN_OUTPUT(uint32_t, coder->_output);
FCWriteUInt32((uint32_t)classIndex, coder->_output);
}
for (__unsafe_unretained NSString *key in propertyKeys)
{
FCWriteObject(self[key], coder);
}
return;
}
//ordinary dictionary
BOOL mutable = ([self classForCoder] == [NSMutableDictionary class]);
if (mutable) FCCacheWrittenObject(self, coder->_objectCache);
FCWriteType(mutable? FCTypeMutableDictionary: FCTypeDictionary, coder->_output);
FC_ALIGN_OUTPUT(uint32_t, coder->_output);
FCWriteUInt32((uint32_t)[self count], coder->_output);
[self enumerateKeysAndObjectsUsingBlock:^(__unsafe_unretained id key, __unsafe_unretained id obj, __unused BOOL *stop) {
FCWriteObject(obj, coder);
FCWriteObject(key, coder);
}];
if (!mutable) FCCacheWrittenObject(self, coder->_objectCache);
}
@end
@implementation NSArray (FastCoding)
- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder
{
if (FCWriteObjectAlias(self, coder)) return;
BOOL mutable = ([self classForCoder] == [NSMutableArray class]);
if (mutable) FCCacheWrittenObject(self, coder->_objectCache);
FCWriteType(mutable? FCTypeMutableArray: FCTypeArray, coder->_output);
FC_ALIGN_OUTPUT(uint32_t, coder->_output);
FCWriteUInt32((uint32_t)[self count], coder->_output);
for (__unsafe_unretained id value in self)
{
FCWriteObject(value, coder);
}
if (!mutable) FCCacheWrittenObject(self, coder->_objectCache);
}
@end
@implementation NSSet (FastCoding)
- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder
{
if (FCWriteObjectAlias(self, coder)) return;
BOOL mutable = ([self classForCoder] == [NSMutableSet class]);
if (mutable) FCCacheWrittenObject(self, coder->_objectCache);
FCWriteType(mutable? FCTypeMutableSet: FCTypeSet, coder->_output);
FC_ALIGN_OUTPUT(uint32_t, coder->_output);
FCWriteUInt32((uint32_t)[self count], coder->_output);
for (__unsafe_unretained id value in self)
{
FCWriteObject(value, coder);
}
if (!mutable) FCCacheWrittenObject(self, coder->_objectCache);
}
@end
@implementation NSOrderedSet (FastCoding)
- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder
{
if (FCWriteObjectAlias(self, coder)) return;
BOOL mutable = ([self classForCoder] == [NSMutableOrderedSet class]);
if (mutable) FCCacheWrittenObject(self, coder->_objectCache);
FCWriteType(mutable? FCTypeMutableOrderedSet: FCTypeOrderedSet, coder->_output);
FC_ALIGN_OUTPUT(uint32_t, coder->_output);
FCWriteUInt32((uint32_t)[self count], coder->_output);
for (__unsafe_unretained id value in self)
{
FCWriteObject(value, coder);
}
if (!mutable) FCCacheWrittenObject(self, coder->_objectCache);
}
@end
@implementation NSIndexSet (FastCoding)
- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder
{
if (FCWriteObjectAlias(self, coder)) return;
BOOL mutable = ([self classForCoder] == [NSMutableIndexSet class]);
if (mutable) FCCacheWrittenObject(self, coder->_objectCache);
uint32_t __block rangeCount = 0; // wish we could get this directly from NSIndexSet...
[self enumerateRangesUsingBlock:^(__unused NSRange range, __unused BOOL *stop) {
rangeCount ++;
}];
FCWriteType(mutable? FCTypeMutableIndexSet: FCTypeIndexSet, coder->_output);
FC_ALIGN_OUTPUT(uint32_t, coder->_output);
FCWriteUInt32(rangeCount, coder->_output);
[self enumerateRangesUsingBlock:^(NSRange range, __unused BOOL *stop) {
FCWriteUInt32((uint32_t)range.location, coder->_output);
FCWriteUInt32((uint32_t)range.length, coder->_output);
}];
if (!mutable) FCCacheWrittenObject(self, coder->_objectCache);
}
@end
@implementation NSURL (FastCoding)
- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder
{
if (FCWriteStringAlias(self, coder)) return;
FCWriteType(FCTypeURL, coder->_output);
FCWriteObject(self.relativeString, coder);
FCWriteObject(self.baseURL, coder);
FCCacheWrittenObject(self, coder->_stringCache);
}
@end
@implementation NSValue (FastCoding)
- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder
{
FCCacheWrittenObject(self, coder->_objectCache);
const char *type = [self objCType];
if (strcmp(type, @encode(CGPoint)) == 0 OR_IF_MAC(strcmp(type, @encode(NSPoint)) == 0))
{
CGFloat point[2];
[self getValue:&point];
FCWriteType(FCTypePoint, coder->_output);
FC_ALIGN_OUTPUT(double_t, coder->_output);
FCWriteDouble((double_t)point[0], coder->_output);
FCWriteDouble((double_t)point[1], coder->_output);
}
else if (strcmp(type, @encode(CGSize)) == 0 OR_IF_MAC(strcmp(type, @encode(NSSize)) == 0))
{
CGFloat size[2];
[self getValue:&size];
FCWriteType(FCTypeSize, coder->_output);
FC_ALIGN_OUTPUT(double_t, coder->_output);
FCWriteDouble((double_t)size[0], coder->_output);
FCWriteDouble((double_t)size[1], coder->_output);
}
else if (strcmp(type, @encode(CGRect)) == 0 OR_IF_MAC(strcmp(type, @encode(NSRect)) == 0))
{
CGFloat rect[4];
[self getValue:&rect];
FCWriteType(FCTypeRect, coder->_output);
FC_ALIGN_OUTPUT(double_t, coder->_output);
FCWriteDouble((double_t)rect[0], coder->_output);
FCWriteDouble((double_t)rect[1], coder->_output);
FCWriteDouble((double_t)rect[2], coder->_output);
FCWriteDouble((double_t)rect[3], coder->_output);
}
else if (strcmp(type, @encode(NSRange)) == 0)
{
NSUInteger range[2];
[self getValue:&range];
FCWriteType(FCTypeRange, coder->_output);
FC_ALIGN_OUTPUT(uint32_t, coder->_output);
FCWriteUInt32((uint32_t)range[0], coder->_output);
FCWriteUInt32((uint32_t)range[1], coder->_output);
}
else if (strcmp(type, @encode(CGVector)) == 0)
{
CGFloat vector[2];
[self getValue:&vector];
FCWriteType(FCTypeVector, coder->_output);
FC_ALIGN_OUTPUT(double_t, coder->_output);
FCWriteDouble((double_t)vector[0], coder->_output);
FCWriteDouble((double_t)vector[1], coder->_output);
}
else if (strcmp(type, @encode(CGAffineTransform)) == 0)
{
CGFloat transform[6];
[self getValue:&transform];
FCWriteType(FCTypeAffineTransform, coder->_output);
for (NSUInteger i = 0; i < 6; i++)
{
FCWriteDouble((double_t)transform[i], coder->_output);
}
}
else if ([@(type) hasPrefix:@"{CATransform3D"])
{
CGFloat transform[16];
[self getValue:&transform];
FCWriteType(FCType3DTransform, coder->_output);
FC_ALIGN_OUTPUT(double_t, coder->_output);
for (NSUInteger i = 0; i < 16; i++)
{
FCWriteDouble((double_t)transform[i], coder->_output);
}
}
else
{
[NSException raise:FastCodingException format:@"Unable to encode NSValue data of type %@", @(type)];
}
}
@end
#pragma mark -
#pragma mark legacy decoding
static inline uint32_t FCReadRawUInt32_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
FC_READ_VALUE(uint32_t, *decoder->_offset, decoder->_input, decoder->_total);
return value;
}
static inline double FCReadRawDouble_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
FC_READ_VALUE(double_t, *decoder->_offset, decoder->_input, decoder->_total);
return value;
}
static id FCReadRawString_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
__autoreleasing NSString *string = nil;
NSUInteger length = strlen(decoder->_input + *decoder->_offset) + 1;
NSUInteger paddedLength = length + (4 - ((length % 4) ?: 4));
FC_ASSERT_FITS(paddedLength, *decoder->_offset, decoder->_total);
if (length > 1)
{
string = CFBridgingRelease(CFStringCreateWithBytes(NULL, decoder->_input + *decoder->_offset,
(CFIndex)length - 1, kCFStringEncodingUTF8, false));
}
else
{
string = @"";
}
*decoder->_offset += paddedLength;
return string;
}
static id FCReadNull_2_3(__unused __unsafe_unretained FCNSDecoder *decoder)
{
return [NSNull null];
}
static id FCReadAlias_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
return FCCachedObjectAtIndex(FCReadRawUInt32_2_3(decoder), decoder->_objectCache);
}
static id FCReadString_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
NSString *string = FCReadRawString_2_3(decoder);
FCCacheReadObject(string, decoder->_objectCache);
return string;
}
static id FCReadMutableString_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
__autoreleasing NSMutableString *string = nil;
NSUInteger length = strlen(decoder->_input + *decoder->_offset) + 1;
NSUInteger paddedLength = length + (4 - ((length % 4) ?: 4));
FC_ASSERT_FITS(paddedLength, *decoder->_offset, decoder->_total);
if (length > 1)
{
string = FC_AUTORELEASE([[NSMutableString alloc] initWithBytes:decoder->_input + *decoder->_offset length:length - 1 encoding:NSUTF8StringEncoding]);
}
else
{
string = [NSMutableString string];
}
*decoder->_offset += paddedLength;
FCCacheReadObject(string, decoder->_objectCache);
return string;
}
static id FCReadDictionary_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
uint32_t count = FCReadRawUInt32_2_3(decoder);
__autoreleasing NSDictionary *dict = nil;
if (count)
{
__autoreleasing id *keys = (__autoreleasing id *)malloc(count * sizeof(id));
__autoreleasing id *objects = (__autoreleasing id *)malloc(count * sizeof(id));
for (uint32_t i = 0; i < count; i++)
{
objects[i] = FCReadObject_2_3(decoder);
keys[i] = FCReadObject_2_3(decoder);
}
dict = [NSDictionary dictionaryWithObjects:objects forKeys:keys count:count];
free(objects);
free(keys);
}
else
{
dict = @{};
}
FCCacheReadObject(dict, decoder->_objectCache);
return dict;
}
static id FCReadMutableDictionary_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
uint32_t count = FCReadRawUInt32_2_3(decoder);
__autoreleasing NSMutableDictionary *dict = CFBridgingRelease(CFDictionaryCreateMutable(NULL, (CFIndex)count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
FCCacheReadObject(dict, decoder->_objectCache);
for (uint32_t i = 0; i < count; i++)
{
__autoreleasing id object = FCReadObject_2_3(decoder);
__autoreleasing id key = FCReadObject_2_3(decoder);
CFDictionarySetValue((__bridge CFMutableDictionaryRef)dict, (__bridge const void *)key, (__bridge const void *)object);
}
return dict;
}
static id FCReadArray_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
uint32_t count = FCReadRawUInt32_2_3(decoder);
__autoreleasing NSArray *array = nil;
if (count)
{
__autoreleasing id *objects = (__autoreleasing id *)malloc(count * sizeof(id));
for (uint32_t i = 0; i < count; i++)
{
objects[i] = FCReadObject_2_3(decoder);
}
array = [NSArray arrayWithObjects:objects count:count];
free(objects);
}
else
{
array = @[];
}
FCCacheReadObject(array, decoder->_objectCache);
return array;
}
static id FCReadMutableArray_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
uint32_t count = FCReadRawUInt32_2_3(decoder);
__autoreleasing NSMutableArray *array = [NSMutableArray arrayWithCapacity:count];
FCCacheReadObject(array, decoder->_objectCache);
for (uint32_t i = 0; i < count; i++)
{
CFArrayAppendValue((__bridge CFMutableArrayRef)array, (__bridge void *)FCReadObject_2_3(decoder));
}
return array;
}
static id FCReadSet_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
uint32_t count = FCReadRawUInt32_2_3(decoder);
__autoreleasing NSSet *set = nil;
if (count)
{
__autoreleasing id *objects = (__autoreleasing id *)malloc(count * sizeof(id));
for (uint32_t i = 0; i < count; i++)
{
objects[i] = FCReadObject_2_3(decoder);
}
set = [NSSet setWithObjects:objects count:count];
free(objects);
}
else
{
set = [NSSet set];
}
FCCacheReadObject(set, decoder->_objectCache);
return set;
}
static id FCReadMutableSet_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
uint32_t count = FCReadRawUInt32_2_3(decoder);
__autoreleasing NSMutableSet *set = [NSMutableSet setWithCapacity:count];
FCCacheReadObject(set, decoder->_objectCache);
for (uint32_t i = 0; i < count; i++)
{
[set addObject:FCReadObject_2_3(decoder)];
}
return set;
}
static id FCReadOrderedSet_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
uint32_t count = FCReadRawUInt32_2_3(decoder);
__autoreleasing NSOrderedSet *set = nil;
if (count)
{
__autoreleasing id *objects = (__autoreleasing id *)malloc(count * sizeof(id));
for (uint32_t i = 0; i < count; i++)
{
objects[i] = FCReadObject_2_3(decoder);
}
set = [NSOrderedSet orderedSetWithObjects:objects count:count];
free(objects);
}
else
{
set = [NSOrderedSet orderedSet];
}
FCCacheReadObject(set, decoder->_objectCache);
return set;
}
static id FCReadMutableOrderedSet_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
uint32_t count = FCReadRawUInt32_2_3(decoder);
__autoreleasing NSMutableOrderedSet *set = [NSMutableOrderedSet orderedSetWithCapacity:count];
FCCacheReadObject(set, decoder->_objectCache);
for (uint32_t i = 0; i < count; i++)
{
[set addObject:FCReadObject_2_3(decoder)];
}
return set;
}
static id FCReadTrue_2_3(__unused __unsafe_unretained FCNSDecoder *decoder)
{
return @YES;
}
static id FCReadFalse_2_3(__unused __unsafe_unretained FCNSDecoder *decoder)
{
return @NO;
}
static id FCReadInt32_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
FC_READ_VALUE(int32_t, *decoder->_offset, decoder->_input, decoder->_total);
__autoreleasing NSNumber *number = @(value);
FCCacheReadObject(number, decoder->_objectCache);
return number;
}
static id FCReadInt64_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
FC_READ_VALUE(int64_t, *decoder->_offset, decoder->_input, decoder->_total);
__autoreleasing NSNumber *number = @(value);
FCCacheReadObject(number, decoder->_objectCache);
return number;
}
static id FCReadfloat_t_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
FC_READ_VALUE(float_t, *decoder->_offset, decoder->_input, decoder->_total);
__autoreleasing NSNumber *number = @(value);
FCCacheReadObject(number, decoder->_objectCache);
return number;
}
static id FCReaddouble_t_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
FC_READ_VALUE(double_t, *decoder->_offset, decoder->_input, decoder->_total);
__autoreleasing NSNumber *number = @(value);
FCCacheReadObject(number, decoder->_objectCache);
return number;
}
static id FCReadData_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
uint32_t length = FCReadRawUInt32_2_3(decoder);
NSUInteger paddedLength = length + (4 - ((length % 4) ?: 4));
FC_ASSERT_FITS(paddedLength, *decoder->_offset, decoder->_total);
__autoreleasing NSData *data = [NSData dataWithBytes:(decoder->_input + *decoder->_offset) length:length];
*decoder->_offset += paddedLength;
FCCacheReadObject(data, decoder->_objectCache);
return data;
}
static id FCReadMutableData_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
uint32_t length = FCReadRawUInt32_2_3(decoder);
NSUInteger paddedLength = length + (4 - ((length % 4) ?: 4));
FC_ASSERT_FITS(paddedLength, *decoder->_offset, decoder->_total);
__autoreleasing NSMutableData *data = [NSMutableData dataWithBytes:(decoder->_input + *decoder->_offset) length:length];
*decoder->_offset += paddedLength;
FCCacheReadObject(data, decoder->_objectCache);
return data;
}
static id FCReadDate_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
FC_READ_VALUE(NSTimeInterval, *decoder->_offset, decoder->_input, decoder->_total);
__autoreleasing NSDate *date = [NSDate dateWithTimeIntervalSince1970:value];
FCCacheReadObject(date, decoder->_objectCache);
return date;
}
static id FCReadClassDefinition_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
__autoreleasing FCClassDefinition *definition = FC_AUTORELEASE([[FCClassDefinition alloc] init]);
FCCacheReadObject(definition, decoder->_objectCache);
definition->_className = FCReadRawString_2_3(decoder);
uint32_t count = FCReadRawUInt32_2_3(decoder);
if (count)
{
__autoreleasing id *objects = (__autoreleasing id *)malloc(count * sizeof(id));
for (uint32_t i = 0; i < count; i++)
{
objects[i] = FCReadRawString_2_3(decoder);
}
__autoreleasing NSArray *propertyKeys = [NSArray arrayWithObjects:objects count:count];
definition->_propertyKeys = propertyKeys;
free(objects);
}
//now return the actual object instance
return FCReadObject_2_3(decoder);
}
static id FCReadObjectInstance_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
__autoreleasing FCClassDefinition *definition = FCCachedObjectAtIndex(FCReadRawUInt32_2_3(decoder), decoder->_objectCache);
__autoreleasing Class objectClass = NSClassFromString(definition->_className);
__autoreleasing id object = nil;
if (objectClass)
{
object = FC_AUTORELEASE([[objectClass alloc] init]);
}
else if (definition->_className)
{
object = [NSMutableDictionary dictionaryWithObject:definition->_className forKey:@"$class"];
}
else if (object)
{
object = [NSMutableDictionary dictionary];
}
NSUInteger cacheIndex = FCCacheReadObject(object, decoder->_objectCache);
for (__unsafe_unretained NSString *key in definition->_propertyKeys)
{
[object setValue:FCReadObject_2_3(decoder) forKey:key];
}
id newObject = [object awakeAfterFastCoding];
if (newObject != object)
{
//TODO: this is only a partial solution, as any objects that referenced
//this object between when it was created and now will have received incorrect instance
FCReplaceCachedObject(cacheIndex, newObject, decoder->_objectCache);
}
return newObject;
}
static id FCReadNil_2_3(__unused __unsafe_unretained FCNSDecoder *decoder)
{
return nil;
}
static id FCReadURL_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
__autoreleasing NSURL *URL = [NSURL URLWithString:FCReadObject_2_3(decoder) relativeToURL:FCReadObject_2_3(decoder)];
FCCacheReadObject(URL, decoder->_objectCache);
return URL;
}
static id FCReadPoint_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
CGPoint point = {(CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder)};
NSValue *value = [NSValue valueWithBytes:&point objCType:@encode(CGPoint)];
FCCacheReadObject(value, decoder->_objectCache);
return value;
}
static id FCReadSize_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
CGSize size = {(CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder)};
NSValue *value = [NSValue valueWithBytes:&size objCType:@encode(CGSize)];
FCCacheReadObject(value, decoder->_objectCache);
return value;
}
static id FCReadRect_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
CGRect rect =
{
{(CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder)},
{(CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder)}
};
NSValue *value = [NSValue valueWithBytes:&rect objCType:@encode(CGRect)];
FCCacheReadObject(value, decoder->_objectCache);
return value;
}
static id FCReadRange_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
NSRange range = {FCReadRawUInt32_2_3(decoder), FCReadRawUInt32_2_3(decoder)};
NSValue *value = [NSValue valueWithBytes:&range objCType:@encode(NSRange)];
FCCacheReadObject(value, decoder->_objectCache);
return value;
}
static id FCReadAffineTransform_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
CGAffineTransform transform =
{
(CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder),
(CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder),
(CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder)
};
NSValue *value = [NSValue valueWithBytes:&transform objCType:@encode(CGAffineTransform)];
FCCacheReadObject(value, decoder->_objectCache);
return value;
}
static id FCRead3DTransform_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
CGFloat transform[] =
{
(CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder),
(CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder),
(CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder),
(CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder),
(CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder),
(CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder),
(CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder),
(CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder)
};
NSValue *value = [NSValue valueWithBytes:&transform objCType:@encode(CGFloat[16])];
FCCacheReadObject(value, decoder->_objectCache);
return value;
}
static id FCReadMutableIndexSet_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
uint32_t rangeCount = FCReadRawUInt32_2_3(decoder);
__autoreleasing NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
FCCacheReadObject(indexSet, decoder->_objectCache);
for (uint32_t i = 0; i < rangeCount; i++)
{
NSRange range = {FCReadRawUInt32_2_3(decoder), FCReadRawUInt32_2_3(decoder)};
[indexSet addIndexesInRange:range];
}
return indexSet;
}
static id FCReadIndexSet_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
__autoreleasing NSIndexSet *indexSet;
uint32_t rangeCount = FCReadRawUInt32_2_3(decoder);
if (rangeCount == 1)
{
//common case optimisation
NSRange range = {FCReadRawUInt32_2_3(decoder), FCReadRawUInt32_2_3(decoder)};
indexSet = [NSIndexSet indexSetWithIndexesInRange:range];
}
else
{
indexSet = [NSMutableIndexSet indexSet];
for (uint32_t i = 0; i < rangeCount; i++)
{
NSRange range = {FCReadRawUInt32_2_3(decoder), FCReadRawUInt32_2_3(decoder)};
[(NSMutableIndexSet *)indexSet addIndexesInRange:range];
}
indexSet = [indexSet copy];
}
FCCacheReadObject(indexSet, decoder->_objectCache);
return indexSet;
}
static id FCReadNSCodedObject_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
NSString *className = FCReadObject_2_3(decoder);
NSMutableDictionary *oldProperties = decoder->_properties;
decoder->_properties = CFBridgingRelease(CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
while (true)
{
id object = FCReadObject_2_3(decoder);
if (!object) break;
NSString *key = FCReadObject_2_3(decoder);
decoder->_properties[key] = object;
}
id object = [[NSClassFromString(className) alloc] initWithCoder:decoder];
decoder->_properties = oldProperties;
FCCacheReadObject(object, decoder->_objectCache);
return object;
}
static id FCReadObject_2_3(__unsafe_unretained FCNSDecoder *decoder)
{
static FCTypeConstructor *constructors[] =
{
FCReadNull_2_3,
FCReadAlias_2_3,
FCReadString_2_3,
FCReadDictionary_2_3,
FCReadArray_2_3,
FCReadSet_2_3,
FCReadOrderedSet_2_3,
FCReadTrue_2_3,
FCReadFalse_2_3,
FCReadInt32_2_3,
FCReadInt64_2_3,
FCReadfloat_t_2_3,
FCReaddouble_t_2_3,
FCReadData_2_3,
FCReadDate_2_3,
FCReadMutableString_2_3,
FCReadMutableDictionary_2_3,
FCReadMutableArray_2_3,
FCReadMutableSet_2_3,
FCReadMutableOrderedSet_2_3,
FCReadMutableData_2_3,
FCReadClassDefinition_2_3,
FCReadObjectInstance_2_3,
FCReadNil_2_3,
FCReadURL_2_3,
FCReadPoint_2_3,
FCReadSize_2_3,
FCReadRect_2_3,
FCReadRange_2_3,
FCReadAffineTransform_2_3,
FCRead3DTransform_2_3,
FCReadMutableIndexSet_2_3,
FCReadIndexSet_2_3,
FCReadNSCodedObject_2_3
};
uint32_t type = FCReadRawUInt32_2_3(decoder);
if (type > sizeof(constructors))
{
[NSException raise:FastCodingException format:@"FastCoding cannot decode object of type: %i", type];
return nil;
}
return constructors[type](decoder);
}
NSObject+FastCoder.h 与 NSObject+FastCoder.m
//
// NSObject+FastCoder.h
// Array
//
// Created by YouXianMing on 14/12/1.
// Copyright (c) 2014年 YouXianMing. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSObject (FastCoder)
/**
* 使用FastCoder将对象写文件
*
* @param path 文件路径
*
* @return YES,成功,NO,失败
*/
- (BOOL)useFastCoderToWriteToFilePath:(NSString *)filePath;
/**
* 使用FastCoder从文件路径中恢复对象
*
* @param filePath 文件路径
*
* @return 对象
*/
- (id)useFastCoderToRecoverFromFilePath:(NSString *)filePath;
/**
* 使用FastCoder将对象转换成NSData
*
* @return NSData
*/
- (NSData *)useFastCoderToCreateData;
@end
//
// NSObject+FastCoder.m
// Array
//
// Created by YouXianMing on 14/12/1.
// Copyright (c) 2014年 YouXianMing. All rights reserved.
//
#import "NSObject+FastCoder.h"
#import "FastCoder.h"
@implementation NSObject (FastCoder)
- (BOOL)useFastCoderToWriteToFilePath:(NSString *)filePath {
BOOL sucess = NO;
if (self) {
NSData *data = [FastCoder dataWithRootObject:self];
sucess = [data writeToFile:filePath atomically:YES];
}
return sucess;
}
- (id)useFastCoderToRecoverFromFilePath:(NSString *)filePath {
NSData *data = [NSData dataWithContentsOfFile:filePath];
return [FastCoder objectWithData:data];
}
- (NSData *)useFastCoderToCreateData {
return [FastCoder dataWithRootObject:self];
}
@end