/* * Tencent is pleased to support the open source community by making ScriptX available. * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. * * 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. */ #pragma once #include "../../src/NativeConverter.hpp" #include "../../src/Reference.h" #include "../../src/utils/GlobalWeakBookkeeping.hpp" #include "LuaHelper.hpp" namespace script { namespace lua_backend { struct LuaBookKeepFetcher { template static ::script::internal::GlobalWeakBookkeeping* get(const T* ref) { if (!ref) return nullptr; auto& val = LuaEngine::refVal(const_cast(ref)); if (!val.engine) return nullptr; return &val.engine->globalWeakBookkeeping_; } template static ::script::internal::GlobalWeakBookkeeping::HandleType& handle(const T* ref) { auto& val = LuaEngine::refVal(const_cast(ref)); return val.handle; } }; using BookKeep = ::script::internal::GlobalWeakBookkeeping::Helper; } // namespace lua_backend template Global::Global() noexcept : val_() {} template Global::Global(const script::Local& localReference) : val_() { auto engine = lua_backend::currentEngine(); val_.engine = engine; val_.index = engine->putGlobalOrWeakTable(localReference, lua_backend::LuaEngine::kLuaGlobalRegistryToken_); lua_backend::BookKeep::keep(this); } template Global::Global(const script::Weak& weak) : val_() { auto engine = weak.val_.engine; if (engine) { auto lua = engine->lua_; val_.engine = engine; lua_backend::luaStackScope(lua, [lua, &weak, this, engine]() { auto local = weak.getValue(); if (local.val_ != 0) { val_.index = engine->putGlobalOrWeakTable(local, lua_backend::LuaEngine::kLuaGlobalRegistryToken_); lua_pop(lua, 1); } }); } lua_backend::BookKeep::keep(this); } template Global::Global(const script::Global& copy) : val_() { auto engine = copy.val_.engine; if (engine) { auto lua = engine->lua_; val_.engine = engine; lua_backend::luaStackScope(lua, [lua, ©, this, engine]() { auto local = copy.getValue(); assert(local.val_ != 0); val_.index = engine->putGlobalOrWeakTable(local, lua_backend::LuaEngine::kLuaGlobalRegistryToken_); lua_pop(lua, 1); }); } lua_backend::BookKeep::afterCopy(true, this, ©); } template Global::Global(script::Global&& move) noexcept : val_(std::move(move.val_)) { lua_backend::BookKeep::afterMove(true, this, &move); } template Global::~Global() { if (!isEmpty()) { EngineScope scope(val_.engine); reset(); } } template Global& Global::operator=(const script::Global& assign) { Global(assign).swap(*this); return *this; } template Global& Global::operator=(script::Global&& move) noexcept { Global(std::move(move)).swap(*this); return *this; } template void Global::swap(Global& rhs) noexcept { std::swap(val_.engine, rhs.val_.engine); std::swap(val_.index, rhs.val_.index); lua_backend::BookKeep::afterSwap(this, &rhs); } template Global& Global::operator=(const script::Local& assign) { *this = Global(assign); return *this; } template Local Global::get() const { auto value = getValue(); if (value.val_ == 0) throw Exception("get on empty Global"); return Local{value.val_}; } template Local Global::getValue() const { if (!val_.engine) return {}; return val_.engine->getGlobalOrWeakTable(val_.index, lua_backend::LuaEngine::kLuaGlobalRegistryToken_); } template bool Global::isEmpty() const { return val_.index == 0; } template void Global::reset() { if (!isEmpty()) { val_.engine->removeGlobalOrWeakTable(val_.index, lua_backend::LuaEngine::kLuaGlobalRegistryToken_); lua_backend::BookKeep::remove(this); val_.index = 0; val_.engine = nullptr; } } // == Weak == template Weak::Weak() noexcept : val_() {} template Weak::~Weak() { if (!isEmpty()) { EngineScope scope(val_.engine); reset(); } } template Weak::Weak(const script::Local& localReference) { auto engine = lua_backend::currentEngine(); val_.engine = engine; val_.index = engine->putGlobalOrWeakTable(localReference, lua_backend::LuaEngine::kLuaWeakRegistryToken_); lua_backend::BookKeep::keep(this); } template Weak::Weak(const script::Global& globalReference) { auto engine = globalReference.val_.engine; if (engine) { auto lua = engine->lua_; val_.engine = engine; lua_backend::luaStackScope(lua, [lua, &globalReference, this, engine]() { auto local = globalReference.getValue(); assert(local.val_ != 0); val_.index = engine->putGlobalOrWeakTable(local, lua_backend::LuaEngine::kLuaWeakRegistryToken_); lua_pop(lua, 1); }); } lua_backend::BookKeep ::keep(this); } template Weak::Weak(const script::Weak& copy) : val_() { auto engine = copy.val_.engine; if (engine) { auto lua = engine->lua_; val_.engine = engine; lua_backend::luaStackScope(lua, [lua, ©, this, engine]() { auto local = copy.getValue(); if (local.val_ != 0) { val_.index = engine->putGlobalOrWeakTable(local, lua_backend::LuaEngine::kLuaWeakRegistryToken_); lua_pop(lua, 1); } }); } lua_backend::BookKeep ::keep(this); } template Weak::Weak(script::Weak&& move) noexcept : val_(std::move(move.val_)) { lua_backend::BookKeep ::afterMove(true, this, &move); } template Weak& Weak::operator=(const script::Weak& assign) { Weak(assign).swap(*this); return *this; } template Weak& Weak::operator=(script::Weak&& move) noexcept { Weak(std::move(move)).swap(*this); return *this; } template void Weak::swap(Weak& rhs) noexcept { std::swap(val_.engine, rhs.val_.engine); std::swap(val_.index, rhs.val_.index); lua_backend::BookKeep ::afterSwap(this, &rhs); } template Weak& Weak::operator=(const script::Local& assign) { Weak(assign).swap(*this); return *this; } template Local Weak::get() const { auto value = getValue(); if (value.isNull()) throw Exception("get on empty Weak"); return converter::Converter>::toCpp(value); } template Local Weak::getValue() const { if (isEmpty()) return {}; return val_.engine->getGlobalOrWeakTable(val_.index, lua_backend::LuaEngine::kLuaWeakRegistryToken_); } template bool Weak::isEmpty() const { return val_.index == 0; } template void Weak::reset() noexcept { if (!isEmpty()) { lua_backend::currentEngine()->removeGlobalOrWeakTable( val_.index, lua_backend::LuaEngine::kLuaWeakRegistryToken_); lua_backend::BookKeep ::remove(this); val_.index = 0; val_.engine = nullptr; } } } // namespace script