mirror of
https://github.com/Tencent/MMKV.git
synced 2026-10-17 04:30:56 +08:00
opt copying from NSData to MMBuffer
This commit is contained in:
@@ -18,7 +18,7 @@
|
||||
CB95641623AB2E9100ACCD39 /* MMKV.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB9563F223AB2E9100ACCD39 /* MMKV.cpp */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
|
||||
CB95641723AB2E9100ACCD39 /* MiniPBCoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB9563F523AB2E9100ACCD39 /* MiniPBCoder.cpp */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
|
||||
CB95641823AB2E9100ACCD39 /* ThreadLock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB9563F723AB2E9100ACCD39 /* ThreadLock.cpp */; };
|
||||
CB95641923AB2E9100ACCD39 /* MMBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB9563F823AB2E9100ACCD39 /* MMBuffer.cpp */; };
|
||||
CB95641923AB2E9100ACCD39 /* MMBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB9563F823AB2E9100ACCD39 /* MMBuffer.cpp */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
|
||||
CB95641A23AB2E9100ACCD39 /* CodedInputData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB9563F923AB2E9100ACCD39 /* CodedInputData.cpp */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
|
||||
CB95641B23AB2E9100ACCD39 /* openssl_cfb128.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB95640123AB2E9100ACCD39 /* openssl_cfb128.cpp */; };
|
||||
CB95641C23AB2E9100ACCD39 /* openssl_aes_core.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB95640323AB2E9100ACCD39 /* openssl_aes_core.cpp */; };
|
||||
|
||||
@@ -23,6 +23,12 @@
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
|
||||
#ifdef MMKV_IOS_OR_MAC
|
||||
# if __has_feature(objc_arc)
|
||||
# error This file must be compiled with MRC. Use -fno-objc-arc flag.
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
MMBuffer::MMBuffer(size_t length) : ptr(nullptr), size(length), isNoCopy(MMBufferCopy) {
|
||||
@@ -38,10 +44,26 @@ MMBuffer::MMBuffer(void *source, size_t length, MMBufferCopyFlag noCopy) : ptr(s
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MMKV_IOS_OR_MAC
|
||||
MMBuffer::MMBuffer(NSData *data, MMBufferCopyFlag noCopy)
|
||||
: ptr((void *) data.bytes), size(data.length), isNoCopy(noCopy) {
|
||||
if (isNoCopy == MMBufferCopy) {
|
||||
m_data = [data retain];
|
||||
} else {
|
||||
m_data = data;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
MMBuffer::MMBuffer(MMBuffer &&other) noexcept : ptr(other.ptr), size(other.size), isNoCopy(other.isNoCopy) {
|
||||
other.ptr = nullptr;
|
||||
other.size = 0;
|
||||
other.isNoCopy = MMBufferCopy;
|
||||
|
||||
#ifdef MMKV_IOS_OR_MAC
|
||||
m_data = other.m_data;
|
||||
other.m_data = nil;
|
||||
#endif
|
||||
}
|
||||
|
||||
MMBuffer &MMBuffer::operator=(MMBuffer &&other) noexcept {
|
||||
@@ -49,10 +71,25 @@ MMBuffer &MMBuffer::operator=(MMBuffer &&other) noexcept {
|
||||
std::swap(size, other.size);
|
||||
std::swap(isNoCopy, other.isNoCopy);
|
||||
|
||||
#ifdef MMKV_IOS_OR_MAC
|
||||
std::swap(m_data, other.m_data);
|
||||
#endif
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
MMBuffer::~MMBuffer() {
|
||||
#ifdef MMKV_IOS_OR_MAC
|
||||
if (m_data) {
|
||||
if (isNoCopy == MMBufferCopy) {
|
||||
[m_data release];
|
||||
}
|
||||
m_data = nil;
|
||||
ptr = nullptr;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (isNoCopy == MMBufferCopy && ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#ifndef MMKV_MMBUFFER_H
|
||||
#define MMKV_MMBUFFER_H
|
||||
|
||||
#include "MMKVPredef.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
@@ -36,6 +38,9 @@ private:
|
||||
void *ptr;
|
||||
size_t size;
|
||||
MMBufferCopyFlag isNoCopy;
|
||||
#ifdef MMKV_IOS_OR_MAC
|
||||
NSData *m_data = nil;
|
||||
#endif
|
||||
|
||||
public:
|
||||
void *getPtr() const { return ptr; }
|
||||
@@ -44,6 +49,9 @@ public:
|
||||
|
||||
explicit MMBuffer(size_t length = 0);
|
||||
MMBuffer(void *source, size_t length, MMBufferCopyFlag noCopy = MMBufferCopy);
|
||||
#ifdef MMKV_IOS_OR_MAC
|
||||
explicit MMBuffer(NSData *data, MMBufferCopyFlag noCopy = MMBufferCopy);
|
||||
#endif
|
||||
|
||||
MMBuffer(MMBuffer &&other) noexcept;
|
||||
MMBuffer &operator=(MMBuffer &&other) noexcept;
|
||||
|
||||
+2
-2
@@ -697,7 +697,7 @@ const MMBuffer &MMKV::getDataForKey(MMKVKey_t key) {
|
||||
if (itr != m_dic.end()) {
|
||||
return itr->second;
|
||||
}
|
||||
static MMBuffer nan(0);
|
||||
static MMBuffer nan((size_t) 0);
|
||||
return nan;
|
||||
}
|
||||
|
||||
@@ -733,7 +733,7 @@ bool MMKV::removeDataForKey(MMKVKey_t key) {
|
||||
m_dic.erase(itr);
|
||||
|
||||
m_hasFullWriteback = false;
|
||||
static MMBuffer nan(0);
|
||||
static MMBuffer nan((size_t) 0);
|
||||
return appendDataWithKey(nan, key);
|
||||
}
|
||||
|
||||
|
||||
+7
-5
@@ -70,9 +70,9 @@ void MMKV::setIsInBackground(bool isInBackground) {
|
||||
|
||||
// @finally in C++ stype
|
||||
template <typename F>
|
||||
struct FinalAction {
|
||||
FinalAction(F f) : m_func{f} {}
|
||||
~FinalAction() { m_func(); }
|
||||
struct AtExit {
|
||||
AtExit(F f) : m_func{f} {}
|
||||
~AtExit() { m_func(); }
|
||||
|
||||
private:
|
||||
F m_func;
|
||||
@@ -90,7 +90,7 @@ bool MMKV::protectFromBackgroundWriting(size_t size, WriteBlock block) {
|
||||
//block(m_output);
|
||||
return false;
|
||||
} else {
|
||||
FinalAction cleanup([=] { munlock((void *) ptr, lockDownSize); });
|
||||
AtExit cleanup([=] { munlock((void *) ptr, lockDownSize); });
|
||||
try {
|
||||
block(m_output);
|
||||
} catch (std::exception &exception) {
|
||||
@@ -121,7 +121,9 @@ bool MMKV::set(NSObject<NSCoding> *__unsafe_unretained obj, MMKVKey_t key) {
|
||||
} else {
|
||||
/*if ([object conformsToProtocol:@protocol(NSCoding)])*/ {
|
||||
auto tmp = [NSKeyedArchiver archivedDataWithRootObject:obj];
|
||||
data = MMBuffer((void *) tmp.bytes, tmp.length);
|
||||
if (tmp.length > 0) {
|
||||
data = MMBuffer(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ void MiniPBCoder::writeRootObject() {
|
||||
m_outputData->writeRawVarint32(encodeItem->valueSize);
|
||||
if (encodeItem->valueSize > 0 && encodeItem->value.tmpObjectValue != nullptr) {
|
||||
auto obj = (__bridge NSData *) encodeItem->value.tmpObjectValue;
|
||||
MMBuffer buffer((void *) obj.bytes, obj.length, MMBufferNoCopy);
|
||||
MMBuffer buffer(obj, MMBufferNoCopy);
|
||||
m_outputData->writeRawData(buffer);
|
||||
}
|
||||
break;
|
||||
@@ -92,7 +92,7 @@ void MiniPBCoder::writeRootObject() {
|
||||
m_outputData->writeRawVarint32(encodeItem->valueSize);
|
||||
if (encodeItem->valueSize > 0 && encodeItem->value.objectValue != nullptr) {
|
||||
auto obj = (__bridge NSData *) encodeItem->value.objectValue;
|
||||
MMBuffer buffer((void *) obj.bytes, obj.length, MMBufferNoCopy);
|
||||
MMBuffer buffer(obj, MMBufferNoCopy);
|
||||
m_outputData->writeRawData(buffer);
|
||||
}
|
||||
break;
|
||||
|
||||
+1
-1
@@ -83,7 +83,7 @@ public:
|
||||
return pbcoder.getEncodeData(obj);
|
||||
} catch (const std::exception &exception) {
|
||||
MMKVError("%s", exception.what());
|
||||
return MMBuffer(0);
|
||||
return MMBuffer((size_t) 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -511,7 +511,7 @@ static BOOL g_hasCalledInitializeMMKV = NO;
|
||||
} else {
|
||||
string = mmapID;
|
||||
}
|
||||
MMKVInfo("mmapKey: %@", string);
|
||||
MMKVDebug("mmapKey: %@", string);
|
||||
return string;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,35 @@
|
||||
#import "MMKVDemo-Swift.h"
|
||||
#import <MMKV/MMKV.h>
|
||||
|
||||
@interface TestNSArchive : NSObject <NSCoding>
|
||||
@property(nonatomic, strong) NSString *m_username;
|
||||
@property(nonatomic, assign) int32_t m_age;
|
||||
@property(nonatomic, assign) float m_score;
|
||||
@end
|
||||
|
||||
@implementation TestNSArchive
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)decoder {
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
self.m_username = [decoder decodeObjectForKey:@"m_username"];
|
||||
self.m_age = [decoder decodeInt32ForKey:@"m_age"];
|
||||
self.m_score = [decoder decodeFloatForKey:@"m_score"];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)encoder {
|
||||
[encoder encodeObject:self.m_username forKey:@"m_username"];
|
||||
[encoder encodeInteger:self.m_age forKey:@"m_age"];
|
||||
[encoder encodeFloat:self.m_score forKey:@"m_score"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface ViewController () <MMKVHandler>
|
||||
@end
|
||||
|
||||
@@ -29,6 +58,8 @@
|
||||
NSMutableArray *m_arrStrings;
|
||||
NSMutableArray *m_arrStrKeys;
|
||||
NSMutableArray *m_arrIntKeys;
|
||||
NSMutableArray *m_arrObjKeys;
|
||||
NSMutableArray *m_arrNSCodingObjs;
|
||||
|
||||
int m_loops;
|
||||
}
|
||||
@@ -69,6 +100,8 @@
|
||||
m_arrStrings = [NSMutableArray arrayWithCapacity:m_loops];
|
||||
m_arrStrKeys = [NSMutableArray arrayWithCapacity:m_loops];
|
||||
m_arrIntKeys = [NSMutableArray arrayWithCapacity:m_loops];
|
||||
m_arrObjKeys = [NSMutableArray arrayWithCapacity:m_loops];
|
||||
m_arrNSCodingObjs = [NSMutableArray arrayWithCapacity:m_loops];
|
||||
for (size_t index = 0; index < m_loops; index++) {
|
||||
NSString *str = [NSString stringWithFormat:@"%s-%d", __FILE__, rand()];
|
||||
[m_arrStrings addObject:str];
|
||||
@@ -78,6 +111,15 @@
|
||||
|
||||
NSString *intKey = [NSString stringWithFormat:@"int-%zu", index];
|
||||
[m_arrIntKeys addObject:intKey];
|
||||
/*
|
||||
NSString *objKey = [NSString stringWithFormat:@"obj-%zu", index];
|
||||
[m_arrObjKeys addObject:objKey];
|
||||
|
||||
TestNSArchive *obj = [[TestNSArchive alloc] init];
|
||||
obj.m_username = str;
|
||||
obj.m_age = rand();
|
||||
obj.m_age = rand() * rand() * 0.5;
|
||||
[m_arrNSCodingObjs addObject:obj];*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,6 +389,9 @@
|
||||
for (size_t index = 0; index < self->m_loops; index++) {
|
||||
NSString *str = [NSString stringWithFormat:@"%s-%d", __FILE__, rand()];
|
||||
[self->m_arrStrings addObject:str];
|
||||
|
||||
//TestNSArchive *obj = self->m_arrNSCodingObjs[index];
|
||||
//obj.m_username = str;
|
||||
}
|
||||
|
||||
[self mmkvBaselineTest:self->m_loops];
|
||||
@@ -365,6 +410,8 @@
|
||||
[self mmkvBatchReadInt:loops];
|
||||
[self mmkvBatchWriteString:loops];
|
||||
[self mmkvBatchReadString:loops];
|
||||
//[self mmkvBatchWriteObject:loops];
|
||||
//[self mmkvBatchReadObject:loops];
|
||||
|
||||
//[self mmkvBatchDeleteString:loops];
|
||||
//[[MMKV defaultMMKV] trim];
|
||||
@@ -447,6 +494,37 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)mmkvBatchWriteObject:(int)loops {
|
||||
@autoreleasepool {
|
||||
NSDate *startDate = [NSDate date];
|
||||
|
||||
MMKV *mmkv = [MMKV defaultMMKV];
|
||||
for (int index = 0; index < loops; index++) {
|
||||
TestNSArchive *obj = m_arrNSCodingObjs[index];
|
||||
NSString *objKey = m_arrObjKeys[index];
|
||||
[mmkv setObject:obj forKey:objKey];
|
||||
}
|
||||
NSDate *endDate = [NSDate date];
|
||||
int cost = [endDate timeIntervalSinceDate:startDate] * 1000;
|
||||
NSLog(@"mmkv write object %d times, cost:%d ms", loops, cost);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)mmkvBatchReadObject:(int)loops {
|
||||
@autoreleasepool {
|
||||
NSDate *startDate = [NSDate date];
|
||||
|
||||
MMKV *mmkv = [MMKV defaultMMKV];
|
||||
for (int index = 0; index < loops; index++) {
|
||||
NSString *objKey = m_arrObjKeys[index];
|
||||
[mmkv getObjectOfClass:TestNSArchive.class forKey:objKey];
|
||||
}
|
||||
NSDate *endDate = [NSDate date];
|
||||
int cost = [endDate timeIntervalSinceDate:startDate] * 1000;
|
||||
NSLog(@"mmkv read object %d times, cost:%d ms", loops, cost);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - NSUserDefault baseline test
|
||||
|
||||
- (void)userDefaultBaselineTest:(int)loops {
|
||||
@@ -454,6 +532,8 @@
|
||||
[self userDefaultBatchReadInt:loops];
|
||||
[self userDefaultBatchWriteString:loops];
|
||||
[self userDefaultBatchReadString:loops];
|
||||
//[self userDefaultBatchWriteObject:loops];
|
||||
//[self userDefaultBatchReadObject:loops];
|
||||
}
|
||||
|
||||
- (void)userDefaultBatchWriteInt:(int)loops {
|
||||
@@ -465,8 +545,8 @@
|
||||
NSInteger tmp = rand();
|
||||
NSString *intKey = m_arrIntKeys[index];
|
||||
[userdefault setInteger:tmp forKey:intKey];
|
||||
[userdefault synchronize];
|
||||
}
|
||||
[userdefault synchronize];
|
||||
NSDate *endDate = [NSDate date];
|
||||
int cost = [endDate timeIntervalSinceDate:startDate] * 1000;
|
||||
NSLog(@"NSUserDefaults write int %d times, cost:%d ms", loops, cost);
|
||||
@@ -497,8 +577,8 @@
|
||||
NSString *str = m_arrStrings[index];
|
||||
NSString *strKey = m_arrStrKeys[index];
|
||||
[userdefault setObject:str forKey:strKey];
|
||||
[userdefault synchronize];
|
||||
}
|
||||
[userdefault synchronize];
|
||||
NSDate *endDate = [NSDate date];
|
||||
int cost = [endDate timeIntervalSinceDate:startDate] * 1000;
|
||||
NSLog(@"NSUserDefaults write string %d times, cost:%d ms", loops, cost);
|
||||
@@ -520,6 +600,40 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)userDefaultBatchWriteObject:(int)loops {
|
||||
@autoreleasepool {
|
||||
NSDate *startDate = [NSDate date];
|
||||
|
||||
NSUserDefaults *userdefault = [NSUserDefaults standardUserDefaults];
|
||||
for (int index = 0; index < loops; index++) {
|
||||
TestNSArchive *obj = m_arrNSCodingObjs[index];
|
||||
NSString *objKey = m_arrObjKeys[index];
|
||||
auto tmp = [NSKeyedArchiver archivedDataWithRootObject:obj];
|
||||
[userdefault setObject:tmp forKey:objKey];
|
||||
}
|
||||
[userdefault synchronize];
|
||||
NSDate *endDate = [NSDate date];
|
||||
int cost = [endDate timeIntervalSinceDate:startDate] * 1000;
|
||||
NSLog(@"NSUserDefaults write object %d times, cost:%d ms", loops, cost);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)userDefaultBatchReadObject:(int)loops {
|
||||
@autoreleasepool {
|
||||
NSDate *startDate = [NSDate date];
|
||||
|
||||
NSUserDefaults *userdefault = [NSUserDefaults standardUserDefaults];
|
||||
for (int index = 0; index < loops; index++) {
|
||||
NSString *objKey = m_arrObjKeys[index];
|
||||
NSData *tmp = [userdefault objectForKey:objKey];
|
||||
[NSKeyedUnarchiver unarchiveObjectWithData:tmp];
|
||||
}
|
||||
NSDate *endDate = [NSDate date];
|
||||
int cost = [endDate timeIntervalSinceDate:startDate] * 1000;
|
||||
NSLog(@"NSUserDefaults read object %d times, cost:%d ms", loops, cost);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - brutle test
|
||||
|
||||
- (void)brutleTest {
|
||||
|
||||
Reference in New Issue
Block a user