diff --git a/adapter/ohos/entrance/ace_container.cpp b/adapter/ohos/entrance/ace_container.cpp index 9affcb38b12174602965c9324cd3aa07488a3895..911a687bd6e6d65f5bc7efc4b8f47f2d646ea70a 100644 --- a/adapter/ohos/entrance/ace_container.cpp +++ b/adapter/ohos/entrance/ace_container.cpp @@ -415,7 +415,9 @@ void AceContainer::Initialize() { ContainerScope scope(instanceId_); // For DECLARATIVE_JS frontend use UI as JS Thread, so InitializeFrontend after UI thread created. - if (type_ != FrontendType::DECLARATIVE_JS && type_ != FrontendType::DECLARATIVE_CJ) { + // For StaticHybridDynamic and DynamicHybridStatic frontend, also initialize after AttachView + if (type_ != FrontendType::DECLARATIVE_JS && type_ != FrontendType::DECLARATIVE_CJ && + type_ != FrontendType::StaticHybridDynamic && type_ != FrontendType::DynamicHybridStatic) { InitializeFrontend(); } } @@ -490,6 +492,116 @@ void AceContainer::DestroyView() aceView_ = nullptr; } +void AceContainer::InitializeStaticHybridDynamic(std::shared_ptr aceAbility) +{ + // 1.2 initialization + frontend_ = MakeRefPtr(sharedRuntime_); + // 1.1 initialization + subFrontend_ = AceType::MakeRefPtr(); + auto declarativeFrontend = AceType::DynamicCast(subFrontend_); + auto& loader = Framework::JsEngineLoader::GetDeclarative(GetDeclarativeSharedLibrary()); + RefPtr jsEngine; + if (GetSettings().usingSharedRuntime) { + jsEngine = loader.CreateJsEngineUsingSharedRuntime( + instanceId_, nullptr); // replace 1.1 preload runtime when initialize + } else { + jsEngine = loader.CreateJsEngine(instanceId_); + } + + jsEngine->AddExtraNativeObject("ability", aceAbility.get()); + auto pageUrlCheckFunc = [id = instanceId_]( + const std::string& url, const std::function& callback, + const std::function& silentInstallErrorCallBack) { + ContainerScope scope(id); + auto container = Container::Current(); + CHECK_NULL_VOID(container); + auto pageUrlChecker = container->GetPageUrlChecker(); + CHECK_NULL_VOID(pageUrlChecker); + pageUrlChecker->LoadPageUrl(url, callback, silentInstallErrorCallBack); + }; + jsEngine->SetPageUrlCheckFunc(std::move(pageUrlCheckFunc)); + + EngineHelper::AddEngine(instanceId_, jsEngine); + declarativeFrontend->SetJsEngine(jsEngine); + declarativeFrontend->SetPageProfile(pageProfile_); + declarativeFrontend->SetNeedDebugBreakPoint(AceApplicationInfo::GetInstance().IsNeedDebugBreakPoint()); + declarativeFrontend->SetDebugVersion(AceApplicationInfo::GetInstance().IsDebugVersion()); +} + +void AceContainer::InitializeDynamicHybridStatic(std::shared_ptr aceAbility) +{ + // 1.2 initialization + if (!ArktsFrontend::preloadArkTSRuntime) { + LOGE("AceContainer::InitializeDynamicHybridStatic: ArktsFrontend::preloadArkTSRuntime is null, preload Fail"); + } + subFrontend_ = MakeRefPtr(ArktsFrontend::preloadArkTSRuntime); + // 1.1 initialization + if (isFormRender_) { +#ifdef FORM_SUPPORTED + LOGI("Init Form Frontend"); + frontend_ = AceType::MakeRefPtr(); + auto cardFrontend = AceType::DynamicCast(frontend_); + auto& loader = Framework::JsEngineLoader::GetDeclarative(GetDeclarativeSharedLibrary()); + RefPtr jsEngine; + if (GetSettings().usingSharedRuntime) { + jsEngine = loader.CreateJsEngineUsingSharedRuntime(instanceId_, sharedRuntime_); + } else { + jsEngine = loader.CreateJsEngine(instanceId_); + } + jsEngine->AddExtraNativeObject("ability", aceAbility.get()); + + EngineHelper::AddEngine(instanceId_, jsEngine); + cardFrontend->SetJsEngine(jsEngine); + cardFrontend->SetPageProfile(pageProfile_); + cardFrontend->SetNeedDebugBreakPoint(AceApplicationInfo::GetInstance().IsNeedDebugBreakPoint()); + cardFrontend->SetDebugVersion(AceApplicationInfo::GetInstance().IsDebugVersion()); + // Card front + cardFrontend->SetRunningCardId(0); // ArkTsCard : nodeId, Host->FMS->FRS->innersdk + cardFrontend->SetIsFormRender(true); +#endif + } else if (!isSubContainer_) { +#ifdef NG_BUILD + frontend_ = AceType::MakeRefPtr(); + auto declarativeFrontend = AceType::DynamicCast(frontend_); +#else + frontend_ = AceType::MakeRefPtr(); + auto declarativeFrontend = AceType::DynamicCast(frontend_); +#endif + + if (!IsDialogContainer()) { + auto& loader = Framework::JsEngineLoader::GetDeclarative(GetDeclarativeSharedLibrary()); + RefPtr jsEngine; + if (GetSettings().usingSharedRuntime) { + jsEngine = loader.CreateJsEngineUsingSharedRuntime(instanceId_, sharedRuntime_); + } else { + jsEngine = loader.CreateJsEngine(instanceId_); + } + + jsEngine->AddExtraNativeObject("ability", aceAbility.get()); + auto pageUrlCheckFunc = [id = instanceId_]( + const std::string& url, const std::function& callback, + const std::function& silentInstallErrorCallBack) { + ContainerScope scope(id); + auto container = Container::Current(); + CHECK_NULL_VOID(container); + auto pageUrlChecker = container->GetPageUrlChecker(); + CHECK_NULL_VOID(pageUrlChecker); + pageUrlChecker->LoadPageUrl(url, callback, silentInstallErrorCallBack); + }; + jsEngine->SetPageUrlCheckFunc(std::move(pageUrlCheckFunc)); + EngineHelper::AddEngine(instanceId_, jsEngine); + + declarativeFrontend->SetJsEngine(jsEngine); + declarativeFrontend->SetPageProfile(pageProfile_); + declarativeFrontend->SetNeedDebugBreakPoint(AceApplicationInfo::GetInstance().IsNeedDebugBreakPoint()); + declarativeFrontend->SetDebugVersion(AceApplicationInfo::GetInstance().IsDebugVersion()); + } + } else { + frontend_ = OHOS::Ace::Platform::AceContainer::GetContainer(parentId_)->GetFrontend(); + return; + } +} + void AceContainer::InitializeFrontend() { auto aceAbility = aceAbility_.lock(); @@ -583,9 +695,17 @@ void AceContainer::InitializeFrontend() return; } } else if (type_ == FrontendType::ARK_TS) { + LOGI("Init ARK_TS Frontend"); frontend_ = MakeRefPtr(sharedRuntime_); + } else if (type_ == FrontendType::StaticHybridDynamic) { + // initialize after AttachView + LOGI("Init StaticHybridDynamic Frontend"); + InitializeStaticHybridDynamic(aceAbility); + } else if (type_ == FrontendType::DynamicHybridStatic) { + LOGI("Init DynamicHybridStatic Frontend"); + InitializeDynamicHybridStatic(aceAbility); } else { - LOGE("Frontend type not supported"); + LOGE("Frontend type not supported, error type: %{public}i", type_); EventReport::SendAppStartException(AppStartExcepType::FRONTEND_TYPE_ERR); return; } @@ -596,6 +716,9 @@ void AceContainer::InitializeFrontend() frontend_->DisallowPopLastPage(); } frontend_->Initialize(type_, taskExecutor_); + if (subFrontend_) { + subFrontend_->Initialize(type_, taskExecutor_); + } } RefPtr AceContainer::GetContainer(int32_t instanceId) diff --git a/adapter/ohos/entrance/ace_container.h b/adapter/ohos/entrance/ace_container.h index 30cce7e2e298df30b5dfcb00f637a46536f898b9..4756f04d478b10638caffe5e7c7f75b482be7363 100644 --- a/adapter/ohos/entrance/ace_container.h +++ b/adapter/ohos/entrance/ace_container.h @@ -844,6 +844,25 @@ public: foldStatusFromListener_ = GetCurrentFoldStatus(); } + RefPtr GetSubFrontend() const override + { + CHECK_NE_RETURN(type_ == FrontendType::StaticHybridDynamic || + type_ == FrontendType::DynamicHybridStatic, true, nullptr); + std::lock_guard lock(subFrontendMutex_); + return subFrontend_; + } + + FrontendType GetSubFrontendType() const + { + CHECK_NE_RETURN(type_ == FrontendType::StaticHybridDynamic || + type_ == FrontendType::DynamicHybridStatic, true, type_); + if (type_ == FrontendType::StaticHybridDynamic) { + return FrontendType::DECLARATIVE_JS; + } else { + return FrontendType::ARK_TS; + } + } + private: virtual bool MaybeRelease() override; void InitializeFrontend(); @@ -891,6 +910,8 @@ private: return uiWindow_->GetWindowMode() == Rosen::WindowMode::WINDOW_MODE_FULLSCREEN; } bool SetSystemBarEnabled(SystemBarType type, bool enable, bool animation) override; + void InitializeStaticHybridDynamic(std::shared_ptr aceAbility); + void InitializeDynamicHybridStatic(std::shared_ptr aceAbility); int32_t instanceId_ = 0; RefPtr aceView_; @@ -972,6 +993,11 @@ private: std::vector paramUie_; SingleHandTransform singleHandTransform_; + + // for multiple frontEnd + // valid only when type_ is StaticHybridDynamic or DynamicHybridStatic + RefPtr subFrontend_ = nullptr; + mutable std::mutex subFrontendMutex_; }; } // namespace OHOS::Ace::Platform diff --git a/adapter/ohos/entrance/ui_content_impl.cpp b/adapter/ohos/entrance/ui_content_impl.cpp index 426e6922c2cedfafdfd3ace4da67200dbdeaf26a..6e3589dcdb021250abb349f46e0ec7e1eeaf6388 100644 --- a/adapter/ohos/entrance/ui_content_impl.cpp +++ b/adapter/ohos/entrance/ui_content_impl.cpp @@ -2043,6 +2043,14 @@ UIContentErrorCode UIContentImpl::CommonInitialize( if (vmType_ == VMType::ARK_NATIVE) { frontendType = FrontendType::ARK_TS; } + + if (appInfo->codeLanguage == AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_HYBRID) { + if (vmType_ == VMType::ARK_NATIVE) { + frontendType = FrontendType::StaticHybridDynamic; + } else { + frontendType = FrontendType::DynamicHybridStatic; + } + } auto container = AceType::MakeRefPtr(instanceId_, frontendType, context_, info, std::make_unique( diff --git a/frameworks/bridge/arkts_frontend/arkts_frontend.cpp b/frameworks/bridge/arkts_frontend/arkts_frontend.cpp index 6a1aa6ae869dfbc6e479beef05eb49d0a305565c..0dabec4bd4a0adba4b2a62917042e63b025ecafd 100644 --- a/frameworks/bridge/arkts_frontend/arkts_frontend.cpp +++ b/frameworks/bridge/arkts_frontend/arkts_frontend.cpp @@ -421,4 +421,15 @@ void ArktsFrontend::SetAniContext(int32_t instanceId, ani_ref* context) std::shared_ptr shared_ptr(context); Framework::AniContextModule::AddAniContext(instanceId, shared_ptr); } + +void* ArktsFrontend::preloadArkTSRuntime = nullptr; +void ArktsFrontend::PreloadAceModule(void* aniEnv) +{ + ArktsFrontend::preloadArkTSRuntime = aniEnv; +} + +extern "C" ACE_FORCE_EXPORT void OHOS_ACE_PreloadAceArkTSModule(void* aniEnv) +{ + ArktsFrontend::PreloadAceModule(aniEnv); +} } // namespace OHOS::Ace diff --git a/frameworks/bridge/arkts_frontend/arkts_frontend.h b/frameworks/bridge/arkts_frontend/arkts_frontend.h index c6af531be023c0583e1c0068091002a67bd9037b..92c74b033fe72920cb320cb6e6647cf97bc159ab 100644 --- a/frameworks/bridge/arkts_frontend/arkts_frontend.h +++ b/frameworks/bridge/arkts_frontend/arkts_frontend.h @@ -359,6 +359,8 @@ public: return pageRouterManager_; } + static void PreloadAceModule(void* aniEnv); + static void* preloadArkTSRuntime; private: RefPtr taskExecutor_; RefPtr pipeline_; diff --git a/frameworks/bridge/common/utils/engine_helper.cpp b/frameworks/bridge/common/utils/engine_helper.cpp index f953ff28d69cf87ff21159bea04cbc49b2af4f02..9562d267a9f867b8d6900960de5226a8ae4bfc5a 100644 --- a/frameworks/bridge/common/utils/engine_helper.cpp +++ b/frameworks/bridge/common/utils/engine_helper.cpp @@ -86,7 +86,7 @@ ScopedDelegate EngineHelper::GetCurrentDelegate() ScopedDelegate EngineHelper::GetCurrentDelegateSafely() { auto engine = GetCurrentEngineSafely(); - if (engine) { + if (engine) { // AddEngine will be called in AceContainer::InitializeFrontend return { engine->GetFrontend(), Container::CurrentIdSafely() }; } auto container = Container::CurrentSafely(); diff --git a/frameworks/bridge/declarative_frontend/declarative_frontend.cpp b/frameworks/bridge/declarative_frontend/declarative_frontend.cpp index fa343e2371ee419ab174927c7fa7653c53424661..fb0e3de1f4d42cf04978293b1d75b026a7daeb52 100644 --- a/frameworks/bridge/declarative_frontend/declarative_frontend.cpp +++ b/frameworks/bridge/declarative_frontend/declarative_frontend.cpp @@ -17,6 +17,7 @@ #include "base/log/dump_log.h" #include "base/log/event_report.h" +#include "bridge/js_frontend/engine/common/js_engine.h" #include "core/common/recorder/node_data_cache.h" #include "frameworks/bridge/card_frontend/form_frontend_delegate_declarative.h" #include "frameworks/bridge/declarative_frontend/ng/page_router_manager_factory.h" @@ -182,7 +183,7 @@ bool DeclarativeFrontend::Initialize(FrontendType type, const RefPtrUpdateHybridType(Framework::JsEngineHybridType::StaticHybridDynamic); + } else if (type_ == FrontendType::DynamicHybridStatic) { + needPostJsTask = false; + jsEngine_->UpdateHybridType(Framework::JsEngineHybridType::DynamicHybridStatic); + } else { + jsEngine_->UpdateHybridType(Framework::JsEngineHybridType::NONE); + } + #if defined(PREVIEW) auto initJSEngineTask = [weakEngine = WeakPtr(jsEngine_), delegate = delegate_, pkgNameMap = pkgNameMap_, pkgAliasMap = pkgAliasMap_, pkgContextInfoMap = pkgContextInfoMap_] { diff --git a/frameworks/bridge/declarative_frontend/engine/jsi/jsi_declarative_engine.cpp b/frameworks/bridge/declarative_frontend/engine/jsi/jsi_declarative_engine.cpp index fd0a9847aa0572660512f35ac9d24cd502f3e041..5af8f206087aef5417dc5375670c613b5d6d640a 100644 --- a/frameworks/bridge/declarative_frontend/engine/jsi/jsi_declarative_engine.cpp +++ b/frameworks/bridge/declarative_frontend/engine/jsi/jsi_declarative_engine.cpp @@ -26,6 +26,7 @@ #include "base/thread/task_executor.h" #include "base/utils/utils.h" +#include "bridge/js_frontend/engine/common/js_engine.h" #ifdef WINDOWS_PLATFORM #include #endif @@ -390,6 +391,7 @@ std::shared_mutex JsiDeclarativeEngineInstance::globalRuntimeMutex_; // for async task callback executed after this instance has been destroyed. thread_local void* cardRuntime_; thread_local shared_ptr localRuntime_; +thread_local void* g_declarativeRuntime = nullptr; // ArkTsCard start thread_local bool isUnique_ = false; @@ -714,6 +716,7 @@ void JsiDeclarativeEngineInstance::PreloadAceModule(void* runtime) } localRuntime_ = arkRuntime; cardRuntime_ = runtime; + g_declarativeRuntime = runtime; } void JsiDeclarativeEngineInstance::InitConsoleModule() @@ -1206,6 +1209,12 @@ bool JsiDeclarativeEngine::Initialize(const RefPtr& delegate) ACE_DCHECK(delegate); NG::UIContextHelper::RegisterRemoveUIContextFunc(); engineInstance_ = AceType::MakeRefPtr(delegate); + if (hybridType == JsEngineHybridType::DynamicHybridStatic) { + runtime_ = g_declarativeRuntime; + } + if (!g_declarativeRuntime) { + LOGE("JsiDeclarativeEngine::Initialize, g_declarativeRuntime is null"); + } auto sharedRuntime = reinterpret_cast(runtime_); std::shared_ptr arkRuntime; EcmaVM* vm = nullptr; diff --git a/frameworks/bridge/js_frontend/engine/common/js_engine.h b/frameworks/bridge/js_frontend/engine/common/js_engine.h index 19463acc133474bce0c73dad49ed7284beac495b..3d4fe51aaf48c452f7cba599fe176f5d2c8d55cd 100644 --- a/frameworks/bridge/js_frontend/engine/common/js_engine.h +++ b/frameworks/bridge/js_frontend/engine/common/js_engine.h @@ -45,6 +45,11 @@ struct JsComponent { const std::string methods; }; +// used for hybrid application +enum class JsEngineHybridType { + NONE, DynamicHybridStatic, StaticHybridDynamic +}; + class JsEngineInstance { public: JsEngineInstance() = default; @@ -492,6 +497,11 @@ public: return nullptr; } + void UpdateHybridType(JsEngineHybridType type) + { + hybridType = type; + } + protected: NativeEngine* nativeEngine_ = nullptr; std::function mediaUpdateCallback_; @@ -499,6 +509,7 @@ protected: std::map>> drawEvents_; bool needUpdate_ = false; PageUrlCheckFunc pageUrlCheckFunc_; + JsEngineHybridType hybridType = JsEngineHybridType::NONE; private: // weather the app has debugger.so. diff --git a/frameworks/core/common/container.h b/frameworks/core/common/container.h index 43ebac69418efc4e66f5a8a76ca7720d7202f101..0408648a80e0eb42d1517283876ecd2da1435b1a 100755 --- a/frameworks/core/common/container.h +++ b/frameworks/core/common/container.h @@ -785,6 +785,9 @@ public: static bool CheckRunOnThreadByThreadId(int32_t currentId, bool defaultRes); + // Get the subFrontend of container + virtual RefPtr GetSubFrontend() const { return nullptr; } + protected: bool IsFontFileExistInPath(const std::string& path); std::vector GetFontFamilyName(const std::string& path); diff --git a/frameworks/core/common/frontend.h b/frameworks/core/common/frontend.h index 701fd48766607b06d1f8e5cc4bb8f1c4724bd20d..83ac0a7f308204503c4ae2381dd49d57c4426757 100644 --- a/frameworks/core/common/frontend.h +++ b/frameworks/core/common/frontend.h @@ -78,7 +78,11 @@ struct WindowConfig { } }; -enum class FrontendType { JSON, JS, JS_CARD, DECLARATIVE_JS, JS_PLUGIN, ETS_CARD, DECLARATIVE_CJ, ARK_TS }; +enum class FrontendType { + JSON, JS, JS_CARD, DECLARATIVE_JS, JS_PLUGIN, ETS_CARD, DECLARATIVE_CJ, ARK_TS, + DynamicHybridStatic, StaticHybridDynamic +}; + struct PageTarget; class ACE_FORCE_EXPORT Frontend : public AceType { diff --git a/interfaces/inner_api/ace/BUILD.gn b/interfaces/inner_api/ace/BUILD.gn index d9bdf6c5548fb912081648df6fe5dcc22745bee3..5ef4e30caeb88fb5bed98614b19ed5bfebe7e096 100644 --- a/interfaces/inner_api/ace/BUILD.gn +++ b/interfaces/inner_api/ace/BUILD.gn @@ -78,6 +78,7 @@ ohos_shared_library("ace_uicontent") { ] sources = [ + "${ace_root}/interfaces/inner_api/ace/arkts_module_preloader.cpp", "${ace_root}/interfaces/inner_api/ace/declarative_module_preloader.cpp", "${ace_root}/interfaces/inner_api/ace/hot_reloader.cpp", "${ace_root}/interfaces/inner_api/ace/navigation_controller.cpp", diff --git a/interfaces/inner_api/ace/arkts_module_preloader.cpp b/interfaces/inner_api/ace/arkts_module_preloader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..661873ff84bf3f2ec77b5d93971ea36e9def3a69 --- /dev/null +++ b/interfaces/inner_api/ace/arkts_module_preloader.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 "interfaces/inner_api/ace/arkts_module_preloader.h" + +#include "ace_forward_compatibility.h" +#include "arkui_log.h" +#include "utils.h" + +namespace OHOS::Ace { + +using CreateFunc = void (*)(void*); +constexpr char PRE_INIT_ACE_ARKTS_MODULE_FUNC[] = "OHOS_ACE_PreloadAceArkTSModule"; + +void InitAceArkTSModule(void* runtime) +{ + LIBHANDLE handle = LOADLIB(AceForwardCompatibility::GetAceLibName()); + if (handle == nullptr) { + return; + } + + auto entry = reinterpret_cast(LOADSYM(handle, PRE_INIT_ACE_ARKTS_MODULE_FUNC)); + if (entry == nullptr) { + FREELIB(handle); + return; + } + + entry(runtime); +} + +void ArkTSModulePreloader::Preload(void* aniEnv) +{ + LOGI("ArkTSModulePreloader::PreloadSTS, aniEnv: %{public}i", aniEnv ? 1 : 0); + InitAceArkTSModule(reinterpret_cast(aniEnv)); +} + +} // namespace OHOS::Ace diff --git a/interfaces/inner_api/ace/arkts_module_preloader.h b/interfaces/inner_api/ace/arkts_module_preloader.h new file mode 100644 index 0000000000000000000000000000000000000000..97ca9320d5be4595b629d975968d1fd9b6edd36b --- /dev/null +++ b/interfaces/inner_api/ace/arkts_module_preloader.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 FOUNDATION_ACE_INTERFACE_INNERKITS_ACE_ARKTS_MODULE_PRELOADER_H +#define FOUNDATION_ACE_INTERFACE_INNERKITS_ACE_ARKTS_MODULE_PRELOADER_H + +#include +#include +#include + +#include "macros.h" + +namespace OHOS::Ace { + +class ACE_FORCE_EXPORT ArkTSModulePreloader { +public: + + static void Preload(void* aniEnv); + +}; + +} // namespace OHOS::Ace + +#endif // FOUNDATION_ACE_INTERFACE_INNERKITS_ACE_ARKTS_MODULE_PRELOADER_H diff --git a/interfaces/inner_api/ace_kit/include/ui/base/utils/utils.h b/interfaces/inner_api/ace_kit/include/ui/base/utils/utils.h index ffa4e2396692190bc2909f69aca0c8f60d785b91..a9c582928f6ccec15d7a2cd8d5d00b0403e3cef5 100644 --- a/interfaces/inner_api/ace_kit/include/ui/base/utils/utils.h +++ b/interfaces/inner_api/ace_kit/include/ui/base/utils/utils.h @@ -61,6 +61,20 @@ continue; \ } +#define CHECK_NE_VOID(var, value) \ + do { \ + if ((var) != (value)) { \ + return; \ + } \ + } while (0) + +#define CHECK_NE_RETURN(var, value, ret) \ + do { \ + if ((var) != (value)) { \ + return ret; \ + } \ + } while (0) + #define CHECK_INITIALIZED_FIELDS_BEGIN() \ constexpr auto _lineBegin = __LINE__;