Files
2026-06-02 19:06:09 +08:00

792 lines
29 KiB
C++
Executable File

/*
* Tencent is pleased to support the open source community by making
* MMKV available.
*
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of
* the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MMKV_MMKV_H
#define MMKV_MMKV_H
#ifdef __cplusplus
#include "MMKVPredef.h"
#ifdef MMKV_APPLE
# include "MMBuffer.h"
# ifdef MMKV_HAS_CPP20
# include <span>
# endif
#endif
#include "MiniPBCoder.h"
#include "MMKVHandler.h"
#include <cstdint>
#include <type_traits>
#include <cstring>
#include <optional>
namespace mmkv {
class CodedOutputData;
class MemoryFile;
class AESCrypt;
struct MMKVMetaInfo;
class FileLock;
class InterProcessLock;
class ThreadLock;
class NameSpace;
} // namespace mmkv
MMKV_NAMESPACE_BEGIN
enum MMKVMode : uint32_t {
MMKV_SINGLE_PROCESS = 1 << 0,
MMKV_MULTI_PROCESS = 1 << 1,
#ifdef MMKV_ANDROID
CONTEXT_MODE_MULTI_PROCESS = 1 << 2, // in case someone mistakenly pass Context.MODE_MULTI_PROCESS
MMKV_ASHMEM = 1 << 3,
MMKV_BACKUP = 1 << 4,
#endif
MMKV_READ_ONLY = 1 << 5,
};
static inline MMKVMode operator | (MMKVMode one, MMKVMode other) {
return static_cast<MMKVMode>(static_cast<uint32_t>(one) | static_cast<uint32_t>(other));
}
// all-in-one configuration for creating MMKV instance
struct MMKVConfig {
MMKVMode mode = MMKV_SINGLE_PROCESS;
#ifndef MMKV_DISABLE_CRYPT
bool aes256 = false; // using AES-256 key length
const std::string *cryptKey = nullptr;
#endif
const MMKVPath_t *rootPath = nullptr;
size_t expectedCapacity = 0; // the initial file size
std::optional<bool> enableKeyExpire = std::nullopt;
uint32_t expiredInSeconds = 0; // ExpireNever = 0
bool enableCompareBeforeSet = false;
std::optional<MMKVRecoverStrategic> recover = std::nullopt; // if not set, use the old style callback
uint32_t itemSizeLimit = 0; // the size limit of a key-value pair, reject insert if pass limit
};
#define MMKV_OUT
#ifdef MMKV_HAS_CPP20
template <class T>
struct mmkv_is_vector { static constexpr bool value = false; };
template <class T, class A>
struct mmkv_is_vector<std::vector<T, A>> { static constexpr bool value = true; };
template <class T, size_t S>
struct mmkv_is_vector<std::span<T, S>> { static constexpr bool value = true; };
template <class T>
inline constexpr bool mmkv_is_vector_v = mmkv_is_vector<T>::value;
template <class T>
concept MMKV_SUPPORTED_PRIMITIVE_VALUE_TYPE = std::is_integral_v<T> || std::is_floating_point_v<T>;
template <class T>
concept MMKV_SUPPORTED_POD_VALUE_TYPE = std::is_same_v<T, const char*> || std::is_same_v<T, std::string> ||
std::is_same_v<T, mmkv::MMBuffer>;
template <class T>
concept MMKV_SUPPORTED_VECTOR_VALUE_TYPE = mmkv_is_vector_v<T> &&
(MMKV_SUPPORTED_PRIMITIVE_VALUE_TYPE<typename T::value_type> || MMKV_SUPPORTED_POD_VALUE_TYPE<typename T::value_type>);
template <class T>
concept MMKV_SUPPORTED_VALUE_TYPE = MMKV_SUPPORTED_PRIMITIVE_VALUE_TYPE<T> || MMKV_SUPPORTED_POD_VALUE_TYPE<T> ||
MMKV_SUPPORTED_VECTOR_VALUE_TYPE<T>;
#endif // MMKV_HAS_CPP20
class MMKV_EXPORT MMKV {
MMKV(const std::string &mmapID, const MMKVConfig &config);
#ifdef MMKV_ANDROID
#ifndef MMKV_OHOS
mmkv::FileLock *m_fileModeLock;
mmkv::InterProcessLock *m_sharedProcessModeLock;
mmkv::InterProcessLock *m_exclusiveProcessModeLock;
#endif // !MMKV_OHOS
mmkv::FileLock *m_fileMigrationLock;
mmkv::InterProcessLock *m_sharedMigrationLock;
MMKV(const std::string &mmapID, int ashmemFD, int ashmemMetaFd, const MMKVConfig &config);
#endif // MMKV_ANDROID
~MMKV();
std::string m_mmapKey;
std::string m_mmapID;
const MMKVMode m_mode;
MMKVPath_t m_path;
MMKVPath_t m_crcPath;
mmkv::MMKVMap *m_dic;
mmkv::MMKVMapCrypt *m_dicCrypt;
size_t m_expectedCapacity;
mmkv::MemoryFile *m_file;
size_t m_actualSize;
mmkv::CodedOutputData *m_output;
bool m_needLoadFromFile;
bool m_hasFullWriteback;
uint32_t m_crcDigest;
mmkv::MemoryFile *m_metaFile;
mmkv::MMKVMetaInfo *m_metaInfo;
mmkv::AESCrypt *m_crypter;
mmkv::ThreadLock *m_lock;
mmkv::FileLock *m_fileLock;
mmkv::InterProcessLock *m_sharedProcessLock;
mmkv::InterProcessLock *m_exclusiveProcessLock;
bool m_enableKeyExpire = false;
uint32_t m_expiredInSeconds = ExpireNever;
bool m_enableCompareBeforeSet = false;
std::optional<MMKVRecoverStrategic> m_recoverStrategic = std::nullopt;
uint32_t m_itemSizeLimit = 0;
#ifdef MMKV_APPLE
#ifdef __OBJC__
using MMKVKey_t = NSString *__unsafe_unretained;
static bool isKeyEmpty(MMKVKey_t key) { return key.length <= 0; }
# define mmkv_key_length(key) key.length
# define mmkv_retain_key(key) [key retain]
# define mmkv_release_key(key) [key release]
#else
using MMKVKey_t = std::string_view;
static bool isKeyEmpty(MMKVKey_t key) { return key.empty(); }
#endif // __OBJC__
#else
using MMKVKey_t = std::string_view;
static bool isKeyEmpty(MMKVKey_t key) { return key.empty(); }
# define mmkv_key_length(key) key.length()
# define mmkv_retain_key(key) ((void) 0)
# define mmkv_release_key(key) ((void) 0)
#endif // !MMKV_APPLE
void loadFromFile();
void partialLoadFromFile();
//#if defined(MMKV_APPLE) || defined(MMKV_WIN32)
// the disk corruption detection is tested in iOS/Win32, but not Android
// let's assume what works for iOS also works on Android for they are all POSIX
bool m_isSecondLoad = false;
bool checkFileHasDiskError();
//#else
// bool checkFileHasDiskError() { return false; }
//#endif
void loadMetaInfoAndCheck();
void checkDataValid(bool &loadFromFile, bool &needFullWriteback);
void checkLoadData();
bool isFileValid();
bool checkFileCRCValid(size_t actualSize, uint32_t crcDigest);
void recalculateCRCDigestWithIV(const void *iv);
void recalculateCRCDigestOnly();
void updateCRCDigest(const uint8_t *ptr, size_t length);
size_t readActualSize();
void oldStyleWriteActualSize(size_t actualSize);
bool writeActualSize(size_t size, uint32_t crcDigest, const void *iv, bool increaseSequence);
bool ensureMemorySize(size_t newSize);
bool expandAndWriteBack(size_t newSize, std::pair<mmkv::MMBuffer, size_t> preparedData, bool needSync = true);
bool fullWriteback(mmkv::AESCrypt *newCrypter = nullptr, bool onlyWhileExpire = false);
bool doFullWriteBack(std::pair<mmkv::MMBuffer, size_t> preparedData, mmkv::AESCrypt *newCrypter, bool needSync = true);
bool doFullWriteBack(mmkv::MMKVVector &&vec);
mmkv::MMBuffer getRawDataForKey(MMKVKey_t key);
mmkv::MMBuffer getDataForKey(MMKVKey_t key);
// isDataHolder: avoid memory copying
bool setDataForKey(mmkv::MMBuffer &&data, MMKVKey_t key, bool isDataHolder = false);
bool setDataForKey(mmkv::MMBuffer &&data, MMKVKey_t key, uint32_t expireDuration);
bool removeDataForKey(MMKVKey_t key);
using KVHolderRet_t = std::pair<bool, mmkv::KeyValueHolder>;
// isDataHolder: avoid memory copying
KVHolderRet_t doAppendDataWithKey(const mmkv::MMBuffer &data, const mmkv::MMBuffer &key, bool isDataHolder, uint32_t keyLength);
KVHolderRet_t appendDataWithKey(const mmkv::MMBuffer &data, MMKVKey_t key, bool isDataHolder = false);
KVHolderRet_t appendDataWithKey(const mmkv::MMBuffer &data, const mmkv::KeyValueHolder &kvHolder, bool isDataHolder = false);
KVHolderRet_t doOverrideDataWithKey(const mmkv::MMBuffer &data, const mmkv::MMBuffer &key, bool isDataHolder, uint32_t keyLength);
KVHolderRet_t overrideDataWithKey(const mmkv::MMBuffer &data, const mmkv::KeyValueHolder &kvHolder, bool isDataHolder = false);
KVHolderRet_t overrideDataWithKey(const mmkv::MMBuffer &data, MMKVKey_t key, bool isDataHolder = false);
bool checkSizeForOverride(size_t size);
#ifdef MMKV_APPLE
#ifdef __OBJC__
mmkv::MMBuffer getDataForKey(std::string_view key);
bool setDataForKey(mmkv::MMBuffer &&data, std::string_view key, bool isDataHolder = false);
#endif
KVHolderRet_t appendDataWithKey(const mmkv::MMBuffer &data,
MMKVKey_t key,
const mmkv::KeyValueHolderCrypt &kvHolder,
bool isDataHolder = false);
KVHolderRet_t overrideDataWithKey(const mmkv::MMBuffer &data,
MMKVKey_t key,
const mmkv::KeyValueHolderCrypt &kvHolder,
bool isDataHolder = false);
#endif
void notifyContentChanged();
void notifyContentLoaded();
#if defined(MMKV_ANDROID) && !defined(MMKV_DISABLE_CRYPT)
void checkReSetCryptKey(int fd, int metaFD, const std::string *cryptKey, bool aes256);
#endif
static bool backupOneToDirectory(const std::string &mmapKey, const MMKVPath_t &dstPath, const MMKVPath_t &srcPath, bool compareFullPath);
static size_t backupAllToDirectory(const MMKVPath_t &dstDir, const MMKVPath_t &srcDir, bool isInSpecialDir);
static bool restoreOneFromDirectory(const std::string &mmapKey, const MMKVPath_t &srcPath, const MMKVPath_t &dstPath, bool compareFullPath);
static size_t restoreAllFromDirectory(const MMKVPath_t &srcDir, const MMKVPath_t &dstDir, bool isInSpecialDir);
static uint32_t getCurrentTimeInSecond();
static uint32_t safeExpirationPlusCurrentTime(uint32_t expireDuration);
uint32_t getExpireTimeForKey(MMKVKey_t key);
mmkv::MMBuffer getDataWithoutMTimeForKey(MMKVKey_t key);
size_t filterExpiredKeys();
static constexpr uint32_t ConstFixed32Size = 4;
void shared_lock();
void shared_unlock();
// assuming rootPath is absolute
static MMKV *getMMKVWithID(const std::string &mmapID, const MMKVConfig &config);
void configAutoExipreIfNeeded(const MMKVConfig &config);
bool checkSizeLimit(size_t size, const mmkv::MMBuffer &keyData, uint32_t originKeyLength);
public:
// call this before getting any MMKV instance
static void initializeMMKV(const MMKVPath_t &rootDir, MMKVLogLevel logLevel = MMKVLogInfo, mmkv::MMKVHandler *handler = nullptr);
// a generic purpose instance
static MMKV *defaultMMKV(MMKVMode mode = MMKV_SINGLE_PROCESS, const std::string *cryptKey = nullptr, bool aes256 = false);
static MMKV *defaultMMKV(const MMKVConfig &config);
// mmapID: any unique ID (com.tencent.xin.pay, etc.)
// if you want a per-user mmkv, you could merge user-id within mmapID
static MMKV *mmkvWithID(const std::string &mmapID, const MMKVConfig &config);
// mmapID: any unique ID (com.tencent.xin.pay, etc.)
// if you want a per-user mmkv, you could merge user-id within mmapID
// cryptKey: 16 bytes at most
static MMKV *mmkvWithID(const std::string &mmapID,
MMKVMode mode = MMKV_SINGLE_PROCESS,
const std::string *cryptKey = nullptr,
const MMKVPath_t *rootPath = nullptr,
size_t expectedCapacity = 0,
bool aes256 = false);
#ifdef MMKV_ANDROID
static MMKV *mmkvWithAshmemFD(const std::string &mmapID, int fd, int metaFD, const MMKVConfig &config);
static MMKV *mmkvWithAshmemFD(const std::string &mmapID, int fd, int metaFD, const std::string *cryptKey = nullptr,
bool aes256 = false);
int ashmemFD();
int ashmemMetaFD();
#ifndef MMKV_OHOS
bool checkProcessMode();
static void enableDisableProcessMode(bool enable);
#endif // !MMKV_OHOS
#endif // MMKV_ANDROID
// get a namespace with custom root dir
static mmkv::NameSpace nameSpace(const MMKVPath_t &rootDir);
// identical with the original MMKV with the global root dir
static mmkv::NameSpace defaultNameSpace();
// you can call this on application termination, it's totally fine if you don't call
static void onExit();
const std::string &mmapID() const;
#ifndef MMKV_ANDROID
bool isMultiProcess() const { return (m_mode & MMKV_MULTI_PROCESS) != 0; }
#else
bool isMultiProcess() const {
return (m_mode & MMKV_MULTI_PROCESS) != 0
|| (m_mode & CONTEXT_MODE_MULTI_PROCESS) != 0
|| (m_mode & MMKV_ASHMEM) != 0; // ashmem is always multi-process
}
bool isAshmem() const {
return (m_mode & MMKV_ASHMEM) != 0;
}
#endif
bool isReadOnly() const { return (m_mode & MMKV_READ_ONLY) != 0; }
#ifndef MMKV_DISABLE_CRYPT
std::string cryptKey() const;
// transform plain text into encrypted text, or vice versa with empty cryptKey
// you can change existing crypt key with different cryptKey
bool reKey(const std::string &cryptKey, bool aes256 = false);
// just reset cryptKey (will not encrypt or decrypt anything)
// usually you should call this method after other process reKey() the multi-process mmkv
void checkReSetCryptKey(const std::string *cryptKey, bool aes256 = false);
#endif
bool set(bool value, MMKVKey_t key);
bool set(bool value, MMKVKey_t key, uint32_t expireDuration);
bool set(int32_t value, MMKVKey_t key);
bool set(int32_t value, MMKVKey_t key, uint32_t expireDuration);
bool set(uint32_t value, MMKVKey_t key);
bool set(uint32_t value, MMKVKey_t key, uint32_t expireDuration);
bool set(int64_t value, MMKVKey_t key);
bool set(int64_t value, MMKVKey_t key, uint32_t expireDuration);
bool set(uint64_t value, MMKVKey_t key);
bool set(uint64_t value, MMKVKey_t key, uint32_t expireDuration);
bool set(float value, MMKVKey_t key);
bool set(float value, MMKVKey_t key, uint32_t expireDuration);
bool set(double value, MMKVKey_t key);
bool set(double value, MMKVKey_t key, uint32_t expireDuration);
#ifdef MMKV_HAS_CPP20
// avoid unexpected type conversion (pointer to bool, etc.)
template <typename T>
requires(!MMKV_SUPPORTED_VALUE_TYPE<T>)
bool set(T value, MMKVKey_t key) = delete;
// avoid unexpected type conversion (pointer to bool, etc.)
template <typename T>
requires(!MMKV_SUPPORTED_VALUE_TYPE<T>)
bool set(T value, MMKVKey_t key, uint32_t expireDuration) = delete;
#else
// avoid unexpected type conversion (pointer to bool, etc.)
template <typename T>
bool set(T value, MMKVKey_t key, uint32_t expireDuration) = delete;
#endif
#ifdef MMKV_APPLE
#ifdef __OBJC__
bool set(bool value, std::string_view key);
bool set(bool value, std::string_view key, uint32_t expireDuration);
bool set(int32_t value, std::string_view key);
bool set(int32_t value, std::string_view key, uint32_t expireDuration);
bool set(uint32_t value, std::string_view key);
bool set(uint32_t value, std::string_view key, uint32_t expireDuration);
bool set(int64_t value, std::string_view key);
bool set(int64_t value, std::string_view key, uint32_t expireDuration);
bool set(uint64_t value, std::string_view key);
bool set(uint64_t value, std::string_view key, uint32_t expireDuration);
bool set(float value, std::string_view key);
bool set(float value, std::string_view key, uint32_t expireDuration);
bool set(double value, std::string_view key);
bool set(double value, std::string_view key, uint32_t expireDuration);
bool set(const char *value, std::string_view key);
bool set(const char *value, std::string_view key, uint32_t expireDuration);
bool set(const std::string &value, std::string_view key);
bool set(const std::string &value, std::string_view key, uint32_t expireDuration);
bool set(std::string_view value, std::string_view key);
bool set(std::string_view value, std::string_view key, uint32_t expireDuration);
bool set(const mmkv::MMBuffer &value, std::string_view key);
bool set(const mmkv::MMBuffer &value, std::string_view key, uint32_t expireDuration);
bool set(const std::vector<std::string> &vector, std::string_view key);
bool set(const std::vector<std::string> &vector, std::string_view key, uint32_t expireDuration);
bool containsKey(std::string_view key);
bool removeValueForKey(std::string_view key);
bool getBool(std::string_view key, bool defaultValue = false, MMKV_OUT bool *hasValue = nullptr);
int32_t getInt32(std::string_view key, int32_t defaultValue = 0, MMKV_OUT bool *hasValue = nullptr);
uint32_t getUInt32(std::string_view key, uint32_t defaultValue = 0, MMKV_OUT bool *hasValue = nullptr);
int64_t getInt64(std::string_view key, int64_t defaultValue = 0, MMKV_OUT bool *hasValue = nullptr);
uint64_t getUInt64(std::string_view key, uint64_t defaultValue = 0, MMKV_OUT bool *hasValue = nullptr);
float getFloat(std::string_view key, float defaultValue = 0, MMKV_OUT bool *hasValue = nullptr);
double getDouble(std::string_view key, double defaultValue = 0, MMKV_OUT bool *hasValue = nullptr);
bool getString(std::string_view key, std::string &result, bool inplaceModification = true);
mmkv::MMBuffer getBytes(std::string_view key);
bool getBytes(std::string_view key, mmkv::MMBuffer &result);
#ifdef MMKV_HAS_CPP20
template<MMKV_SUPPORTED_VECTOR_VALUE_TYPE T>
bool getVector(std::string_view key, T &result);
bool getVector(std::string_view key, std::vector<std::string> &result);
#endif
bool set(NSObject<NSCoding> *__unsafe_unretained obj, MMKVKey_t key);
bool set(NSObject<NSCoding> *__unsafe_unretained obj, MMKVKey_t key, uint32_t expireDuration);
NSObject *getObject(MMKVKey_t key, Class cls);
#endif // __OBJC__
#endif // MMKV_APPLE
bool set(const char *value, MMKVKey_t key);
bool set(const char *value, MMKVKey_t key, uint32_t expireDuration);
bool set(const std::string &value, MMKVKey_t key);
bool set(const std::string &value, MMKVKey_t key, uint32_t expireDuration);
bool set(std::string_view value, MMKVKey_t key);
bool set(std::string_view value, MMKVKey_t key, uint32_t expireDuration);
bool set(const mmkv::MMBuffer &value, MMKVKey_t key);
bool set(const mmkv::MMBuffer &value, MMKVKey_t key, uint32_t expireDuration);
bool set(const std::vector<std::string> &vector, MMKVKey_t key);
bool set(const std::vector<std::string> &vector, MMKVKey_t key, uint32_t expireDuration);
#ifdef MMKV_HAS_CPP20
template<MMKV_SUPPORTED_VECTOR_VALUE_TYPE T>
bool set(const T& value, MMKVKey_t key) {
return set<T>(value, key, m_expiredInSeconds);
}
template<MMKV_SUPPORTED_VECTOR_VALUE_TYPE T>
bool set(const T& value, MMKVKey_t key, uint32_t expireDuration);
template<MMKV_SUPPORTED_VECTOR_VALUE_TYPE T>
bool getVector(MMKVKey_t key, T &result);
#endif // MMKV_HAS_CPP20
// inplaceModification is recommended for faster speed
bool getString(MMKVKey_t key, std::string &result, bool inplaceModification = true);
mmkv::MMBuffer getBytes(MMKVKey_t key);
bool getBytes(MMKVKey_t key, mmkv::MMBuffer &result);
bool getVector(MMKVKey_t key, std::vector<std::string> &result);
bool getBool(MMKVKey_t key, bool defaultValue = false, MMKV_OUT bool *hasValue = nullptr);
int32_t getInt32(MMKVKey_t key, int32_t defaultValue = 0, MMKV_OUT bool *hasValue = nullptr);
uint32_t getUInt32(MMKVKey_t key, uint32_t defaultValue = 0, MMKV_OUT bool *hasValue = nullptr);
int64_t getInt64(MMKVKey_t key, int64_t defaultValue = 0, MMKV_OUT bool *hasValue = nullptr);
uint64_t getUInt64(MMKVKey_t key, uint64_t defaultValue = 0, MMKV_OUT bool *hasValue = nullptr);
float getFloat(MMKVKey_t key, float defaultValue = 0, MMKV_OUT bool *hasValue = nullptr);
double getDouble(MMKVKey_t key, double defaultValue = 0, MMKV_OUT bool *hasValue = nullptr);
// return the actual size consumption of the key's value
// pass actualSize = true to get value's length
size_t getValueSize(MMKVKey_t key, bool actualSize);
// return size written into buffer
// return -1 on any error
int32_t writeValueToBuffer(MMKVKey_t key, void *ptr, int32_t size);
bool containsKey(MMKVKey_t key);
// filterExpire: return count of all non-expired keys, keep in mind it comes with cost
size_t count(bool filterExpire = false);
size_t totalSize();
size_t actualSize();
static constexpr uint32_t ExpireNever = 0;
// all keys created (or last modified) longer than expiredInSeconds will be deleted on next full-write-back
// expiredInSeconds = MMKV::ExpireNever (0) means no common expiration duration for all keys, aka each key will have it's own expiration duration
bool enableAutoKeyExpire(uint32_t expiredInSeconds = 0);
bool disableAutoKeyExpire();
// compare value for key before set, to reduce the possibility of file expanding
bool enableCompareBeforeSet();
bool disableCompareBeforeSet();
bool isExpirationEnabled() const { return m_enableKeyExpire; }
bool isEncryptionEnabled() const { return m_crypter != nullptr; }
bool isCompareBeforeSetEnabled() const { return m_enableCompareBeforeSet && !m_enableKeyExpire && !m_crypter; }
#ifdef MMKV_APPLE
#ifdef __OBJC__
// filterExpire: return all non-expired keys, keep in mind it comes with cost
NSArray *allKeysObjC(bool filterExpire = false);
bool removeValuesForKeys(NSArray *arrKeys);
typedef void (^EnumerateBlock)(NSString *key, BOOL *stop);
void enumerateKeys(EnumerateBlock block);
#endif // __OBJC__
// filterExpire: return all non-expired keys, keep in mind it comes with cost
std::vector<std::string> allKeys(bool filterExpire = false);
bool removeValuesForKeys(const std::vector<std::string> &arrKeys);
# ifdef MMKV_IOS
static void setIsInBackground(bool isInBackground);
static bool isInBackground();
# endif
#else // !defined(MMKV_APPLE)
// filterExpire: return all non-expired keys, keep in mind it comes with cost
std::vector<std::string> allKeys(bool filterExpire = false);
bool removeValuesForKeys(const std::vector<std::string> &arrKeys);
#endif // MMKV_APPLE
bool removeValueForKey(MMKVKey_t key);
// keepSpace: remove all keys but keep the file size not changed, running faster
void clearAll(bool keepSpace = false);
// MMKV's size won't reduce after deleting key-values
// call this method after lots of deleting if you care about disk usage
// note that `clearAll` has the similar effect of `trim`
void trim();
// import all key-value items from source
// return count of items imported
size_t importFrom(MMKV *src);
// call this method if the instance is no longer needed in the near future
// any subsequent call to the instance is undefined behavior
void close();
// call this method if you are facing memory-warning
// any subsequent call to the instance will load all key-values from file again
// keepSpace: remove all keys but keep the file size not changed, running faster
void clearMemoryCache(bool keepSpace = false);
// you don't need to call this, really, I mean it
// unless you worry about running out of battery
void sync(SyncFlag flag = MMKV_SYNC);
// get exclusive access
void lock();
void unlock();
bool try_lock();
// get thread lock
#ifndef MMKV_WIN32
void lock_thread();
void unlock_thread();
bool try_lock_thread();
#endif
static const MMKVPath_t &getRootDir();
// backup one MMKV instance from srcDir to dstDir
// if srcDir is null, then backup from the root dir of MMKV
static bool backupOneToDirectory(const std::string &mmapID, const MMKVPath_t &dstDir, const MMKVPath_t *srcDir = nullptr);
// restore one MMKV instance from srcDir to dstDir
// if dstDir is null, then restore to the root dir of MMKV
static bool restoreOneFromDirectory(const std::string &mmapID, const MMKVPath_t &srcDir, const MMKVPath_t *dstDir = nullptr);
// backup all MMKV instance from srcDir to dstDir
// if srcDir is null, then backup from the root dir of MMKV
// return count of MMKV successfully backuped
static size_t backupAllToDirectory(const MMKVPath_t &dstDir, const MMKVPath_t *srcDir = nullptr);
// restore all MMKV instance from srcDir to dstDir
// if dstDir is null, then restore to the root dir of MMKV
// return count of MMKV successfully restored
static size_t restoreAllFromDirectory(const MMKVPath_t &srcDir, const MMKVPath_t *dstDir = nullptr);
// check if content been changed by other process
void checkContentChanged();
// register a unified callback handler for MMKV
static void registerHandler(mmkv::MMKVHandler *handler);
static void unRegisterHandler();
// MMKVLogInfo by default
// pass MMKVLogNone to disable all logging
static void setLogLevel(MMKVLogLevel level);
// detect if the MMKV file is valid or not
// Note: Don't use this to check the existence of the instance, the return value is undefined if the file was never created.
static bool isFileValid(const std::string &mmapID, const MMKVPath_t *relatePath = nullptr);
// remove the storage of the MMKV, including the data file & meta file (.crc)
// Note: the existing instance (if any) will be closed & destroyed
static bool removeStorage(const std::string &mmapID, const MMKVPath_t *relatePath = nullptr);
// check the existence of the MMKV file
static bool checkExist(const std::string &mmapID, const MMKVPath_t *relatePath = nullptr);
// just forbid it for possibly misuse
explicit MMKV(const MMKV &other) = delete;
MMKV &operator=(const MMKV &other) = delete;
friend class mmkv::NameSpace;
};
#if defined(MMKV_HAS_CPP20)
template<MMKV_SUPPORTED_VECTOR_VALUE_TYPE T>
bool MMKV::set(const T& value, MMKVKey_t key, uint32_t expireDuration) {
if (isKeyEmpty(key)) {
return false;
}
mmkv::MMBuffer data;
if constexpr (std::is_same_v<T, std::vector<bool>>) {
data = mmkv::MiniPBCoder::encodeDataWithObject(value);
} else {
data = mmkv::MiniPBCoder::encodeDataWithObject(std::span(value));
}
if (mmkv_unlikely(m_enableKeyExpire) && data.length() > 0) {
auto tmp = mmkv::MMBuffer(data.length() + ConstFixed32Size);
auto ptr = (uint8_t *) tmp.getPtr();
memcpy(ptr, data.getPtr(), data.length());
auto time = (expireDuration != ExpireNever) ? safeExpirationPlusCurrentTime(expireDuration) : ExpireNever;
memcpy(ptr + data.length(), &time, ConstFixed32Size);
data = std::move(tmp);
}
return setDataForKey(std::move(data), key);
}
template<MMKV_SUPPORTED_VECTOR_VALUE_TYPE T>
bool MMKV::getVector(MMKVKey_t key, T &result) {
if (isKeyEmpty(key)) {
return false;
}
shared_lock();
bool ret = false;
auto data = getDataForKey(key);
if (data.length() > 0) {
ret = mmkv::MiniPBCoder::decodeVector(data, result);
}
shared_unlock();
return ret;
}
#ifdef MMKV_APPLE
#ifdef __OBJC__
template<MMKV_SUPPORTED_VECTOR_VALUE_TYPE T>
bool getVector(std::string_view key, T &result) {
HybridString hybridKey(key);
return getVector(hybridKey.str, result);
}
#endif // __OBJC__
#endif // MMKV_APPLE
#endif // MMKV_HAS_CPP20
MMKV_NAMESPACE_END
namespace mmkv {
// a POD-like facade what wraps custom root directory
class MMKV_EXPORT NameSpace {
const MMKVPath_t &m_rootDir;
NameSpace(const MMKVPath_t &rootDir) : m_rootDir(rootDir) {}
public:
// return the absolute root dir of NameSpace
const MMKVPath_t &getRootDir() { return m_rootDir; }
MMKV *mmkvWithID(const std::string &mmapID, const MMKVConfig &config);
// mmapID: any unique ID (com.tencent.xin.pay, etc.)
// if you want a per-user mmkv, you could merge user-id within mmapID
// cryptKey: 16 bytes at most
MMKV *mmkvWithID(const std::string &mmapID,
MMKVMode mode = MMKV_SINGLE_PROCESS,
const std::string *cryptKey = nullptr,
size_t expectedCapacity = 0,
bool aes256 = false);
// backup one MMKV instance to dstDir
bool backupOneToDirectory(const std::string &mmapID, const MMKVPath_t &dstDir);
// restore one MMKV instance from srcDir
bool restoreOneFromDirectory(const std::string &mmapID, const MMKVPath_t &srcDir);
// backup all MMKV instance to dstDir
// return count of MMKV successfully backuped
size_t backupAllToDirectory(const MMKVPath_t &dstDir);
// restore all MMKV instance from srcDir
// return count of MMKV successfully restored
size_t restoreAllFromDirectory(const MMKVPath_t &srcDir);
// detect if the MMKV file is valid or not
// Note: Don't use this to check the existence of the instance, the return value is undefined if the file was never created.
bool isFileValid(const std::string &mmapID);
// remove the storage of the MMKV, including the data file & meta file (.crc)
// Note: the existing instance (if any) will be closed & destroyed
bool removeStorage(const std::string &mmapID);
// check the existence of the MMKV file
bool checkExist(const std::string &mmapID);
friend class MMKV_NAMESPACE_PREFIX::MMKV;
};
}
#endif // __cplusplus
#endif // MMKV_MMKV_H