From 3310901ce39cbc65e2ee2b343596e719a7894613 Mon Sep 17 00:00:00 2001 From: Ilia Udalov Date: Sat, 11 Feb 2017 15:44:17 +0300 Subject: [PATCH] Robust exception handling --- src/cpp/garbage-collector.cpp | 14 ++++++------- src/cpp/garbage-collector.h | 20 +++++++++--------- src/cpp/shared-table.cpp | 20 +++++++++--------- src/cpp/shared-table.h | 12 +++++------ src/cpp/stored-object.cpp | 21 ++++++++++--------- src/cpp/stored-object.h | 6 +++--- src/cpp/threading.cpp | 39 +++++++++++++++++------------------ src/cpp/threading.h | 24 ++++++++++----------- src/cpp/utils.h | 3 +-- 9 files changed, 79 insertions(+), 80 deletions(-) diff --git a/src/cpp/garbage-collector.cpp b/src/cpp/garbage-collector.cpp index f6e654a..14b0ea5 100644 --- a/src/cpp/garbage-collector.cpp +++ b/src/cpp/garbage-collector.cpp @@ -7,12 +7,12 @@ namespace effil { -GarbageCollector::GarbageCollector() noexcept +GarbageCollector::GarbageCollector() : state_(GCState::Idle), lastCleanup_(0), step_(200) {} -GCObject* GarbageCollector::get(GCObjectHandle handle) noexcept { +GCObject* GarbageCollector::get(GCObjectHandle handle) { std::lock_guard g(lock_); auto it = objects_.find(handle); if (it == objects_.end()) { @@ -22,7 +22,7 @@ GCObject* GarbageCollector::get(GCObjectHandle handle) noexcept { return it->second.get(); } -bool GarbageCollector::has(GCObjectHandle handle) const noexcept { +bool GarbageCollector::has(GCObjectHandle handle) const { std::lock_guard g(lock_); return objects_.find(handle) != objects_.end(); } @@ -63,25 +63,25 @@ void GarbageCollector::cleanup() { lastCleanup_.store(0); } -size_t GarbageCollector::size() const noexcept { +size_t GarbageCollector::size() const { std::lock_guard g(lock_); return objects_.size(); } -void GarbageCollector::stop() noexcept { +void GarbageCollector::stop() { std::lock_guard g(lock_); assert(state_ == GCState::Idle || state_ == GCState::Stopped); state_ = GCState::Stopped; } -void GarbageCollector::resume() noexcept { +void GarbageCollector::resume() { std::lock_guard g(lock_); assert(state_ == GCState::Idle || state_ == GCState::Stopped); state_ = GCState::Idle; } -GarbageCollector& getGC() noexcept { +GarbageCollector& getGC() { static GarbageCollector pool; return pool; } diff --git a/src/cpp/garbage-collector.h b/src/cpp/garbage-collector.h index 434cb96..9fb78e7 100644 --- a/src/cpp/garbage-collector.h +++ b/src/cpp/garbage-collector.h @@ -39,7 +39,7 @@ enum class GCState { class GarbageCollector { public: - GarbageCollector() noexcept; + GarbageCollector(); ~GarbageCollector() = default; // This method is used to create all managed objects. @@ -53,15 +53,15 @@ public: return *object; } - GCObject* get(GCObjectHandle handle) noexcept; - bool has(GCObjectHandle handle) const noexcept; + GCObject* get(GCObjectHandle handle); + bool has(GCObjectHandle handle) const; void cleanup(); - size_t size() const noexcept; - void stop() noexcept; - void resume() noexcept; - size_t step() const noexcept { return step_; } - void step(size_t newStep) noexcept { step_ = newStep; } - GCState state() const noexcept { return state_; } + size_t size() const; + void stop(); + void resume(); + size_t step() const { return step_; } + void step(size_t newStep) { step_ = newStep; } + GCState state() const { return state_; } private: mutable std::mutex lock_; @@ -76,6 +76,6 @@ private: }; -GarbageCollector& getGC() noexcept; +GarbageCollector& getGC(); } // effil \ No newline at end of file diff --git a/src/cpp/shared-table.cpp b/src/cpp/shared-table.cpp index 0d6ea2d..16622c5 100644 --- a/src/cpp/shared-table.cpp +++ b/src/cpp/shared-table.cpp @@ -7,17 +7,17 @@ namespace effil { -SharedTable::SharedTable() noexcept +SharedTable::SharedTable() : GCObject(), data_(std::make_shared()) { } -SharedTable::SharedTable(const SharedTable& init) noexcept +SharedTable::SharedTable(const SharedTable& init) : GCObject(init), data_(init.data_) { } -sol::object SharedTable::getUserType(sol::state_view &lua) noexcept { +sol::object SharedTable::getUserType(sol::state_view &lua) { static sol::usertype type( "new", sol::no_constructor, sol::meta_function::new_index, &SharedTable::luaSet, @@ -28,7 +28,7 @@ sol::object SharedTable::getUserType(sol::state_view &lua) noexcept { return sol::stack::pop(lua); } -void SharedTable::set(StoredObject&& key, StoredObject&& value) noexcept { +void SharedTable::set(StoredObject&& key, StoredObject&& value) { std::lock_guard g(data_->lock); if (key->gcHandle()) refs_->insert(key->gcHandle()); @@ -38,7 +38,7 @@ void SharedTable::set(StoredObject&& key, StoredObject&& value) noexcept { } void SharedTable::luaSet(const sol::stack_object& luaKey, const sol::stack_object& luaValue) { - ASSERT(luaKey.valid()) << "Invalid table index"; + REQUIRE(luaKey.valid()) << "Indexing by nil"; StoredObject key = createStoredObject(luaKey); if (luaValue.get_type() == sol::type::nil) { @@ -57,12 +57,12 @@ void SharedTable::luaSet(const sol::stack_object& luaKey, const sol::stack_objec } } -sol::object SharedTable::luaGet(const sol::stack_object& key, const sol::this_state& state) const { - ASSERT(key.valid()); +sol::object SharedTable::luaGet(const sol::stack_object& luaKey, const sol::this_state& state) const { + REQUIRE(luaKey.valid()) << "Indexing by nil"; - StoredObject cppKey = createStoredObject(key); + StoredObject key = createStoredObject(luaKey); std::lock_guard g(data_->lock); - auto val = data_->entries.find(cppKey); + auto val = data_->entries.find(key); if (val == data_->entries.end()) { return sol::nil; } else { @@ -70,7 +70,7 @@ sol::object SharedTable::luaGet(const sol::stack_object& key, const sol::this_st } } -size_t SharedTable::size() const noexcept { +size_t SharedTable::size() const { std::lock_guard g(data_->lock); return data_->entries.size(); } diff --git a/src/cpp/shared-table.h b/src/cpp/shared-table.h index e03e5d9..bdd0bac 100644 --- a/src/cpp/shared-table.h +++ b/src/cpp/shared-table.h @@ -13,18 +13,18 @@ namespace effil { class SharedTable : public GCObject { public: - SharedTable() noexcept; + SharedTable(); SharedTable(SharedTable&&) = default; - SharedTable(const SharedTable& init) noexcept; + SharedTable(const SharedTable& init); virtual ~SharedTable() = default; - static sol::object getUserType(sol::state_view &lua) noexcept; - void set(StoredObject&&, StoredObject&&) noexcept; + static sol::object getUserType(sol::state_view &lua); + void set(StoredObject&&, StoredObject&&); // These functions could be invoked from lua scripts void luaSet(const sol::stack_object& luaKey, const sol::stack_object& luaValue); - sol::object luaGet(const sol::stack_object& key, const sol::this_state& state) const; - size_t size() const noexcept; + sol::object luaGet(const sol::stack_object& luaKey, const sol::this_state& state) const; + size_t size() const; private: typedef std::unique_ptr StoredObject; diff --git a/src/cpp/stored-object.cpp b/src/cpp/stored-object.cpp index f6c6f94..afae288 100644 --- a/src/cpp/stored-object.cpp +++ b/src/cpp/stored-object.cpp @@ -47,7 +47,7 @@ public: FunctionHolder(SolObject luaObject) noexcept { sol::state_view lua(luaObject.lua_state()); sol::function dumper = lua["string"]["dump"]; - ASSERT(dumper.valid()); + if (!dumper.valid()) throw Exception() << "Invalid string.dump()"; function_ = dumper(luaObject); } @@ -62,9 +62,10 @@ public: sol::object unpack(sol::this_state state) const final { sol::state_view lua((lua_State*)state); sol::function loader = lua["loadstring"]; - ASSERT(loader.valid()); + REQUIRE(loader.valid()) << "Invalid loadstring()"; sol::function result = loader(function_); - ASSERT(result.valid()) << "Unable to restore function!\n" << "Content:\n" << function_; + // The result of restaring always is valid function. + assert(result.valid()); return sol::make_object(state, result); } @@ -75,28 +76,28 @@ private: class TableHolder : public BaseHolder { public: template - TableHolder(const SolType& luaObject) noexcept { + TableHolder(const SolType& luaObject) { assert(luaObject.template is()); handle_ = luaObject.template as().handle(); assert(getGC().has(handle_)); } - TableHolder(GCObjectHandle handle) noexcept + TableHolder(GCObjectHandle handle) : handle_(handle) {} - bool rawCompare(const BaseHolder *other) const noexcept final { + bool rawCompare(const BaseHolder *other) const final { return static_cast(other)->handle_ == handle_; } - std::size_t hash() const noexcept final { + std::size_t hash() const final { return std::hash()(handle_); } - sol::object unpack(sol::this_state state) const noexcept final { + sol::object unpack(sol::this_state state) const final { return sol::make_object(state, *static_cast(getGC().get(handle_))); } - GCObjectHandle gcHandle() const noexcept override { return handle_; } + GCObjectHandle gcHandle() const override { return handle_; } private: GCObjectHandle handle_; }; @@ -165,7 +166,7 @@ StoredObject fromSolObject(const SolObject& luaObject) { return std::make_unique(table.handle()); } default: - ERROR << "Unable to store object of that type: " << (int)luaObject.get_type() << "\n"; + throw Exception() << "Unable to store object of that type: " << (int)luaObject.get_type() << "\n"; } return nullptr; } diff --git a/src/cpp/stored-object.h b/src/cpp/stored-object.h index a58bd89..54ed1ed 100644 --- a/src/cpp/stored-object.h +++ b/src/cpp/stored-object.h @@ -11,16 +11,16 @@ public: BaseHolder() = default; virtual ~BaseHolder() = default; - bool compare(const BaseHolder* other) const noexcept { + bool compare(const BaseHolder* other) const { return typeid(*this) == typeid(*other) && rawCompare(other); } virtual bool rawCompare(const BaseHolder* other) const = 0; virtual const std::type_info& type() { return typeid(*this); } - virtual std::size_t hash() const noexcept = 0; + virtual std::size_t hash() const = 0; virtual sol::object unpack(sol::this_state state) const = 0; - virtual GCObjectHandle gcHandle() const noexcept { return GCNull; } + virtual GCObjectHandle gcHandle() const { return GCNull; } private: BaseHolder(const BaseHolder&) = delete; diff --git a/src/cpp/threading.cpp b/src/cpp/threading.cpp index cd2f398..83b1f7b 100644 --- a/src/cpp/threading.cpp +++ b/src/cpp/threading.cpp @@ -7,19 +7,19 @@ namespace effil { class LuaHookStopException : public std::exception {}; -std::string threadId() noexcept +std::string threadId() { std::stringstream ss; ss << std::this_thread::get_id(); return ss.str(); } -void yield() noexcept +void yield() { std::this_thread::yield(); } -void sleep(int64_t time, sol::optional period) noexcept +void sleep(int64_t time, sol::optional period) { std::string metric = period ? period.value() : "s"; if (metric == "ms") @@ -38,7 +38,7 @@ thread_local LuaThread::ThreadData* LuaThread::pThreadLocalData = NULL; LuaThread::LuaThread(std::shared_ptr threadData, const std::string& function, const sol::variadic_args& args) { pThreadData_ = threadData; - ASSERT(pThreadData_.get()); + assert(pThreadData_); pThreadData_->command = ThreadCommand::Nothing; pThreadData_->status = ThreadStatus::Running; @@ -49,7 +49,7 @@ LuaThread::LuaThread(std::shared_ptr threadData, const std::string& } pThread_.reset(new std::thread(&LuaThread::work, pThreadData_, function, std::move(arguments))); - ASSERT(pThread_.get() != nullptr); + assert(pThread_); pThread_->detach(); } @@ -84,12 +84,12 @@ void LuaThread::luaHook(lua_State*, lua_Debug*) } } -void LuaThread::work(std::shared_ptr threadData, const std::string strFunction, std::vector&& arguments) noexcept { +void LuaThread::work(std::shared_ptr threadData, const std::string strFunction, std::vector&& arguments) { try { pThreadLocalData = threadData.get(); - ASSERT(threadData.get()) << "invalid internal thread state\n"; + assert(threadData); const sol::object& stringLoader = threadData->luaState["loadstring"]; - ASSERT(stringLoader.valid() && stringLoader.get_type() == sol::type::function); + REQUIRE(stringLoader.valid() && stringLoader.get_type() == sol::type::function) << "Invalid loadstring function"; sol::function userFuncObj = static_cast(stringLoader)(strFunction); sol::function_result results = userFuncObj(sol::as_args(arguments)); (void)results; // TODO: try to avoid use of useless sol::function_result here @@ -111,22 +111,22 @@ void LuaThread::work(std::shared_ptr threadData, const std::string s } } -void LuaThread::cancel() noexcept +void LuaThread::cancel() { pThreadData_->command = ThreadCommand::Cancel; } -void LuaThread::pause() noexcept +void LuaThread::pause() { pThreadData_->command = ThreadCommand::Pause; } -void LuaThread::resume() noexcept +void LuaThread::resume() { pThreadData_->command = ThreadCommand::Resume; } -std::tuple LuaThread::wait(sol::this_state state) const noexcept +std::tuple LuaThread::wait(sol::this_state state) const { ThreadStatus stat = pThreadData_->status; @@ -145,7 +145,7 @@ std::tuple LuaThread::wait(sol::this_state state) const return std::make_tuple(sol::make_object(state, threadStatusToString(stat)), std::move(returns)); } -std::string LuaThread::threadStatusToString(ThreadStatus stat) const noexcept +std::string LuaThread::threadStatusToString(ThreadStatus stat) const { switch(stat) { @@ -159,12 +159,12 @@ std::string LuaThread::threadStatusToString(ThreadStatus stat) const noexcept return "unknown"; } -std::string LuaThread::status() const noexcept +std::string LuaThread::status() const { return threadStatusToString(pThreadData_->status); } -sol::object LuaThread::getUserType(sol::state_view &lua) noexcept +sol::object LuaThread::getUserType(sol::state_view &lua) { static sol::usertype type( "new", sol::no_constructor, @@ -183,8 +183,7 @@ sol::object LuaThread::getUserType(sol::state_view &lua) noexcept ThreadFactory::ThreadFactory(const sol::function& func) : stepwise_(false), step_(100U) { sol::state_view lua(func.lua_state()); const sol::object& dumper = lua["string"]["dump"]; - ASSERT(dumper.valid() && dumper.get_type() == sol::type::function) - << "Unable to get string.dump()"; + REQUIRE(dumper.valid() && dumper.get_type() == sol::type::function) << "Unable to get string.dump()"; strFunction_ = static_cast(dumper)(func); // Inherit all pathes from parent state by default @@ -193,8 +192,8 @@ ThreadFactory::ThreadFactory(const sol::function& func) : stepwise_(false), step } std::unique_ptr ThreadFactory::runThread(const sol::variadic_args& args) { - std::shared_ptr threadData(new LuaThread::ThreadData); - ASSERT(threadData.get()); + std::shared_ptr threadData = std::make_shared(); + assert(threadData.get()); threadData->luaState.open_libraries( sol::lib::base, sol::lib::string, sol::lib::package, sol::lib::io, sol::lib::os @@ -246,7 +245,7 @@ std::string ThreadFactory::packageCPath(const sol::optional& value) return ret; } -sol::object ThreadFactory::getUserType(sol::state_view &lua) noexcept +sol::object ThreadFactory::getUserType(sol::state_view &lua) { static sol::usertype type( "new", sol::no_constructor, diff --git a/src/cpp/threading.h b/src/cpp/threading.h index ffd0ff5..7c0d28b 100644 --- a/src/cpp/threading.h +++ b/src/cpp/threading.h @@ -9,9 +9,9 @@ namespace effil { // Lua this thread API -std::string threadId() noexcept; -void yield() noexcept; -void sleep(int64_t, sol::optional) noexcept; +std::string threadId(); +void yield(); +void sleep(int64_t, sol::optional); class LuaThread { public: @@ -39,22 +39,22 @@ public: }; LuaThread(std::shared_ptr threadData, const std::string& function, const sol::variadic_args& args); - static sol::object getUserType(sol::state_view &lua) noexcept; + static sol::object getUserType(sol::state_view &lua); static void luaHook(lua_State*, lua_Debug*); /* Public lua methods*/ - void cancel() noexcept; - void pause() noexcept; - void resume() noexcept; - std::string status() const noexcept; - std::tuple wait(sol::this_state state) const noexcept; + void cancel(); + void pause(); + void resume(); + std::string status() const; + std::tuple wait(sol::this_state state) const; private: LuaThread(const LuaThread&) = delete; LuaThread& operator=(const LuaThread&) = delete; - std::string threadStatusToString(ThreadStatus stat) const noexcept; - static void work(std::shared_ptr threadData, const std::string strFunction, std::vector&& arguments) noexcept; + std::string threadStatusToString(ThreadStatus stat) const; + static void work(std::shared_ptr threadData, const std::string strFunction, std::vector&& arguments); std::shared_ptr pThreadData_; std::shared_ptr pThread_; @@ -65,7 +65,7 @@ private: class ThreadFactory { public: ThreadFactory(const sol::function& func); - static sol::object getUserType(sol::state_view &lua) noexcept; + static sol::object getUserType(sol::state_view &lua); /* Public lua methods*/ std::unique_ptr runThread(const sol::variadic_args& args); diff --git a/src/cpp/utils.h b/src/cpp/utils.h index 1674861..94ead35 100644 --- a/src/cpp/utils.h +++ b/src/cpp/utils.h @@ -29,8 +29,7 @@ private: } // effil -#define ERROR throw effil::Exception() << __FILE__ << ":" << __LINE__ -#define ASSERT(cond) if (!(cond)) ERROR << "In condition '" << #cond << "': " +#define REQUIRE(cond) if (!cond) throw effil::Exception() #ifdef NDEBUG # define DEBUG if (false) std::cout