/* * Tencent is pleased to support the open source community by making * MMKV available. * * Copyright (C) 2020 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. */ #include #include #include #include #ifdef MMKV_WIN32 #include typedef SSIZE_T ssize_t; #endif using namespace mmkv; using namespace std; namespace py = pybind11; static MMKVConfig pyArgsToConfig(MMKVMode mode, const string &cryptKey, const MMKVPath_t &rootDir, size_t expectedCapacity, bool aes256, std::optional enableKeyExpire, uint32_t expiredInSeconds, bool enableCompareBeforeSet, std::optional recover, uint32_t itemSizeLimit) { MMKVConfig config; config.mode = mode; config.aes256 = aes256; config.cryptKey = (cryptKey.length() > 0) ? (string *) &cryptKey : nullptr; config.rootPath = (rootDir.length() > 0) ? (MMKVPath_t *) &rootDir : nullptr; config.expectedCapacity = expectedCapacity; config.enableKeyExpire = enableKeyExpire; config.expiredInSeconds = expiredInSeconds; config.enableCompareBeforeSet = enableCompareBeforeSet; config.recover = recover; config.itemSizeLimit = itemSizeLimit; return config; } static MMBuffer pyBytes2MMBuffer(const py::bytes &bytes) { char *buffer = nullptr; ssize_t length = 0; if (PYBIND11_BYTES_AS_STRING_AND_SIZE(bytes.ptr(), &buffer, &length) == 0) { return {buffer, static_cast(length), MMBufferNoCopy}; } return MMBuffer(0); } static function g_logHandler = nullptr; static function g_errorHandler = nullptr; static function g_contentHandler = nullptr; static function g_contentLoadedHandler = nullptr; // C++ handler that bridges to Python callbacks class PyMMKVHandler : public mmkv::MMKVHandler { public: void mmkvLog(MMKVLogLevel level, const char *file, int line, const char *function, MMKVLog_t message) override { if (g_logHandler) { g_logHandler(level, file, line, function, message); } } MMKVRecoverStrategic onMMKVCRCCheckFail(const std::string &mmapID) override { if (g_errorHandler) { return g_errorHandler(mmapID, MMKVErrorType::MMKVCRCCheckFail); } return OnErrorDiscard; } MMKVRecoverStrategic onMMKVFileLengthError(const std::string &mmapID) override { if (g_errorHandler) { return g_errorHandler(mmapID, MMKVErrorType::MMKVFileLength); } return OnErrorDiscard; } void onContentChangedByOuterProcess(const std::string &mmapID) override { if (g_contentHandler) { g_contentHandler(mmapID); } } void onMMKVContentLoadSuccessfully(const std::string &mmapID) override { if (g_contentLoadedHandler) { g_contentLoadedHandler(mmapID); } } }; static PyMMKVHandler g_pyHandler; PYBIND11_MODULE(mmkv, m) { m.doc() = "An efficient, small key-value storage framework developed by WeChat Team."; py::enum_(m, "MMKVMode", py::arithmetic()) .value("SingleProcess", MMKVMode::MMKV_SINGLE_PROCESS) .value("MultiProcess", MMKVMode::MMKV_MULTI_PROCESS) .value("ReadOnly", MMKVMode::MMKV_READ_ONLY) .export_values(); py::enum_(m, "MMKVLogLevel") .value("NoLog", MMKVLogLevel::MMKVLogNone) .value("Debug", MMKVLogLevel::MMKVLogDebug) .value("Info", MMKVLogLevel::MMKVLogInfo) .value("Warning", MMKVLogLevel::MMKVLogWarning) .value("Error", MMKVLogLevel::MMKVLogError) .export_values(); py::enum_(m, "SyncFlag") .value("Sync", SyncFlag::MMKV_SYNC) .value("ASync", SyncFlag::MMKV_ASYNC) .export_values(); py::enum_(m, "MMKVRecoverStrategic") .value("OnErrorDiscard", MMKVRecoverStrategic::OnErrorDiscard) .value("OnErrorRecover", MMKVRecoverStrategic::OnErrorRecover) .export_values(); py::enum_(m, "MMKVErrorType") .value("CRCCheckFail", MMKVErrorType::MMKVCRCCheckFail) .value("FileLength", MMKVErrorType::MMKVFileLength) .export_values(); py::class_> clsNameSpace(m, "NameSpace"); clsNameSpace.def("mmkvWithID", [](NameSpace &self, const string &mmapID, MMKVMode mode, const string &cryptKey, const size_t expectedCapacity, bool aes256, std::optional enableKeyExpire, uint32_t expiredInSeconds, bool enableCompareBeforeSet,std::optional recover, uint32_t itemSizeLimit) { auto config = pyArgsToConfig(mode, cryptKey, self.getRootDir(), expectedCapacity, aes256, enableKeyExpire, expiredInSeconds, enableCompareBeforeSet, recover, itemSizeLimit); return MMKV::mmkvWithID(mmapID, config); }, "Parameters:\n" " mmapID: all instances of the same mmapID share the same data and file storage\n" " mode: pass MMKVMode.MultiProcess for a multi-process MMKV\n" " cryptKey: pass a non-empty string for an encrypted MMKV, 32 bytes at most\n" " expectedCapacity: the file size you expected when opening or creating file\n" " aes256: use AES 256 key length\n" " enableKeyExpire: enable auto key expiration\n" " expiredInSeconds: expiration in seconds\n" " enableCompareBeforeSet: enable compare before set, if new value is the same, dont update/insert\n" " recover: recover strategy on file corruption\n" " itemSizeLimit: size limit for a key-value pair\n", py::arg("mmapID"), py::arg("mode") = MMKV_SINGLE_PROCESS, py::arg("cryptKey") = string(), py::arg("expectedCapacity") = 0, py::arg("aes256") = false, py::arg("enableKeyExpire") = std::nullopt, py::arg("expiredInSeconds") = 0, py::arg("enableCompareBeforeSet") = false, py::arg("recover") = std::nullopt, py::arg("itemSizeLimit") = 0 ); clsNameSpace.def("rootDir", &NameSpace::getRootDir, "get the root directory of NameSpace"); clsNameSpace.def("backupOneToDirectory", &NameSpace::backupOneToDirectory, "backup one MMKV instance from the root dir of NameSpace to dstDir", py::arg("mmapID"), py::arg("dstDir")); clsNameSpace.def("restoreOneFromDirectory", &NameSpace::restoreOneFromDirectory, "restore one MMKV instance from srcDir to dstDir to the root dir of NameSpace", py::arg("mmapID"), py::arg("srcDir")); clsNameSpace.def("backupAllToDirectory", &NameSpace::backupAllToDirectory, "backup all MMKV instance from the root dir of NameSpace to dstDir", py::arg("dstDir")); clsNameSpace.def("restoreAllFromDirectory", &NameSpace::restoreAllFromDirectory, "restore all MMKV instance from srcDir to the root dir of NameSpace", py::arg("srcDir")); clsNameSpace.def("removeStorage", &NameSpace::removeStorage); clsNameSpace.def("isFileValid", &NameSpace::isFileValid); clsNameSpace.def("checkExist", &NameSpace::checkExist); py::class_> clsMMKV(m, "MMKV"); // TODO: not working // clsMMKV.def(py::init(&MMKV::mmkvWithID), // py::arg("mmapID"), // py::arg("mode") = MMKV_SINGLE_PROCESS, // py::arg("cryptKey") = (string*) nullptr, // py::arg("rootDir") = (string*) nullptr); clsMMKV.def(py::init([](const string &mmapID, MMKVMode mode, const string &cryptKey, const MMKVPath_t &rootDir, const size_t expectedCapacity, bool aes256, std::optional enableKeyExpire, uint32_t expiredInSeconds, bool enableCompareBeforeSet,std::optional recover, uint32_t itemSizeLimit) { auto config = pyArgsToConfig(mode, cryptKey, rootDir, expectedCapacity, aes256, enableKeyExpire, expiredInSeconds, enableCompareBeforeSet, recover, itemSizeLimit); return MMKV::mmkvWithID(mmapID, config); }), "Parameters:\n" " mmapID: all instances of the same mmapID share the same data and file storage\n" " mode: pass MMKVMode.MultiProcess for a multi-process MMKV\n" " cryptKey: pass a non-empty string for an encrypted MMKV, 32 bytes at most\n" " rootDir: custom root directory\n" " expectedCapacity: the file size you expected when opening or creating file\n" " aes256: use AES 256 key length\n" " enableKeyExpire: enable auto key expiration\n" " expiredInSeconds: expiration in seconds\n" " enableCompareBeforeSet: enable compare before set, if new value is the same, dont update/insert\n" " recover: recover strategy on file corruption\n" " itemSizeLimit: size limit for a key-value pair\n", py::arg("mmapID"), py::arg("mode") = MMKV_SINGLE_PROCESS, py::arg("cryptKey") = string(), py::arg("rootDir") = string(), py::arg("expectedCapacity") = 0, py::arg("aes256") = false, py::arg("enableKeyExpire") = std::nullopt, py::arg("expiredInSeconds") = 0, py::arg("enableCompareBeforeSet") = false, py::arg("recover") = std::nullopt, py::arg("itemSizeLimit") = 0); clsMMKV.def("__eq__", [](MMKV &kv, const MMKV &other) { return kv.mmapID() == other.mmapID(); }); clsMMKV.def_static( "initializeMMKV", [](const MMKVPath_t &rootDir, MMKVLogLevel logLevel, decltype(g_logHandler) logHandler) { if (logHandler) { g_logHandler = std::move(logHandler); MMKV::initializeMMKV(rootDir, logLevel, &g_pyHandler); } else { MMKV::initializeMMKV(rootDir, logLevel, nullptr); } }, "must call this before getting any MMKV instance", py::arg("rootDir"), py::arg("logLevel") = MMKVLogNone, py::arg("log_handler") = nullptr); clsMMKV.def_static( "defaultMMKV", [](MMKVMode mode, const string &cryptKey, bool aes256, size_t expectedCapacity, std::optional enableKeyExpire, uint32_t expiredInSeconds, bool enableCompareBeforeSet, std::optional recover, uint32_t itemSizeLimit) { auto config = pyArgsToConfig(mode, cryptKey, string(), expectedCapacity, aes256, enableKeyExpire, expiredInSeconds, enableCompareBeforeSet, recover, itemSizeLimit); return MMKV::defaultMMKV(config); }, "a generic purpose instance\n" "Parameters:\n" " mode: pass MMKVMode.MultiProcess for a multi-process MMKV\n" " cryptKey: pass a non-empty string for an encrypted MMKV, 32 bytes at most\n" " aes256: use AES 256 key length\n" " expectedCapacity: the file size you expected when opening or creating file\n" " enableKeyExpire: enable auto key expiration\n" " expiredInSeconds: expiration in seconds\n" " enableCompareBeforeSet: enable compare before set, if new value is the same, dont update/insert\n" " recover: recover strategy on file corruption\n" " itemSizeLimit: size limit for a key-value pair\n", py::arg("mode") = MMKV_SINGLE_PROCESS, py::arg("cryptKey") = string(), py::arg("aes256") = false, py::arg("expectedCapacity") = 0, py::arg("enableKeyExpire") = std::nullopt, py::arg("expiredInSeconds") = 0, py::arg("enableCompareBeforeSet") = false, py::arg("recover") = std::nullopt, py::arg("itemSizeLimit") = 0); clsMMKV.def_static("nameSpace", &MMKV::nameSpace, "get a namespace with custom root dir"); clsMMKV.def_static("defaultNameSpace", &MMKV::defaultNameSpace, "identical with the original MMKV with the global root dir"); clsMMKV.def("mmapID", &MMKV::mmapID); clsMMKV.def("isInterProcess", &MMKV::isMultiProcess); clsMMKV.def("cryptKey", &MMKV::cryptKey); clsMMKV.def("reKey", &MMKV::reKey, "transform plain text into encrypted text, or vice versa with an empty cryptKey\n" "Parameters:\n" " newCryptKey: 32 bytes at most\n" " aes256: use AES 256 key length", py::arg("newCryptKey"), py::arg("aes256") = false); clsMMKV.def("checkReSetCryptKey", &MMKV::checkReSetCryptKey, "just reset cryptKey (will not encrypt or decrypt anything),\n" "usually you should call this method after other process reKey() a multi-process mmkv", py::arg("newCryptKey"), py::arg("aes256") = false); // TODO: Doesn't work, why? // clsMMKV.def("set", py::overload_cast(&MMKV::set), py::arg("value"), py::arg("key")); clsMMKV.def("set", (bool (MMKV::*)(bool, string_view))(&MMKV::set), "encode a boolean value", py::arg("value"), py::arg("key")); clsMMKV.def("set", (bool (MMKV::*)(bool, string_view, uint32_t))(&MMKV::set), "encode a boolean value with expiration", py::arg("value"), py::arg("key"), py::arg("expireDuration")); clsMMKV.def("set", (bool (MMKV::*)(int32_t, string_view))(&MMKV::set), "encode an int32 value", py::arg("value"), py::arg("key")); clsMMKV.def("set", (bool (MMKV::*)(int32_t, string_view, uint32_t))(&MMKV::set), "encode an int32 value with expiration", py::arg("value"), py::arg("key"), py::arg("expireDuration")); clsMMKV.def("set", (bool (MMKV::*)(uint32_t, string_view))(&MMKV::set), "encode an unsigned int32 value", py::arg("value"), py::arg("key")); clsMMKV.def("set", (bool (MMKV::*)(uint32_t, string_view, uint32_t))(&MMKV::set), "encode an unsigned int32 value with expiration", py::arg("value"), py::arg("key"), py::arg("expireDuration")); clsMMKV.def("set", (bool (MMKV::*)(int64_t, string_view))(&MMKV::set), "encode an int64 value", py::arg("value"), py::arg("key")); clsMMKV.def("set", (bool (MMKV::*)(int64_t, string_view, uint32_t))(&MMKV::set), "encode an int64 value with expiration", py::arg("value"), py::arg("key"), py::arg("expireDuration")); clsMMKV.def("set", (bool (MMKV::*)(uint64_t, string_view))(&MMKV::set), "encode an unsigned int64 value", py::arg("value"), py::arg("key")); clsMMKV.def("set", (bool (MMKV::*)(uint64_t, string_view, uint32_t))(&MMKV::set), "encode an unsigned int64 value with expiration", py::arg("value"), py::arg("key"), py::arg("expireDuration")); //clsMMKV.def("set", (bool (MMKV::*)(float, string_view))(&MMKV::set), py::arg("value"), py::arg("key")); clsMMKV.def("set", (bool (MMKV::*)(double, string_view))(&MMKV::set), "encode a float/double value", py::arg("value"), py::arg("key")); clsMMKV.def("set", (bool (MMKV::*)(double, string_view, uint32_t))(&MMKV::set), "encode a float/double value with expiration", py::arg("value"), py::arg("key"), py::arg("expireDuration")); //clsMMKV.def("set", (bool (MMKV::*)(const char*, string_view))(&MMKV::set), py::arg("value"), py::arg("key")); clsMMKV.def("set", (bool (MMKV::*)(const string &, string_view))(&MMKV::set), "encode an UTF-8 String/bytes value", py::arg("value"), py::arg("key")); clsMMKV.def("set", (bool (MMKV::*)(const string &, string_view, uint32_t))(&MMKV::set), "encode an UTF-8 String/bytes value with expiration", py::arg("value"), py::arg("key"), py::arg("expireDuration")); #if PY_MAJOR_VERSION >= 3 clsMMKV.def( "set", [](MMKV &kv, const py::bytes &value, const string &key) { return kv.set(pyBytes2MMBuffer(value), key); }, "encode a bytes value", py::arg("value"), py::arg("key")); clsMMKV.def( "set", [](MMKV &kv, const py::bytes &value, const string &key, uint32_t expireDuration) { return kv.set(pyBytes2MMBuffer(value), key, expireDuration); }, "encode a bytes value with expiration", py::arg("value"), py::arg("key"), py::arg("expireDuration")); #endif clsMMKV.def("getBool", &MMKV::getBool, "decode a boolean value", py::arg("key"), py::arg("defaultValue") = false, py::arg("hasValue") = nullptr); clsMMKV.def("getInt", &MMKV::getInt32, "decode an int32 value", py::arg("key"), py::arg("defaultValue") = 0, py::arg("hasValue") = nullptr); clsMMKV.def("getUInt", &MMKV::getUInt32, "decode an unsigned int32 value", py::arg("key"), py::arg("defaultValue") = 0, py::arg("hasValue") = nullptr); clsMMKV.def("getLongInt", &MMKV::getInt64, "decode an int64 value", py::arg("key"), py::arg("defaultValue") = 0, py::arg("hasValue") = nullptr); clsMMKV.def("getLongUInt", &MMKV::getUInt64, "decode an unsigned int64 value", py::arg("key"), py::arg("defaultValue") = 0, py::arg("hasValue") = nullptr); //clsMMKV.def("getFloat", &MMKV::getFloat, py::arg("key"), py::arg("defaultValue") = 0); clsMMKV.def("getFloat", &MMKV::getDouble, "decode a float/double value", py::arg("key"), py::arg("defaultValue") = 0, py::arg("hasValue") = nullptr); clsMMKV.def( "getString", [](MMKV &kv, const string &key, const string &defaultValue) { string result; if (kv.getString(key, result)) { return result; } return defaultValue; }, "decode an UTF-8 String/bytes value", py::arg("key"), py::arg("defaultValue") = string()); clsMMKV.def( "getBytes", [](MMKV &kv, const string &key, const py::bytes &defaultValue) { MMBuffer result = kv.getBytes(key); if (result.length() > 0) { return py::bytes((const char *) result.getPtr(), result.length()); } return defaultValue; }, "decode a bytes value", py::arg("key"), py::arg("defaultValue") = py::bytes()); clsMMKV.def("__contains__", &MMKV::containsKey, py::arg("key")); clsMMKV.def("keys", &MMKV::allKeys, py::arg("filterExpire") = false); clsMMKV.def("count", &MMKV::count, py::arg("filterExpire") = false); clsMMKV.def("totalSize", &MMKV::totalSize); clsMMKV.def("actualSize", &MMKV::actualSize); clsMMKV.def("remove", &MMKV::removeValueForKey, py::arg("key")); clsMMKV.def("remove", &MMKV::removeValuesForKeys, py::arg("keys")); clsMMKV.def("clearAll", &MMKV::clearAll, py::arg("keepSpace") = false, "remove all key-values"); clsMMKV.def("trim", &MMKV::trim, "call this method after lots of removing if you care about disk usage"); clsMMKV.def("importFrom", &MMKV::importFrom, "import all key-value items from others"); clsMMKV.def("clearMemoryCache", &MMKV::clearMemoryCache, "call this method if you are facing memory-warning", py::arg("keepSpace") = false); clsMMKV.def("sync", &MMKV::sync, py::arg("flag") = MMKV_SYNC, "this call is not necessary unless you worry about unexpected shutdown of the machine (running out of " "battery, etc.)"); clsMMKV.def("enableAutoKeyExpire", &MMKV::enableAutoKeyExpire, py::arg("expireDurationInSecond"), "turn on auto key expiration, passing 0 means never expire"); clsMMKV.def("disableAutoKeyExpire", &MMKV::disableAutoKeyExpire, "turn off auto key expiration"); clsMMKV.def("enableCompareBeforeSet", &MMKV::enableCompareBeforeSet, "turn on compare before set/update"); clsMMKV.def("disableCompareBeforeSet", &MMKV::disableCompareBeforeSet, "turn off compare before set/update"); clsMMKV.def("lock", &MMKV::lock, "get exclusive access, won't return until the lock is obtained"); clsMMKV.def("unlock", &MMKV::unlock); clsMMKV.def("try_lock", &MMKV::try_lock, "try to get exclusive access"); clsMMKV.def("isMultiProcess", &MMKV::isMultiProcess, "check multi-process mode"); clsMMKV.def("isReadOnly", &MMKV::isReadOnly, "check read-only mode"); clsMMKV.def("close", &MMKV::close, "Permanently close the instance. This is terminal: all Python aliases " "to the same native instance become invalid, and close must not race " "with another operation."); clsMMKV.def_static("rootDir", &MMKV::getRootDir, "get the root directory of MMKV"); // unified callback handler clsMMKV.def("checkContentChanged", &MMKV::checkContentChanged, "check if content been changed by other process"); clsMMKV.def_static( "registerHandler", [](decltype(g_logHandler) logHandler, decltype(g_errorHandler) errorHandler, decltype(g_contentHandler) contentChangeHandler, decltype(g_contentLoadedHandler) contentLoadedHandler) { g_logHandler = logHandler ? std::move(logHandler) : nullptr; g_errorHandler = errorHandler ? std::move(errorHandler) : nullptr; g_contentHandler = contentChangeHandler ? std::move(contentChangeHandler) : nullptr; g_contentLoadedHandler = contentLoadedHandler ? std::move(contentLoadedHandler) : nullptr; MMKV::registerHandler(&g_pyHandler); }, "register a unified callback handler for MMKV,\n" "must call MMKV.unRegisterHandler() or MMKV.onExit() before exit\n" "Parameters:\n" " log_handler: (logLevel: mmkv.MMKVLogLevel, file: str, line: int, function: str, message: str) -> None\n" " error_handler: (mmapID: str, errorType: mmkv.MMKVErrorType) -> mmkv.MMKVRecoverStrategic\n" " content_change_handler: (mmapID: str) -> None\n" " content_loaded_handler: (mmapID: str) -> None", py::arg("log_handler") = nullptr, py::arg("error_handler") = nullptr, py::arg("content_change_handler") = nullptr, py::arg("content_loaded_handler") = nullptr); clsMMKV.def_static( "unRegisterHandler", [] { g_logHandler = nullptr; g_errorHandler = nullptr; g_contentHandler = nullptr; g_contentLoadedHandler = nullptr; MMKV::unRegisterHandler(); }, "If you have registered a handler, you must call this method or MMKV.onExit() before exit. " "Otherwise your app/script won't exit properly."); clsMMKV.def_static( "onExit", [] { MMKV::onExit(); g_logHandler = nullptr; g_errorHandler = nullptr; g_contentHandler = nullptr; g_contentLoadedHandler = nullptr; }, "call this method before exit, especially if you have registered any callback handlers"); clsMMKV.def_static( "backupOneToDirectory", [](const string &mmapID, const MMKVPath_t &dstDir, const MMKVPath_t &srcDir) { MMKVPath_t *srcDirPtr = (!srcDir.empty()) ? (MMKVPath_t *) &srcDir : nullptr; return MMKV::backupOneToDirectory(mmapID, dstDir, srcDirPtr); }, "backup one MMKV instance from srcDir (default to the root dir of MMKV) to dstDir", py::arg("mmapID"), py::arg("dstDir"), py::arg("srcDir") = MMKVPath_t()); clsMMKV.def_static( "restoreOneFromDirectory", [](const string &mmapID, const MMKVPath_t &srcDir, const MMKVPath_t &dstDir) { MMKVPath_t *dstDirPtr = (!dstDir.empty()) ? (MMKVPath_t *) &dstDir : nullptr; return MMKV::restoreOneFromDirectory(mmapID, srcDir, dstDirPtr); }, "restore one MMKV instance from srcDir to dstDir (default to the root dir of MMKV)", py::arg("mmapID"), py::arg("srcDir"), py::arg("dstDir") = MMKVPath_t()); clsMMKV.def_static( "backupAllToDirectory", [](const MMKVPath_t &dstDir, const MMKVPath_t &srcDir) { MMKVPath_t *srcDirPtr = (!srcDir.empty()) ? (MMKVPath_t *) &srcDir : nullptr; return MMKV::backupAllToDirectory(dstDir, srcDirPtr); }, "backup all MMKV instance from srcDir (default to the root dir of MMKV) to dstDir", py::arg("dstDir"), py::arg("srcDir") = MMKVPath_t()); clsMMKV.def_static( "restoreAllFromDirectory", [](const MMKVPath_t &srcDir, const MMKVPath_t &dstDir) { MMKVPath_t *dstDirPtr = (!dstDir.empty()) ? (MMKVPath_t *) &dstDir : nullptr; return MMKV::restoreAllFromDirectory(srcDir, dstDirPtr); }, "restore all MMKV instance from srcDir to dstDir (default to the root dir of MMKV)", py::arg("srcDir"), py::arg("dstDir") = MMKVPath_t()); clsMMKV.def_static( "removeStorage", [](const string &mmapID, const MMKVPath_t &rootDir) { MMKVPath_t *rootDirPtr = (!rootDir.empty()) ? (MMKVPath_t *) &rootDir : nullptr; return MMKV::removeStorage(mmapID, rootDirPtr); }, "remove the storage of the MMKV, including the data file & meta file (.crc)", py::arg("mmapID"), py::arg("rootDir") = MMKVPath_t()); clsMMKV.def_static("isFileValid", [](const string &mmapID, const MMKVPath_t &rootDir) { MMKVPath_t *rootDirPtr = (!rootDir.empty()) ? (MMKVPath_t *) &rootDir : nullptr; return MMKV::isFileValid(mmapID, rootDirPtr); }, "detect if the MMKV file is valid or not", py::arg("mmapID"), py::arg("rootDir") = MMKVPath_t()); clsMMKV.def_static("checkExist", [](const string &mmapID, const MMKVPath_t &rootDir) { MMKVPath_t *rootDirPtr = (!rootDir.empty()) ? (MMKVPath_t *) &rootDir : nullptr; return MMKV::checkExist(mmapID, rootDirPtr); }, "check if the MMKV file is exist or not", py::arg("mmapID"), py::arg("rootDir") = MMKVPath_t()); }