From 01edc4fb218d670e1c561ef1f354cd5b794abef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Thu, 8 Jun 2017 15:53:17 +0200 Subject: [PATCH] Add coroutine support (WIP) --- include/Nazara/Lua/LuaCoroutine.hpp | 44 +++++++++++++++++++++++ include/Nazara/Lua/LuaCoroutine.inl | 25 +++++++++++++ include/Nazara/Lua/LuaInstance.hpp | 1 + include/Nazara/Lua/LuaState.hpp | 12 +++---- include/Nazara/Lua/LuaState.inl | 8 +++-- src/Nazara/Lua/LuaCoroutine.cpp | 55 +++++++++++++++++++++++++++++ src/Nazara/Lua/LuaInstance.cpp | 2 +- src/Nazara/Lua/LuaState.cpp | 23 ++++++++---- 8 files changed, 154 insertions(+), 16 deletions(-) create mode 100644 include/Nazara/Lua/LuaCoroutine.hpp create mode 100644 include/Nazara/Lua/LuaCoroutine.inl create mode 100644 src/Nazara/Lua/LuaCoroutine.cpp diff --git a/include/Nazara/Lua/LuaCoroutine.hpp b/include/Nazara/Lua/LuaCoroutine.hpp new file mode 100644 index 000000000..b145cfe22 --- /dev/null +++ b/include/Nazara/Lua/LuaCoroutine.hpp @@ -0,0 +1,44 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Lua scripting module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_LUACOROUTINE_HPP +#define NAZARA_LUACOROUTINE_HPP + +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_LUA_API LuaCoroutine : public LuaState + { + friend class LuaState; + + public: + LuaCoroutine(const LuaCoroutine&) = delete; + inline LuaCoroutine(LuaCoroutine&& instance); + ~LuaCoroutine(); + + bool CanResume() const; + + Ternary Resume(unsigned int argCount = 0); + + LuaCoroutine& operator=(const LuaCoroutine&) = delete; + inline LuaCoroutine& operator=(LuaCoroutine&& instance); + + private: + LuaCoroutine(lua_State* internalState, int refIndex); + + bool Run(int argCount, int resultCount) override; + + int m_ref; + }; +} + +#include + +#endif // NAZARA_LUACOROUTINE_HPP diff --git a/include/Nazara/Lua/LuaCoroutine.inl b/include/Nazara/Lua/LuaCoroutine.inl new file mode 100644 index 000000000..7dcdd0e07 --- /dev/null +++ b/include/Nazara/Lua/LuaCoroutine.inl @@ -0,0 +1,25 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Lua scripting module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include + +namespace Nz +{ + inline LuaCoroutine::LuaCoroutine(LuaCoroutine&& instance) : + LuaState(std::move(instance)), + m_ref(instance.m_ref) + { + instance.m_ref = -1; + } + + inline LuaCoroutine& LuaCoroutine::operator=(LuaCoroutine&& instance) + { + LuaState::operator=(std::move(instance)); + + m_ref = instance.m_ref; + instance.m_ref = -1; + + return *this; + } +} diff --git a/include/Nazara/Lua/LuaInstance.hpp b/include/Nazara/Lua/LuaInstance.hpp index 45d19ddba..a5d631645 100644 --- a/include/Nazara/Lua/LuaInstance.hpp +++ b/include/Nazara/Lua/LuaInstance.hpp @@ -16,6 +16,7 @@ namespace Nz { class NAZARA_LUA_API LuaInstance : public LuaState { + friend class LuaCoroutine; friend class LuaState; public: diff --git a/include/Nazara/Lua/LuaState.hpp b/include/Nazara/Lua/LuaState.hpp index a34ec27fd..f3bfdc34a 100644 --- a/include/Nazara/Lua/LuaState.hpp +++ b/include/Nazara/Lua/LuaState.hpp @@ -21,6 +21,7 @@ struct lua_State; namespace Nz { + class LuaCoroutine; class LuaInstance; class LuaState; @@ -115,6 +116,7 @@ namespace Nz void MoveTo(LuaState* instance, int n) const; + LuaCoroutine NewCoroutine(); bool NewMetatable(const char* str); bool NewMetatable(const String& str); bool Next(int index = -2) const; @@ -158,10 +160,8 @@ namespace Nz void SetMetatable(const char* tname) const; void SetMetatable(const String& tname) const; void SetMetatable(int index) const; - void SetMemoryLimit(std::size_t memoryLimit); void SetTable(int index = -3) const; void SetTableRaw(int index = -3) const; - void SetTimeLimit(UInt32 timeLimit); bool ToBoolean(int index) const; long long ToInteger(int index, bool* succeeded = nullptr) const; @@ -176,18 +176,18 @@ namespace Nz LuaState& operator=(LuaState&& instance) noexcept; static int GetIndexOfUpValue(int upValue); - static LuaState GetState(lua_State* internalState); + static LuaInstance& GetInstance(lua_State* internalState); + static inline LuaState GetState(lua_State* internalState); protected: - LuaState(LuaInstance* instance, lua_State* internalState); + LuaState(lua_State* internalState); template T CheckBounds(int index, long long value) const; - bool Run(int argCount, int resultCount); + virtual bool Run(int argCount, int resultCount); static int ProxyFunc(lua_State* internalState); String m_lastError; - LuaInstance* m_instance; lua_State* m_state; }; } diff --git a/include/Nazara/Lua/LuaState.inl b/include/Nazara/Lua/LuaState.inl index dbc9016cf..fa4ecaaf0 100644 --- a/include/Nazara/Lua/LuaState.inl +++ b/include/Nazara/Lua/LuaState.inl @@ -15,8 +15,7 @@ namespace Nz { - inline LuaState::LuaState(LuaInstance* instance, lua_State* internalState) : - m_instance(instance), + inline LuaState::LuaState(lua_State* internalState) : m_state(internalState) { } @@ -785,4 +784,9 @@ namespace Nz return static_cast(value); } + + inline LuaState LuaState::GetState(lua_State* internalState) + { + return LuaState(internalState); + } } diff --git a/src/Nazara/Lua/LuaCoroutine.cpp b/src/Nazara/Lua/LuaCoroutine.cpp new file mode 100644 index 000000000..ea73af31a --- /dev/null +++ b/src/Nazara/Lua/LuaCoroutine.cpp @@ -0,0 +1,55 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Lua scripting module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include + +namespace Nz +{ + LuaCoroutine::LuaCoroutine(lua_State* internalState, int refIndex) : + LuaState(internalState), + m_ref(refIndex) + { + } + + LuaCoroutine::~LuaCoroutine() + { + if (m_ref >= 0) + DestroyReference(m_ref); + } + + bool LuaCoroutine::CanResume() const + { + return lua_status(m_state) == LUA_YIELD; + } + + Ternary LuaCoroutine::Resume(unsigned int argCount) + { + LuaInstance& instance = GetInstance(m_state); + if (instance.m_level++ == 0) + instance.m_clock.Restart(); + + int status = lua_resume(m_state, nullptr, argCount); + instance.m_level--; + + if (status == LUA_OK) + return Ternary_True; + else if (status == LUA_YIELD) + return Ternary_Unknown; + else + { + m_lastError = ToString(-1); + Pop(); + return Ternary_False; + } + } + + bool LuaCoroutine::Run(int argCount, int /*resultCount*/) + { + return Resume(argCount) != Ternary_False; + } +} diff --git a/src/Nazara/Lua/LuaInstance.cpp b/src/Nazara/Lua/LuaInstance.cpp index 607edc126..a0d5d3ff7 100644 --- a/src/Nazara/Lua/LuaInstance.cpp +++ b/src/Nazara/Lua/LuaInstance.cpp @@ -30,7 +30,7 @@ namespace Nz } LuaInstance::LuaInstance() : - LuaState(this, lua_newstate(MemoryAllocator, this)), + LuaState(nullptr), m_memoryLimit(0), m_memoryUsage(0), m_timeLimit(1000), diff --git a/src/Nazara/Lua/LuaState.cpp b/src/Nazara/Lua/LuaState.cpp index f71504ab7..94170aee0 100644 --- a/src/Nazara/Lua/LuaState.cpp +++ b/src/Nazara/Lua/LuaState.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -127,7 +128,6 @@ namespace Nz LuaState::LuaState(LuaState&& state) noexcept : m_lastError(state.m_lastError), - m_instance(state.m_instance), m_state(state.m_state) { } @@ -570,6 +570,14 @@ namespace Nz lua_xmove(m_state, instance->m_state, n); } + LuaCoroutine LuaState::NewCoroutine() + { + lua_State* thread = lua_newthread(m_state); + int ref = luaL_ref(m_state, LUA_REGISTRYINDEX); + + return LuaCoroutine(thread, ref); + } + bool LuaState::NewMetatable(const char* str) { return luaL_newmetatable(m_state, str) != 0; @@ -783,7 +791,6 @@ namespace Nz LuaState& LuaState::operator=(LuaState&& state) noexcept { - m_instance = state.m_instance; m_lastError = std::move(state.m_lastError); m_state = state.m_state; @@ -792,12 +799,14 @@ namespace Nz bool LuaState::Run(int argCount, int resultCount) { - if (m_instance->m_level++ == 0) - m_instance->m_clock.Restart(); + LuaInstance& instance = GetInstance(m_state); + + if (instance.m_level++ == 0) + instance.m_clock.Restart(); int status = lua_pcall(m_state, argCount, resultCount, 0); - m_instance->m_level--; + instance.m_level--; if (status != 0) { @@ -815,12 +824,12 @@ namespace Nz return lua_upvalueindex(upValue); } - LuaState LuaState::GetState(lua_State* internalState) + LuaInstance& LuaState::GetInstance(lua_State* internalState) { LuaInstance* instance; lua_getallocf(internalState, reinterpret_cast(&instance)); - return LuaState(instance, internalState); + return *instance; } int LuaState::ProxyFunc(lua_State* internalState)