react-native-mmkv 3.0.0-beta.6 → 3.0.0-beta.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MMKV/Core/CMakeLists.txt +1 -1
- package/MMKV/Core/Core.xcodeproj/project.pbxproj +4 -6
- package/MMKV/Core/KeyValueHolder.cpp +1 -1
- package/MMKV/Core/KeyValueHolder.h +5 -1
- package/MMKV/Core/MMBuffer.h +1 -1
- package/MMKV/Core/MMKV.cpp +70 -73
- package/MMKV/Core/MMKV.h +126 -11
- package/MMKV/Core/MMKVPredef.h +44 -3
- package/MMKV/Core/MMKV_IO.cpp +47 -33
- package/MMKV/Core/MMKV_OSX.cpp +16 -29
- package/MMKV/Core/MemoryFile_Android.cpp +27 -13
- package/MMKV/Core/MiniPBCoder.cpp +308 -9
- package/MMKV/Core/MiniPBCoder.h +36 -17
- package/MMKV/Core/MiniPBCoder_OSX.cpp +1 -0
- package/MMKV/Core/PBEncodeItem.hpp +18 -0
- package/MMKV/Core/PBUtility.h +0 -12
- package/MMKV/Core/ThreadLock.cpp +1 -3
- package/MMKV/Core/aes/AESCrypt.cpp +26 -6
- package/MMKV/Core/aes/AESCrypt.h +5 -1
- package/MMKV/Core/core.vcxproj +4 -4
- package/MMKV/Core/crc32/Checksum.h +4 -1
- package/android/CMakeLists.txt +0 -1
- package/android/src/main/java/com/mrousavy/mmkv/MmkvPlatformContextModule.java +9 -0
- package/cpp/MmkvHostObject.cpp +35 -37
- package/ios/MmkvPlatformContextModule.mm +19 -1
- package/lib/commonjs/MMKV.js.map +1 -1
- package/lib/commonjs/NativeMmkvPlatformContext.js.map +1 -1
- package/lib/commonjs/createMMKV.js +17 -0
- package/lib/commonjs/createMMKV.js.map +1 -1
- package/lib/commonjs/hooks.js.map +1 -1
- package/lib/module/MMKV.js.map +1 -1
- package/lib/module/NativeMmkvPlatformContext.js.map +1 -1
- package/lib/module/createMMKV.js +17 -0
- package/lib/module/createMMKV.js.map +1 -1
- package/lib/module/hooks.js.map +1 -1
- package/lib/typescript/src/MMKV.d.ts +0 -1
- package/lib/typescript/src/MMKV.d.ts.map +1 -1
- package/lib/typescript/src/NativeMmkv.d.ts +3 -3
- package/lib/typescript/src/NativeMmkvPlatformContext.d.ts +11 -0
- package/lib/typescript/src/NativeMmkvPlatformContext.d.ts.map +1 -1
- package/lib/typescript/src/Types.d.ts +4 -0
- package/lib/typescript/src/Types.d.ts.map +1 -1
- package/lib/typescript/src/createMMKV.d.ts +1 -1
- package/lib/typescript/src/createMMKV.d.ts.map +1 -1
- package/lib/typescript/src/createMMKV.web.d.ts +1 -1
- package/lib/typescript/src/createMMKV.web.d.ts.map +1 -1
- package/lib/typescript/src/hooks.d.ts +1 -1
- package/lib/typescript/src/hooks.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/MMKV.ts +0 -1
- package/src/NativeMmkv.ts +3 -3
- package/src/NativeMmkvPlatformContext.ts +11 -0
- package/src/Types.ts +4 -0
- package/src/createMMKV.ts +20 -2
- package/src/createMMKV.web.ts +1 -1
- package/src/hooks.ts +1 -1
- package/android/src/main/cpp/cpp-adapter.cpp +0 -7
package/MMKV/Core/CMakeLists.txt
CHANGED
|
@@ -452,7 +452,7 @@
|
|
|
452
452
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
|
453
453
|
CLANG_ANALYZER_NONNULL = YES;
|
|
454
454
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
|
455
|
-
CLANG_CXX_LANGUAGE_STANDARD = "gnu++
|
|
455
|
+
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
|
456
456
|
CLANG_CXX_LIBRARY = "libc++";
|
|
457
457
|
CLANG_ENABLE_MODULES = YES;
|
|
458
458
|
CLANG_ENABLE_OBJC_ARC = YES;
|
|
@@ -517,7 +517,7 @@
|
|
|
517
517
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
|
518
518
|
CLANG_ANALYZER_NONNULL = YES;
|
|
519
519
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
|
520
|
-
CLANG_CXX_LANGUAGE_STANDARD = "gnu++
|
|
520
|
+
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
|
521
521
|
CLANG_CXX_LIBRARY = "libc++";
|
|
522
522
|
CLANG_ENABLE_MODULES = YES;
|
|
523
523
|
CLANG_ENABLE_OBJC_ARC = YES;
|
|
@@ -572,7 +572,6 @@
|
|
|
572
572
|
CB9563E223AB2D9500ACCD39 /* Debug */ = {
|
|
573
573
|
isa = XCBuildConfiguration;
|
|
574
574
|
buildSettings = {
|
|
575
|
-
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
|
576
575
|
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
|
|
577
576
|
CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES;
|
|
578
577
|
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
|
@@ -592,13 +591,13 @@
|
|
|
592
591
|
SKIP_INSTALL = YES;
|
|
593
592
|
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx appletvsimulator appletvos xrsimulator xros";
|
|
594
593
|
TARGETED_DEVICE_FAMILY = "1,2,3";
|
|
594
|
+
SUPPORTS_MACCATALYST = YES;
|
|
595
595
|
};
|
|
596
596
|
name = Debug;
|
|
597
597
|
};
|
|
598
598
|
CB9563E323AB2D9500ACCD39 /* Release */ = {
|
|
599
599
|
isa = XCBuildConfiguration;
|
|
600
600
|
buildSettings = {
|
|
601
|
-
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
|
602
601
|
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
|
|
603
602
|
CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES;
|
|
604
603
|
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
|
@@ -619,13 +618,13 @@
|
|
|
619
618
|
SKIP_INSTALL = YES;
|
|
620
619
|
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx appletvsimulator appletvos xrsimulator xros";
|
|
621
620
|
TARGETED_DEVICE_FAMILY = "1,2,3";
|
|
621
|
+
SUPPORTS_MACCATALYST = YES;
|
|
622
622
|
};
|
|
623
623
|
name = Release;
|
|
624
624
|
};
|
|
625
625
|
CBF19074243D70BA001C82ED /* Debug */ = {
|
|
626
626
|
isa = XCBuildConfiguration;
|
|
627
627
|
buildSettings = {
|
|
628
|
-
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
|
629
628
|
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
|
|
630
629
|
CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES;
|
|
631
630
|
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
|
@@ -650,7 +649,6 @@
|
|
|
650
649
|
CBF19075243D70BA001C82ED /* Release */ = {
|
|
651
650
|
isa = XCBuildConfiguration;
|
|
652
651
|
buildSettings = {
|
|
653
|
-
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
|
654
652
|
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
|
|
655
653
|
CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES;
|
|
656
654
|
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
|
@@ -131,7 +131,7 @@ uint32_t KeyValueHolderCrypt::realValueSize() const {
|
|
|
131
131
|
|
|
132
132
|
// get decrypt data with [position, -1)
|
|
133
133
|
static MMBuffer decryptBuffer(AESCrypt &crypter, const MMBuffer &inputBuffer, size_t position) {
|
|
134
|
-
|
|
134
|
+
size_t smallBuffer[16 / sizeof(size_t)];
|
|
135
135
|
auto basePtr = (uint8_t *) inputBuffer.getPtr();
|
|
136
136
|
auto ptr = basePtr;
|
|
137
137
|
for (size_t index = sizeof(smallBuffer); index < position; index += sizeof(smallBuffer)) {
|
|
@@ -78,7 +78,11 @@ struct KeyValueHolderCrypt {
|
|
|
78
78
|
return sizeof(KeyValueHolderCrypt) - offsetof(KeyValueHolderCrypt, paddedValue);
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
static
|
|
81
|
+
static constexpr size_t MediumBufferSize() {
|
|
82
|
+
return 256;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
static bool isValueStoredAsOffset(size_t valueSize) { return valueSize > MediumBufferSize(); }
|
|
82
86
|
|
|
83
87
|
KeyValueHolderCrypt() = default;
|
|
84
88
|
KeyValueHolderCrypt(const void *valuePtr, size_t valueLength);
|
package/MMKV/Core/MMBuffer.h
CHANGED
|
@@ -59,7 +59,7 @@ class MMBuffer {
|
|
|
59
59
|
};
|
|
60
60
|
struct {
|
|
61
61
|
uint8_t paddedSize;
|
|
62
|
-
// make at least 10 bytes to hold all primitive types (negative int32, int64, double etc) on 32 bit device
|
|
62
|
+
// make at least 10 bytes to hold all primitive types (negative int32, int64, double etc.) on 32 bit device
|
|
63
63
|
// on 64 bit device it's guaranteed larger than 10 bytes
|
|
64
64
|
uint8_t paddedBuffer[10];
|
|
65
65
|
};
|
package/MMKV/Core/MMKV.cpp
CHANGED
|
@@ -98,7 +98,7 @@ MMKV::MMKV(const string &mmapID, MMKVMode mode, string *cryptKey, MMKVPath_t *ro
|
|
|
98
98
|
m_output = nullptr;
|
|
99
99
|
|
|
100
100
|
# ifndef MMKV_DISABLE_CRYPT
|
|
101
|
-
if (cryptKey && cryptKey->
|
|
101
|
+
if (cryptKey && !cryptKey->empty()) {
|
|
102
102
|
m_dicCrypt = new MMKVMapCrypt();
|
|
103
103
|
m_crypter = new AESCrypt(cryptKey->data(), cryptKey->length());
|
|
104
104
|
} else {
|
|
@@ -365,7 +365,7 @@ void MMKV::checkReSetCryptKey(const string *cryptKey) {
|
|
|
365
365
|
SCOPED_LOCK(m_lock);
|
|
366
366
|
|
|
367
367
|
if (m_crypter) {
|
|
368
|
-
if (cryptKey && cryptKey->
|
|
368
|
+
if (cryptKey && !cryptKey->empty()) {
|
|
369
369
|
string oldKey = this->cryptKey();
|
|
370
370
|
if (oldKey != *cryptKey) {
|
|
371
371
|
MMKVInfo("setting new aes key");
|
|
@@ -385,7 +385,7 @@ void MMKV::checkReSetCryptKey(const string *cryptKey) {
|
|
|
385
385
|
checkLoadData();
|
|
386
386
|
}
|
|
387
387
|
} else {
|
|
388
|
-
if (cryptKey && cryptKey->
|
|
388
|
+
if (cryptKey && !cryptKey->empty()) {
|
|
389
389
|
MMKVInfo("setting new aes key");
|
|
390
390
|
auto ptr = cryptKey->data();
|
|
391
391
|
m_crypter = new AESCrypt(ptr, cryptKey->length());
|
|
@@ -419,7 +419,7 @@ bool MMKV::checkFileCRCValid(size_t actualSize, uint32_t crcDigest) {
|
|
|
419
419
|
return false;
|
|
420
420
|
}
|
|
421
421
|
|
|
422
|
-
void MMKV::
|
|
422
|
+
void MMKV::recalculateCRCDigestWithIV(const void *iv) {
|
|
423
423
|
auto ptr = (const uint8_t *) m_file->getMemory();
|
|
424
424
|
if (ptr) {
|
|
425
425
|
m_crcDigest = 0;
|
|
@@ -428,7 +428,7 @@ void MMKV::recaculateCRCDigestWithIV(const void *iv) {
|
|
|
428
428
|
}
|
|
429
429
|
}
|
|
430
430
|
|
|
431
|
-
void MMKV::
|
|
431
|
+
void MMKV::recalculateCRCDigestOnly() {
|
|
432
432
|
auto ptr = (const uint8_t *) m_file->getMemory();
|
|
433
433
|
if (ptr) {
|
|
434
434
|
m_crcDigest = 0;
|
|
@@ -456,11 +456,11 @@ bool MMKV::set(bool value, MMKVKey_t key, uint32_t expireDuration) {
|
|
|
456
456
|
if (isKeyEmpty(key)) {
|
|
457
457
|
return false;
|
|
458
458
|
}
|
|
459
|
-
size_t size =
|
|
459
|
+
size_t size = mmkv_unlikely(m_enableKeyExpire) ? Fixed32Size + pbBoolSize() : pbBoolSize();
|
|
460
460
|
MMBuffer data(size);
|
|
461
461
|
CodedOutputData output(data.getPtr(), size);
|
|
462
462
|
output.writeBool(value);
|
|
463
|
-
if (
|
|
463
|
+
if (mmkv_unlikely(m_enableKeyExpire)) {
|
|
464
464
|
auto time = (expireDuration != ExpireNever) ? getCurrentTimeInSecond() + expireDuration : ExpireNever;
|
|
465
465
|
output.writeRawLittleEndian32(UInt32ToInt32(time));
|
|
466
466
|
} else {
|
|
@@ -478,11 +478,11 @@ bool MMKV::set(int32_t value, MMKVKey_t key, uint32_t expireDuration) {
|
|
|
478
478
|
if (isKeyEmpty(key)) {
|
|
479
479
|
return false;
|
|
480
480
|
}
|
|
481
|
-
size_t size =
|
|
481
|
+
size_t size = mmkv_unlikely(m_enableKeyExpire) ? Fixed32Size + pbInt32Size(value) : pbInt32Size(value);
|
|
482
482
|
MMBuffer data(size);
|
|
483
483
|
CodedOutputData output(data.getPtr(), size);
|
|
484
484
|
output.writeInt32(value);
|
|
485
|
-
if (
|
|
485
|
+
if (mmkv_unlikely(m_enableKeyExpire)) {
|
|
486
486
|
auto time = (expireDuration != ExpireNever) ? getCurrentTimeInSecond() + expireDuration : ExpireNever;
|
|
487
487
|
output.writeRawLittleEndian32(UInt32ToInt32(time));
|
|
488
488
|
} else {
|
|
@@ -500,11 +500,11 @@ bool MMKV::set(uint32_t value, MMKVKey_t key, uint32_t expireDuration) {
|
|
|
500
500
|
if (isKeyEmpty(key)) {
|
|
501
501
|
return false;
|
|
502
502
|
}
|
|
503
|
-
size_t size =
|
|
503
|
+
size_t size = mmkv_unlikely(m_enableKeyExpire) ? Fixed32Size + pbUInt32Size(value) : pbUInt32Size(value);
|
|
504
504
|
MMBuffer data(size);
|
|
505
505
|
CodedOutputData output(data.getPtr(), size);
|
|
506
506
|
output.writeUInt32(value);
|
|
507
|
-
if (
|
|
507
|
+
if (mmkv_unlikely(m_enableKeyExpire)) {
|
|
508
508
|
auto time = (expireDuration != ExpireNever) ? getCurrentTimeInSecond() + expireDuration : ExpireNever;
|
|
509
509
|
output.writeRawLittleEndian32(UInt32ToInt32(time));
|
|
510
510
|
} else {
|
|
@@ -522,11 +522,11 @@ bool MMKV::set(int64_t value, MMKVKey_t key, uint32_t expireDuration) {
|
|
|
522
522
|
if (isKeyEmpty(key)) {
|
|
523
523
|
return false;
|
|
524
524
|
}
|
|
525
|
-
size_t size =
|
|
525
|
+
size_t size = mmkv_unlikely(m_enableKeyExpire) ? Fixed32Size + pbInt64Size(value) : pbInt64Size(value);
|
|
526
526
|
MMBuffer data(size);
|
|
527
527
|
CodedOutputData output(data.getPtr(), size);
|
|
528
528
|
output.writeInt64(value);
|
|
529
|
-
if (
|
|
529
|
+
if (mmkv_unlikely(m_enableKeyExpire)) {
|
|
530
530
|
auto time = (expireDuration != ExpireNever) ? getCurrentTimeInSecond() + expireDuration : ExpireNever;
|
|
531
531
|
output.writeRawLittleEndian32(UInt32ToInt32(time));
|
|
532
532
|
} else {
|
|
@@ -544,11 +544,11 @@ bool MMKV::set(uint64_t value, MMKVKey_t key, uint32_t expireDuration) {
|
|
|
544
544
|
if (isKeyEmpty(key)) {
|
|
545
545
|
return false;
|
|
546
546
|
}
|
|
547
|
-
size_t size =
|
|
547
|
+
size_t size = mmkv_unlikely(m_enableKeyExpire) ? Fixed32Size + pbUInt64Size(value) : pbUInt64Size(value);
|
|
548
548
|
MMBuffer data(size);
|
|
549
549
|
CodedOutputData output(data.getPtr(), size);
|
|
550
550
|
output.writeUInt64(value);
|
|
551
|
-
if (
|
|
551
|
+
if (mmkv_unlikely(m_enableKeyExpire)) {
|
|
552
552
|
auto time = (expireDuration != ExpireNever) ? getCurrentTimeInSecond() + expireDuration : ExpireNever;
|
|
553
553
|
output.writeRawLittleEndian32(UInt32ToInt32(time));
|
|
554
554
|
} else {
|
|
@@ -566,11 +566,11 @@ bool MMKV::set(float value, MMKVKey_t key, uint32_t expireDuration) {
|
|
|
566
566
|
if (isKeyEmpty(key)) {
|
|
567
567
|
return false;
|
|
568
568
|
}
|
|
569
|
-
size_t size =
|
|
569
|
+
size_t size = mmkv_unlikely(m_enableKeyExpire) ? Fixed32Size + pbFloatSize() : pbFloatSize();
|
|
570
570
|
MMBuffer data(size);
|
|
571
571
|
CodedOutputData output(data.getPtr(), size);
|
|
572
572
|
output.writeFloat(value);
|
|
573
|
-
if (
|
|
573
|
+
if (mmkv_unlikely(m_enableKeyExpire)) {
|
|
574
574
|
auto time = (expireDuration != ExpireNever) ? getCurrentTimeInSecond() + expireDuration : ExpireNever;
|
|
575
575
|
output.writeRawLittleEndian32(UInt32ToInt32(time));
|
|
576
576
|
} else {
|
|
@@ -588,11 +588,11 @@ bool MMKV::set(double value, MMKVKey_t key, uint32_t expireDuration) {
|
|
|
588
588
|
if (isKeyEmpty(key)) {
|
|
589
589
|
return false;
|
|
590
590
|
}
|
|
591
|
-
size_t size =
|
|
591
|
+
size_t size = mmkv_unlikely(m_enableKeyExpire) ? Fixed32Size + pbDoubleSize() : pbDoubleSize();
|
|
592
592
|
MMBuffer data(size);
|
|
593
593
|
CodedOutputData output(data.getPtr(), size);
|
|
594
594
|
output.writeDouble(value);
|
|
595
|
-
if (
|
|
595
|
+
if (mmkv_unlikely(m_enableKeyExpire)) {
|
|
596
596
|
auto time = (expireDuration != ExpireNever) ? getCurrentTimeInSecond() + expireDuration : ExpireNever;
|
|
597
597
|
output.writeRawLittleEndian32(UInt32ToInt32(time));
|
|
598
598
|
} else {
|
|
@@ -604,6 +604,20 @@ bool MMKV::set(double value, MMKVKey_t key, uint32_t expireDuration) {
|
|
|
604
604
|
|
|
605
605
|
#ifndef MMKV_APPLE
|
|
606
606
|
|
|
607
|
+
bool MMKV::setDataForKey(mmkv::MMBuffer &&data, MMKV::MMKVKey_t key, uint32_t expireDuration) {
|
|
608
|
+
if (mmkv_likely(!m_enableKeyExpire)) {
|
|
609
|
+
assert(expireDuration == ExpireNever && "setting expire duration without calling enableAutoKeyExpire() first");
|
|
610
|
+
return setDataForKey(std::move(data), key, true);
|
|
611
|
+
} else {
|
|
612
|
+
auto tmp = MMBuffer(pbMMBufferSize(data) + Fixed32Size);
|
|
613
|
+
CodedOutputData output(tmp.getPtr(), tmp.length());
|
|
614
|
+
output.writeData(data);
|
|
615
|
+
auto time = (expireDuration != ExpireNever) ? getCurrentTimeInSecond() + expireDuration : ExpireNever;
|
|
616
|
+
output.writeRawLittleEndian32(UInt32ToInt32(time));
|
|
617
|
+
return setDataForKey(std::move(tmp), key);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
|
|
607
621
|
bool MMKV::set(const char *value, MMKVKey_t key) {
|
|
608
622
|
return set(value, key, m_expiredInSeconds);
|
|
609
623
|
}
|
|
@@ -613,21 +627,7 @@ bool MMKV::set(const char *value, MMKVKey_t key, uint32_t expireDuration) {
|
|
|
613
627
|
removeValueForKey(key);
|
|
614
628
|
return true;
|
|
615
629
|
}
|
|
616
|
-
|
|
617
|
-
assert(expireDuration == ExpireNever && "setting expire duration without calling enableAutoKeyExpire() first");
|
|
618
|
-
return setDataForKey(MMBuffer((void *) value, strlen(value), MMBufferNoCopy), key, true);
|
|
619
|
-
} else {
|
|
620
|
-
MMBuffer data((void *) value, strlen(value), MMBufferNoCopy);
|
|
621
|
-
if (data.length() > 0) {
|
|
622
|
-
auto tmp = MMBuffer(pbMMBufferSize(data) + Fixed32Size);
|
|
623
|
-
CodedOutputData output(tmp.getPtr(), tmp.length());
|
|
624
|
-
output.writeData(data);
|
|
625
|
-
auto time = (expireDuration != ExpireNever) ? getCurrentTimeInSecond() + expireDuration : ExpireNever;
|
|
626
|
-
output.writeRawLittleEndian32(UInt32ToInt32(time));
|
|
627
|
-
data = std::move(tmp);
|
|
628
|
-
}
|
|
629
|
-
return setDataForKey(std::move(data), key);
|
|
630
|
-
}
|
|
630
|
+
return setDataForKey(MMBuffer((void *) value, strlen(value), MMBufferNoCopy), key, expireDuration);
|
|
631
631
|
}
|
|
632
632
|
|
|
633
633
|
bool MMKV::set(const string &value, MMKVKey_t key) {
|
|
@@ -638,21 +638,18 @@ bool MMKV::set(const string &value, MMKVKey_t key, uint32_t expireDuration) {
|
|
|
638
638
|
if (isKeyEmpty(key)) {
|
|
639
639
|
return false;
|
|
640
640
|
}
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
output.writeRawLittleEndian32(UInt32ToInt32(time));
|
|
652
|
-
data = std::move(tmp);
|
|
653
|
-
}
|
|
654
|
-
return setDataForKey(std::move(data), key);
|
|
641
|
+
return setDataForKey(MMBuffer((void *) value.data(), value.length(), MMBufferNoCopy), key, expireDuration);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
bool MMKV::set(string_view value, MMKVKey_t key) {
|
|
645
|
+
return set(value, key, m_expiredInSeconds);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
bool MMKV::set(string_view value, MMKVKey_t key, uint32_t expireDuration) {
|
|
649
|
+
if (isKeyEmpty(key)) {
|
|
650
|
+
return false;
|
|
655
651
|
}
|
|
652
|
+
return setDataForKey(MMBuffer((void *) value.data(), value.length(), MMBufferNoCopy), key, expireDuration);
|
|
656
653
|
}
|
|
657
654
|
|
|
658
655
|
bool MMKV::set(const MMBuffer &value, MMKVKey_t key) {
|
|
@@ -663,23 +660,7 @@ bool MMKV::set(const MMBuffer &value, MMKVKey_t key, uint32_t expireDuration) {
|
|
|
663
660
|
if (isKeyEmpty(key)) {
|
|
664
661
|
return false;
|
|
665
662
|
}
|
|
666
|
-
|
|
667
|
-
// avoid memory copying
|
|
668
|
-
if (likely(!m_enableKeyExpire)) {
|
|
669
|
-
assert(expireDuration == ExpireNever && "setting expire duration without calling enableAutoKeyExpire() first");
|
|
670
|
-
return setDataForKey(MMBuffer(value.getPtr(), value.length(), MMBufferNoCopy), key, true);
|
|
671
|
-
} else {
|
|
672
|
-
MMBuffer data(value.getPtr(), value.length(), MMBufferNoCopy);
|
|
673
|
-
if (data.length() > 0) {
|
|
674
|
-
auto tmp = MMBuffer(pbMMBufferSize(data) + Fixed32Size);
|
|
675
|
-
CodedOutputData output(tmp.getPtr(), tmp.length());
|
|
676
|
-
output.writeData(data);
|
|
677
|
-
auto time = (expireDuration != ExpireNever) ? getCurrentTimeInSecond() + expireDuration : ExpireNever;
|
|
678
|
-
output.writeRawLittleEndian32(UInt32ToInt32(time));
|
|
679
|
-
data = std::move(tmp);
|
|
680
|
-
}
|
|
681
|
-
return setDataForKey(std::move(data), key);
|
|
682
|
-
}
|
|
663
|
+
return setDataForKey(MMBuffer(value.getPtr(), value.length(), MMBufferNoCopy), key, expireDuration);
|
|
683
664
|
}
|
|
684
665
|
|
|
685
666
|
bool MMKV::set(const vector<string> &value, MMKVKey_t key) {
|
|
@@ -690,8 +671,12 @@ bool MMKV::set(const vector<string> &v, MMKVKey_t key, uint32_t expireDuration)
|
|
|
690
671
|
if (isKeyEmpty(key)) {
|
|
691
672
|
return false;
|
|
692
673
|
}
|
|
674
|
+
#ifdef MMKV_HAS_CPP20
|
|
675
|
+
auto data = MiniPBCoder::encodeDataWithObject(std::span(v));
|
|
676
|
+
#else
|
|
693
677
|
auto data = MiniPBCoder::encodeDataWithObject(v);
|
|
694
|
-
|
|
678
|
+
#endif
|
|
679
|
+
if (mmkv_unlikely(m_enableKeyExpire) && data.length() > 0) {
|
|
695
680
|
auto tmp = MMBuffer(data.length() + Fixed32Size);
|
|
696
681
|
auto ptr = (uint8_t *) tmp.getPtr();
|
|
697
682
|
memcpy(ptr, data.getPtr(), data.length());
|
|
@@ -788,6 +773,16 @@ bool MMKV::getVector(MMKVKey_t key, vector<string> &result) {
|
|
|
788
773
|
return false;
|
|
789
774
|
}
|
|
790
775
|
|
|
776
|
+
void MMKV::shared_lock() {
|
|
777
|
+
m_lock->lock();
|
|
778
|
+
m_sharedProcessLock->lock();
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
void MMKV::shared_unlock() {
|
|
782
|
+
m_sharedProcessLock->lock();
|
|
783
|
+
m_lock->lock();
|
|
784
|
+
}
|
|
785
|
+
|
|
791
786
|
#endif // MMKV_APPLE
|
|
792
787
|
|
|
793
788
|
bool MMKV::getBool(MMKVKey_t key, bool defaultValue, bool *hasValue) {
|
|
@@ -1060,7 +1055,7 @@ bool MMKV::containsKey(MMKVKey_t key) {
|
|
|
1060
1055
|
SCOPED_LOCK(m_lock);
|
|
1061
1056
|
checkLoadData();
|
|
1062
1057
|
|
|
1063
|
-
if (
|
|
1058
|
+
if (mmkv_likely(!m_enableKeyExpire)) {
|
|
1064
1059
|
if (m_crypter) {
|
|
1065
1060
|
return m_dicCrypt->find(key) != m_dicCrypt->end();
|
|
1066
1061
|
} else {
|
|
@@ -1075,7 +1070,7 @@ size_t MMKV::count(bool filterExpire) {
|
|
|
1075
1070
|
SCOPED_LOCK(m_lock);
|
|
1076
1071
|
checkLoadData();
|
|
1077
1072
|
|
|
1078
|
-
if (
|
|
1073
|
+
if (mmkv_unlikely(filterExpire && m_enableKeyExpire)) {
|
|
1079
1074
|
SCOPED_LOCK(m_exclusiveProcessLock);
|
|
1080
1075
|
fullWriteback(nullptr, true);
|
|
1081
1076
|
}
|
|
@@ -1116,7 +1111,7 @@ vector<string> MMKV::allKeys(bool filterExpire) {
|
|
|
1116
1111
|
SCOPED_LOCK(m_lock);
|
|
1117
1112
|
checkLoadData();
|
|
1118
1113
|
|
|
1119
|
-
if (
|
|
1114
|
+
if (mmkv_unlikely(filterExpire && m_enableKeyExpire)) {
|
|
1120
1115
|
SCOPED_LOCK(m_exclusiveProcessLock);
|
|
1121
1116
|
fullWriteback(nullptr, true);
|
|
1122
1117
|
}
|
|
@@ -1220,7 +1215,7 @@ static bool backupOneToDirectoryByFilePath(const string &mmapKey, const MMKVPath
|
|
|
1220
1215
|
return false;
|
|
1221
1216
|
}
|
|
1222
1217
|
|
|
1223
|
-
bool ret
|
|
1218
|
+
bool ret;
|
|
1224
1219
|
{
|
|
1225
1220
|
#ifdef MMKV_WIN32
|
|
1226
1221
|
MMKVInfo("backup one mmkv[%s] from [%ls] to [%ls]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
|
|
@@ -1346,7 +1341,8 @@ size_t MMKV::backupAllToDirectory(const MMKVPath_t &dstDir, const MMKVPath_t &sr
|
|
|
1346
1341
|
auto basename = filename(srcPath);
|
|
1347
1342
|
const auto &strBasename = MMKVPath_t2String(basename);
|
|
1348
1343
|
auto mmapKey = isInSpecialDir ? strBasename : mmapedKVKey(strBasename, &srcDir);
|
|
1349
|
-
auto dstPath = dstDir + MMKV_PATH_SLASH
|
|
1344
|
+
auto dstPath = dstDir + MMKV_PATH_SLASH;
|
|
1345
|
+
dstPath += basename;
|
|
1350
1346
|
if (backupOneToDirectory(mmapKey, dstPath, srcPath, compareFullPath)) {
|
|
1351
1347
|
count++;
|
|
1352
1348
|
}
|
|
@@ -1379,7 +1375,7 @@ static bool restoreOneFromDirectoryByFilePath(const string &mmapKey, const MMKVP
|
|
|
1379
1375
|
return false;
|
|
1380
1376
|
}
|
|
1381
1377
|
|
|
1382
|
-
bool ret
|
|
1378
|
+
bool ret;
|
|
1383
1379
|
{
|
|
1384
1380
|
#ifdef MMKV_WIN32
|
|
1385
1381
|
MMKVInfo("restore one mmkv[%s] from [%ls] to [%ls]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
|
|
@@ -1510,7 +1506,8 @@ size_t MMKV::restoreAllFromDirectory(const MMKVPath_t &srcDir, const MMKVPath_t
|
|
|
1510
1506
|
auto basename = filename(srcPath);
|
|
1511
1507
|
const auto &strBasename = MMKVPath_t2String(basename);
|
|
1512
1508
|
auto mmapKey = isInSpecialDir ? strBasename : mmapedKVKey(strBasename, &dstDir);
|
|
1513
|
-
auto dstPath = dstDir + MMKV_PATH_SLASH
|
|
1509
|
+
auto dstPath = dstDir + MMKV_PATH_SLASH;
|
|
1510
|
+
dstPath += basename;
|
|
1514
1511
|
if (restoreOneFromDirectory(mmapKey, srcPath, dstPath, compareFullPath)) {
|
|
1515
1512
|
count++;
|
|
1516
1513
|
}
|
package/MMKV/Core/MMKV.h
CHANGED
|
@@ -21,9 +21,22 @@
|
|
|
21
21
|
#ifndef MMKV_MMKV_H
|
|
22
22
|
#define MMKV_MMKV_H
|
|
23
23
|
#ifdef __cplusplus
|
|
24
|
+
#include "MMKVPredef.h"
|
|
25
|
+
|
|
26
|
+
#ifdef MMKV_APPLE
|
|
27
|
+
|
|
28
|
+
# include "MMBuffer.h"
|
|
29
|
+
# ifdef MMKV_HAS_CPP20
|
|
30
|
+
# include <span>
|
|
31
|
+
# endif
|
|
32
|
+
|
|
33
|
+
#else
|
|
34
|
+
# include "MiniPBCoder.h"
|
|
35
|
+
#endif
|
|
24
36
|
|
|
25
|
-
#include "MMBuffer.h"
|
|
26
37
|
#include <cstdint>
|
|
38
|
+
#include <type_traits>
|
|
39
|
+
#include <cstring>
|
|
27
40
|
|
|
28
41
|
namespace mmkv {
|
|
29
42
|
class CodedOutputData;
|
|
@@ -49,6 +62,32 @@ enum MMKVMode : uint32_t {
|
|
|
49
62
|
|
|
50
63
|
#define MMKV_OUT
|
|
51
64
|
|
|
65
|
+
#ifdef MMKV_HAS_CPP20
|
|
66
|
+
template <class T>
|
|
67
|
+
struct mmkv_is_vector { static constexpr bool value = false; };
|
|
68
|
+
template <class T, class A>
|
|
69
|
+
struct mmkv_is_vector<std::vector<T, A>> { static constexpr bool value = true; };
|
|
70
|
+
template <class T, size_t S>
|
|
71
|
+
struct mmkv_is_vector<std::span<T, S>> { static constexpr bool value = true; };
|
|
72
|
+
template <class T>
|
|
73
|
+
inline constexpr bool mmkv_is_vector_v = mmkv_is_vector<T>::value;
|
|
74
|
+
|
|
75
|
+
template <class T>
|
|
76
|
+
concept MMKV_SUPPORTED_PRIMITIVE_VALUE_TYPE = std::is_integral_v<T> || std::is_floating_point_v<T>;
|
|
77
|
+
|
|
78
|
+
template <class T>
|
|
79
|
+
concept MMKV_SUPPORTED_POD_VALUE_TYPE = std::is_same_v<T, const char*> || std::is_same_v<T, std::string> ||
|
|
80
|
+
std::is_same_v<T, mmkv::MMBuffer>;
|
|
81
|
+
|
|
82
|
+
template <class T>
|
|
83
|
+
concept MMKV_SUPPORTED_VECTOR_VALUE_TYPE = mmkv_is_vector_v<T> &&
|
|
84
|
+
(MMKV_SUPPORTED_PRIMITIVE_VALUE_TYPE<typename T::value_type> || MMKV_SUPPORTED_POD_VALUE_TYPE<typename T::value_type>);
|
|
85
|
+
|
|
86
|
+
template <class T>
|
|
87
|
+
concept MMKV_SUPPORTED_VALUE_TYPE = MMKV_SUPPORTED_PRIMITIVE_VALUE_TYPE<T> || MMKV_SUPPORTED_POD_VALUE_TYPE<T> ||
|
|
88
|
+
MMKV_SUPPORTED_VECTOR_VALUE_TYPE<T>;
|
|
89
|
+
#endif // MMKV_HAS_CPP20
|
|
90
|
+
|
|
52
91
|
class MMKV {
|
|
53
92
|
#ifndef MMKV_ANDROID
|
|
54
93
|
std::string m_mmapKey;
|
|
@@ -103,12 +142,12 @@ class MMKV {
|
|
|
103
142
|
# define mmkv_retain_key(key) [key retain]
|
|
104
143
|
# define mmkv_release_key(key) [key release]
|
|
105
144
|
#else
|
|
106
|
-
using MMKVKey_t =
|
|
145
|
+
using MMKVKey_t = std::string_view;
|
|
107
146
|
static bool isKeyEmpty(MMKVKey_t key) { return key.empty(); }
|
|
108
147
|
# define mmkv_key_length(key) key.length()
|
|
109
148
|
# define mmkv_retain_key(key) ((void) 0)
|
|
110
149
|
# define mmkv_release_key(key) ((void) 0)
|
|
111
|
-
#endif
|
|
150
|
+
#endif // !MMKV_APPLE
|
|
112
151
|
|
|
113
152
|
void loadFromFile();
|
|
114
153
|
|
|
@@ -124,8 +163,8 @@ class MMKV {
|
|
|
124
163
|
|
|
125
164
|
bool checkFileCRCValid(size_t actualSize, uint32_t crcDigest);
|
|
126
165
|
|
|
127
|
-
void
|
|
128
|
-
void
|
|
166
|
+
void recalculateCRCDigestWithIV(const void *iv);
|
|
167
|
+
void recalculateCRCDigestOnly();
|
|
129
168
|
|
|
130
169
|
void updateCRCDigest(const uint8_t *ptr, size_t length);
|
|
131
170
|
|
|
@@ -151,6 +190,9 @@ class MMKV {
|
|
|
151
190
|
|
|
152
191
|
// isDataHolder: avoid memory copying
|
|
153
192
|
bool setDataForKey(mmkv::MMBuffer &&data, MMKVKey_t key, bool isDataHolder = false);
|
|
193
|
+
#ifndef MMKV_APPLE
|
|
194
|
+
bool setDataForKey(mmkv::MMBuffer &&data, MMKVKey_t key, uint32_t expireDuration);
|
|
195
|
+
#endif
|
|
154
196
|
|
|
155
197
|
bool removeDataForKey(MMKVKey_t key);
|
|
156
198
|
|
|
@@ -190,6 +232,12 @@ class MMKV {
|
|
|
190
232
|
mmkv::MMBuffer getDataWithoutMTimeForKey(MMKVKey_t key);
|
|
191
233
|
size_t filterExpiredKeys();
|
|
192
234
|
|
|
235
|
+
#ifndef MMKV_APPLE
|
|
236
|
+
static constexpr uint32_t ConstFixed32Size = 4;
|
|
237
|
+
void shared_lock();
|
|
238
|
+
void shared_unlock();
|
|
239
|
+
#endif
|
|
240
|
+
|
|
193
241
|
public:
|
|
194
242
|
// call this before getting any MMKV instance
|
|
195
243
|
static void initializeMMKV(const MMKVPath_t &rootDir, MMKVLogLevel logLevel = MMKVLogInfo, mmkv::LogHandler handler = nullptr);
|
|
@@ -199,7 +247,7 @@ public:
|
|
|
199
247
|
|
|
200
248
|
#ifndef MMKV_ANDROID
|
|
201
249
|
|
|
202
|
-
// mmapID: any unique ID (com.tencent.xin.pay, etc)
|
|
250
|
+
// mmapID: any unique ID (com.tencent.xin.pay, etc.)
|
|
203
251
|
// if you want a per-user mmkv, you could merge user-id within mmapID
|
|
204
252
|
// cryptKey: 16 bytes at most
|
|
205
253
|
static MMKV *mmkvWithID(const std::string &mmapID,
|
|
@@ -210,7 +258,7 @@ public:
|
|
|
210
258
|
|
|
211
259
|
#else // defined(MMKV_ANDROID)
|
|
212
260
|
|
|
213
|
-
// mmapID: any unique ID (com.tencent.xin.pay, etc)
|
|
261
|
+
// mmapID: any unique ID (com.tencent.xin.pay, etc.)
|
|
214
262
|
// if you want a per-user mmkv, you could merge user-id within mmapID
|
|
215
263
|
// cryptKey: 16 bytes at most
|
|
216
264
|
static MMKV *mmkvWithID(const std::string &mmapID,
|
|
@@ -269,11 +317,21 @@ public:
|
|
|
269
317
|
bool set(double value, MMKVKey_t key);
|
|
270
318
|
bool set(double value, MMKVKey_t key, uint32_t expireDuration);
|
|
271
319
|
|
|
272
|
-
|
|
320
|
+
#ifdef MMKV_HAS_CPP20
|
|
321
|
+
// avoid unexpected type conversion (pointer to bool, etc.)
|
|
273
322
|
template <typename T>
|
|
323
|
+
requires(!MMKV_SUPPORTED_VALUE_TYPE<T>)
|
|
274
324
|
bool set(T value, MMKVKey_t key) = delete;
|
|
325
|
+
|
|
326
|
+
// avoid unexpected type conversion (pointer to bool, etc.)
|
|
275
327
|
template <typename T>
|
|
328
|
+
requires(!MMKV_SUPPORTED_VALUE_TYPE<T>)
|
|
276
329
|
bool set(T value, MMKVKey_t key, uint32_t expireDuration) = delete;
|
|
330
|
+
#else
|
|
331
|
+
// avoid unexpected type conversion (pointer to bool, etc.)
|
|
332
|
+
template <typename T>
|
|
333
|
+
bool set(T value, MMKVKey_t key, uint32_t expireDuration) = delete;
|
|
334
|
+
#endif
|
|
277
335
|
|
|
278
336
|
#ifdef MMKV_APPLE
|
|
279
337
|
bool set(NSObject<NSCoding> *__unsafe_unretained obj, MMKVKey_t key);
|
|
@@ -287,12 +345,28 @@ public:
|
|
|
287
345
|
bool set(const std::string &value, MMKVKey_t key);
|
|
288
346
|
bool set(const std::string &value, MMKVKey_t key, uint32_t expireDuration);
|
|
289
347
|
|
|
348
|
+
bool set(std::string_view value, MMKVKey_t key);
|
|
349
|
+
bool set(std::string_view value, MMKVKey_t key, uint32_t expireDuration);
|
|
350
|
+
|
|
290
351
|
bool set(const mmkv::MMBuffer &value, MMKVKey_t key);
|
|
291
352
|
bool set(const mmkv::MMBuffer &value, MMKVKey_t key, uint32_t expireDuration);
|
|
292
353
|
|
|
293
354
|
bool set(const std::vector<std::string> &vector, MMKVKey_t key);
|
|
294
355
|
bool set(const std::vector<std::string> &vector, MMKVKey_t key, uint32_t expireDuration);
|
|
295
356
|
|
|
357
|
+
#ifdef MMKV_HAS_CPP20
|
|
358
|
+
template<MMKV_SUPPORTED_VECTOR_VALUE_TYPE T>
|
|
359
|
+
bool set(const T& value, MMKVKey_t key) {
|
|
360
|
+
return set<T>(value, key, m_expiredInSeconds);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
template<MMKV_SUPPORTED_VECTOR_VALUE_TYPE T>
|
|
364
|
+
bool set(const T& value, MMKVKey_t key, uint32_t expireDuration);
|
|
365
|
+
|
|
366
|
+
template<MMKV_SUPPORTED_VECTOR_VALUE_TYPE T>
|
|
367
|
+
bool getVector(MMKVKey_t key, T &result);
|
|
368
|
+
#endif
|
|
369
|
+
|
|
296
370
|
// inplaceModification is recommended for faster speed
|
|
297
371
|
bool getString(MMKVKey_t key, std::string &result, bool inplaceModification = true);
|
|
298
372
|
|
|
@@ -346,9 +420,9 @@ public:
|
|
|
346
420
|
bool enableCompareBeforeSet();
|
|
347
421
|
bool disableCompareBeforeSet();
|
|
348
422
|
|
|
349
|
-
bool isExpirationEnabled() { return m_enableKeyExpire; }
|
|
350
|
-
bool isEncryptionEnabled() { return m_dicCrypt; }
|
|
351
|
-
bool isCompareBeforeSetEnabled() { return m_enableCompareBeforeSet && !m_enableKeyExpire && !m_dicCrypt; }
|
|
423
|
+
bool isExpirationEnabled() const { return m_enableKeyExpire; }
|
|
424
|
+
bool isEncryptionEnabled() const { return m_dicCrypt; }
|
|
425
|
+
bool isCompareBeforeSetEnabled() const { return m_enableCompareBeforeSet && !m_enableKeyExpire && !m_dicCrypt; }
|
|
352
426
|
|
|
353
427
|
#ifdef MMKV_APPLE
|
|
354
428
|
// filterExpire: return all non-expired keys, keep in mind it comes with cost
|
|
@@ -460,6 +534,47 @@ public:
|
|
|
460
534
|
MMKV &operator=(const MMKV &other) = delete;
|
|
461
535
|
};
|
|
462
536
|
|
|
537
|
+
#if defined(MMKV_HAS_CPP20) && !defined(MMKV_APPLE)
|
|
538
|
+
template<MMKV_SUPPORTED_VECTOR_VALUE_TYPE T>
|
|
539
|
+
bool MMKV::set(const T& value, MMKVKey_t key, uint32_t expireDuration) {
|
|
540
|
+
if (isKeyEmpty(key)) {
|
|
541
|
+
return false;
|
|
542
|
+
}
|
|
543
|
+
mmkv::MMBuffer data;
|
|
544
|
+
if constexpr (std::is_same_v<T, std::vector<bool>>) {
|
|
545
|
+
data = mmkv::MiniPBCoder::encodeDataWithObject(value);
|
|
546
|
+
} else {
|
|
547
|
+
data = mmkv::MiniPBCoder::encodeDataWithObject(std::span(value));
|
|
548
|
+
}
|
|
549
|
+
if (mmkv_unlikely(m_enableKeyExpire) && data.length() > 0) {
|
|
550
|
+
auto tmp = mmkv::MMBuffer(data.length() + ConstFixed32Size);
|
|
551
|
+
auto ptr = (uint8_t *) tmp.getPtr();
|
|
552
|
+
memcpy(ptr, data.getPtr(), data.length());
|
|
553
|
+
auto time = (expireDuration != ExpireNever) ? getCurrentTimeInSecond() + expireDuration : ExpireNever;
|
|
554
|
+
memcpy(ptr + data.length(), &time, ConstFixed32Size);
|
|
555
|
+
data = std::move(tmp);
|
|
556
|
+
}
|
|
557
|
+
return setDataForKey(std::move(data), key);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
template<MMKV_SUPPORTED_VECTOR_VALUE_TYPE T>
|
|
561
|
+
bool MMKV::getVector(MMKVKey_t key, T &result) {
|
|
562
|
+
if (isKeyEmpty(key)) {
|
|
563
|
+
return false;
|
|
564
|
+
}
|
|
565
|
+
shared_lock();
|
|
566
|
+
|
|
567
|
+
bool ret = false;
|
|
568
|
+
auto data = getDataForKey(key);
|
|
569
|
+
if (data.length() > 0) {
|
|
570
|
+
ret = mmkv::MiniPBCoder::decodeVector(data, result);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
shared_unlock();
|
|
574
|
+
return ret;
|
|
575
|
+
}
|
|
576
|
+
#endif // MMKV_HAS_CPP20 && !MMKV_APPLE
|
|
577
|
+
|
|
463
578
|
MMKV_NAMESPACE_END
|
|
464
579
|
|
|
465
580
|
#endif
|