mirror of
https://github.com/Tencent/MMKV.git
synced 2026-10-17 04:30:56 +08:00
792 lines
29 KiB
C++
Executable File
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
|