使用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@endtypedef id FCTypeConstructor(FCNSDecoder *);@interface FCNSDecoder ()
{@publicNSUInteger *_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;@endstatic 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 instancereturn 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 instanceFCReplaceCachedObject(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 optimisationNSRange 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 FastArchivereturn nil;}//read header
    FCHeader header;const void *input = data.bytes;memcpy(&header, input, sizeof(header));if (header.identifier != FCIdentifier){//not a FastArchivereturn nil;}if (header.majorVersion < 2 || header.majorVersion > FCMajorVersion){//not compatibleNSLog(@"This version of the FastCoding library doesn't support FastCoding version %i.%i files", header.majorVersion, header.minorVersion);return nil;}//create decoderNSUInteger 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 headerFCHeader header = {FCIdentifier, FCMajorVersion, FCMinorVersion};NSMutableData *output = [NSMutableData dataWithLength:sizeof(header)];memcpy(output.mutableBytes, &header, sizeof(header));//object count placeholdersFCWriteUInt32(0, output);FCWriteUInt32(0, output);FCWriteUInt32(0, output);//set up cacheconst 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 coderFCNSCoder *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 objectFCWriteObject(object, coder);//set object countuint32_t objectCount = (uint32_t)[objectCache count];[output replaceBytesInRange:NSMakeRange(sizeof(header), sizeof(uint32_t)) withBytes:&objectCount];//set class countuint32_t classCount = (uint32_t)[classCache count];[output replaceBytesInRange:NSMakeRange(sizeof(header) + sizeof(uint32_t), sizeof(uint32_t)) withBytes:&classCount];//set string countuint32_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 propertyobjc_property_t property = properties[i];const char *propertyName = property_getName(property);NSString *key = @(propertyName);//see if there is a backing ivarchar *ivar = property_copyAttributeValue(property, "V");if (ivar){//check if ivar has KVC-compliant nameNSString *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 NSCodingif (![self preferFastCoding] && [self conformsToProtocol:@protocol(NSCoding)]){//write objectFCWriteType(FCTypeNSCodedObject, coder->_output);FCWriteObject(NSStringFromClass([self classForCoder]), coder);[(id <NSCoding>)self encodeWithCoder:coder];FCWriteType(FCTypeNil, coder->_output);FCCacheWrittenObject(self, coder->_objectCache);return;}//write class definitionClass 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 objectFCCacheWrittenObject(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 keyspropertyKeys = [propertyKeys arrayByAddingObjectsFromArray:keys];objectClass = nil;}}if (!objectClass){//create class definitionobjectClass = FC_AUTORELEASE([[FCClassDefinition alloc] init]);objectClass->_className = className;objectClass->_propertyKeys = propertyKeys;coder->_classesByName[className] = objectClass;}//write class definitionNSUInteger 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 caseFCWriteString([key description], coder->_output);}}//write objectFCCacheWrittenObject(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 dictionaryBOOL 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 decodingstatic 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 instancereturn 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 instanceFCReplaceCachedObject(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 optimisationNSRange 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

转载于:https://www.cnblogs.com/YouXianMing/p/4136166.html

使用FastCoder写缓存单例相关推荐

  1. 以ChatGPT写诗为例,教你如何用AI软件创新性提问?

    想用AI软件创作出动人的诗篇吗? ChatGPT 是一款人工智能软件,可以帮助你创作鼓舞人心的诗歌.它为您提供了一个强大的平台来探索您的创意方面.通过一组简单的问题,您只需点击几下就可以生成令人惊叹的 ...

  2. 如何根据用例图写出用例描述

    如何根据用例图写出用例描述 前言:因为用例描述中的执行者和用例名很容易通过用例图得出来,所以下面讲的主要内容是如何通过用例图获得用例描述中的交互动作序列. 第一步 用例分类 A.用例分类是什么??? ...

  3. socket可以写成单例嘛_精读《设计模式 - Singleton 单例模式》

    Singleton(单例模式) Singleton(单例模式)属于创建型模式,提供一种对象获取方式,保证在一定范围内是唯一的. 意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点. 其实单例模 ...

  4. socket可以写成单例嘛_精读设计模式 Singleton 单例模式

    Singleton(单例模式) Singleton(单例模式)属于创建型模式,提供一种对象获取方式,保证在一定范围内是唯一的. 意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点. 其实单例模 ...

  5. typora导出word指定样式_Word长文档排版以写论文为例

    前言 用Word编辑长文档(比如学位论文.标书.项目总结报告)是件非常耗时耗力的活儿,主要体现在内容的创作(及复制粘贴和组合)上,但后期的排版也会让不少人困扰,无法流畅地排出自己想要的版式. 经过多年 ...

  6. 经典仿句100例_仿写句子100例集锦

    作文素材集锦:精美句子仿写 100 例 1 .太阳无语,却放射出光辉:高山无语,却体现出巍峨. 蓝天无语,却显露出高远:大地无语,却展示出广博. 鲜花无语,却散发出芬芳:青春无语,却散发出活力. 2 ...

  7. 经典仿句100例_仿写句子_二年级仿写句子100例

    梅花:迎接它出生的不是和煦的春风,而是凛冽的北风:伴随它成长的不是温暖的春天,而是寒冷的冬天:滋润它成长的不是晶莹的甘露,而是肃杀的严霜:衬托它美姿的不是浓浓的绿意,而是寒彻的白雪.花坛暖房里,它不开 ...

  8. 如何烧写Uboot-Ralink5350为例

    Uboot烧写可能对于开发人员来说都是一件简单的事吧,在网上找了很多资料都没有写具体如何操作的.权当扫盲贴了. 首先声明:Uboot就像电脑的BIOS,通常本身是十分稳定的,没有必要是不会去修改的.而 ...

  9. 如何用Dart写一个单例

    由于Dart拥有factory constructors,因此构建单例模式很容易. class Singleton {static final Singleton _singleton = new S ...

最新文章

  1. EOSIO Dawn 4.0 发布
  2. AI一分钟 | 厉害了!BBC记者挑战中国天网工程,潜逃仅7分钟被抓;百度狂砸20亿,设国内最大规模的AI专项风投基金
  3. python 常见函数_Python基础函数:初学者常用的十个Python函数,非常全面!
  4. angular 图片引入_推荐一个 angular 图像加载插件
  5. Linux系统openssl测试指导,Linux管理员必用:OpenSSL服务器测试技巧
  6. vector c++ 赋值_面对拷贝赋值时发生的自我赋值的正确态度时接受而不是防止
  7. 非root用户ssh 执行 sudo远程机器免密钥
  8. 质量故事(2)---降落伞的真实故事
  9. MySQL -- 行转列 -- GROUP_CONCAT -- MAX(CASE WHEN THEN)
  10. Eclipse清除SVN的账号信息
  11. 智能优化算法:粒子群算法相关代码
  12. sqlserver 当月、 时间_SQLServer取系统当前时间
  13. 电脑实用的软件及工具
  14. 扇贝离线 android,扇贝单词离线
  15. 知识图谱论文读后感001
  16. 【NVMe2.0b 8】NVMe 队列仲裁机制
  17. numpy统计图像中某个像素值的个数
  18. 【华人学者风采】余家国 武汉理工大学
  19. js关闭浏览器当前页(iframe)
  20. Oracle导入dmp数据

热门文章

  1. Android自定义Layout
  2. 最大字段和 冲出暴力枚举
  3. MySQL笔记1:考察内链接、左连接、右连接。
  4. 解释i节点在文件系统中的作用?超级块作用?
  5. MOVW 和 rep
  6. JUC并发编程二 并发架构--线程运行原理
  7. linux之ifconfig、ifup、ifdown
  8. 害怕抑郁症?该系统通过日常交流就能判断你是否有病
  9. laravel 的 表单请求
  10. cisco 6509交换配置