From 9221b46e1bdd5e055204c72e885429292a230582 Mon Sep 17 00:00:00 2001 From: Haibo Date: Fri, 16 Nov 2018 15:53:39 +0800 Subject: [PATCH] optimize: intrusive list --- core/base/Action.hpp | 7 +- core/base/ActionFiniteTime.cpp | 2 +- core/base/ActionManager.cpp | 10 +- core/base/ActionManager.h | 2 +- core/base/{BaseTypes.h => BaseTypes.hpp} | 0 core/base/Canvas.cpp | 2 +- core/base/Game.h | 2 +- core/base/Image.h | 2 +- core/base/Input.h | 2 +- core/base/IntrusiveList.hpp | 231 ------------------- core/base/IntrusivePtr.hpp | 184 --------------- core/base/KeyEvent.h | 2 +- core/base/MouseEvent.h | 2 +- core/base/Music.h | 2 +- core/base/Node.cpp | 56 ++--- core/base/Node.h | 11 +- core/base/Task.h | 9 +- core/base/TaskManager.cpp | 16 +- core/base/TaskManager.h | 2 +- core/base/Text.cpp | 2 +- core/base/TextRenderer.cpp | 2 +- core/base/TextStyle.hpp | 2 +- core/base/Transition.h | 2 +- core/base/audio.cpp | 2 +- core/base/{base.h => base.hpp} | 8 +- core/base/intrusive/List.hpp | 273 +++++++++++++++++++++++ core/base/intrusive/SmartPointer.hpp | 195 ++++++++++++++++ core/base/render.cpp | 2 +- core/base/render.h | 2 +- core/base/time.cpp | 6 +- core/base/window.cpp | 5 +- core/base/window.h | 2 +- core/easy2d.h | 6 +- core/math/Transform.hpp | 2 +- core/utils/Data.h | 2 +- core/utils/File.h | 2 +- core/utils/Path.h | 2 +- core/utils/Player.h | 2 +- core/utils/Transcoder.cpp | 2 +- project/vs2013/Easy2D.vcxproj | 8 +- project/vs2013/Easy2D.vcxproj.filters | 23 +- project/vs2015/Easy2D.vcxproj | 8 +- project/vs2015/Easy2D.vcxproj.filters | 23 +- project/vs2017/Easy2D.vcxproj | 10 +- project/vs2017/Easy2D.vcxproj.filters | 23 +- 45 files changed, 613 insertions(+), 547 deletions(-) rename core/base/{BaseTypes.h => BaseTypes.hpp} (100%) delete mode 100644 core/base/IntrusiveList.hpp delete mode 100644 core/base/IntrusivePtr.hpp rename core/base/{base.h => base.hpp} (92%) create mode 100644 core/base/intrusive/List.hpp create mode 100644 core/base/intrusive/SmartPointer.hpp diff --git a/core/base/Action.hpp b/core/base/Action.hpp index e7505422..20edd883 100644 --- a/core/base/Action.hpp +++ b/core/base/Action.hpp @@ -19,9 +19,9 @@ // THE SOFTWARE. #pragma once -#include "base.h" +#include "base.hpp" #include "time.h" -#include "IntrusiveList.hpp" +#include "intrusive/List.hpp" namespace easy2d { @@ -29,7 +29,7 @@ namespace easy2d class Action : public RefCounter - , public IntrusiveItem + , protected intrusive::ListItem { E2D_DISABLE_COPY(Action); @@ -37,6 +37,7 @@ namespace easy2d friend class Loop; friend class Sequence; friend class Spawn; + friend class intrusive::List; public: Action() : running_(false), done_(false), initialized_(false) {} diff --git a/core/base/ActionFiniteTime.cpp b/core/base/ActionFiniteTime.cpp index 44340bc2..d0ff4bdd 100644 --- a/core/base/ActionFiniteTime.cpp +++ b/core/base/ActionFiniteTime.cpp @@ -19,7 +19,7 @@ // THE SOFTWARE. #include "ActionFiniteTime.h" -#include "base.h" +#include "base.hpp" #include "Node.h" #include diff --git a/core/base/ActionManager.cpp b/core/base/ActionManager.cpp index d8c3a8c8..fd387916 100644 --- a/core/base/ActionManager.cpp +++ b/core/base/ActionManager.cpp @@ -31,7 +31,7 @@ namespace easy2d spAction next; for (auto action = actions_.First(); action; action = next) { - next = action->Next(); + next = action->NextItem(); if (action->IsRunning()) action->Update(target, dt); @@ -49,7 +49,7 @@ namespace easy2d if (action) { action->Start(); - actions_.Append(action); + actions_.PushBack(Action::ItemType(action)); } } @@ -58,7 +58,7 @@ namespace easy2d if (actions_.IsEmpty()) return; - for (auto& action = actions_.First(); action; action = action->Next()) + for (auto& action = actions_.First(); action; action = action->NextItem()) { action->Resume(); } @@ -69,7 +69,7 @@ namespace easy2d if (actions_.IsEmpty()) return; - for (auto& action = actions_.First(); action; action = action->Next()) + for (auto& action = actions_.First(); action; action = action->NextItem()) { action->Pause(); } @@ -80,7 +80,7 @@ namespace easy2d if (actions_.IsEmpty()) return; - for (auto& action = actions_.First(); action; action = action->Next()) + for (auto& action = actions_.First(); action; action = action->NextItem()) { action->Stop(); } diff --git a/core/base/ActionManager.h b/core/base/ActionManager.h index 015f7a8c..8ecb28a1 100644 --- a/core/base/ActionManager.h +++ b/core/base/ActionManager.h @@ -25,7 +25,7 @@ namespace easy2d { class ActionManager { - using Actions = IntrusiveList; + using Actions = intrusive::List; public: // 执行动作 diff --git a/core/base/BaseTypes.h b/core/base/BaseTypes.hpp similarity index 100% rename from core/base/BaseTypes.h rename to core/base/BaseTypes.hpp diff --git a/core/base/Canvas.cpp b/core/base/Canvas.cpp index 282b4f17..d58aea5a 100644 --- a/core/base/Canvas.cpp +++ b/core/base/Canvas.cpp @@ -18,7 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -#include "base.h" +#include "base.hpp" #include "Canvas.h" #include "render.h" #include "logs.h" diff --git a/core/base/Game.h b/core/base/Game.h index ca984bcb..23ab7a21 100644 --- a/core/base/Game.h +++ b/core/base/Game.h @@ -19,7 +19,7 @@ // THE SOFTWARE. #pragma once -#include "base.h" +#include "base.hpp" #include "window.h" #include "time.h" #include "KeyEvent.h" diff --git a/core/base/Image.h b/core/base/Image.h index 2ec999a4..07d78315 100644 --- a/core/base/Image.h +++ b/core/base/Image.h @@ -19,7 +19,7 @@ // THE SOFTWARE. #pragma once -#include "base.h" +#include "base.hpp" #include "Resource.h" namespace easy2d diff --git a/core/base/Input.h b/core/base/Input.h index 8e48e963..e7996944 100644 --- a/core/base/Input.h +++ b/core/base/Input.h @@ -19,7 +19,7 @@ // THE SOFTWARE. #pragma once -#include "base.h" +#include "base.hpp" #include "Singleton.hpp" namespace easy2d diff --git a/core/base/IntrusiveList.hpp b/core/base/IntrusiveList.hpp deleted file mode 100644 index b7cd3013..00000000 --- a/core/base/IntrusiveList.hpp +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright (c) 2016-2018 Easy2D - Nomango -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#pragma once -#include "macros.h" -#include - -namespace easy2d -{ - template - class IntrusiveList - { - T first_; - T last_; - int size_; - - public: - IntrusiveList() : first_(), last_(), size_(0) {} - - ~IntrusiveList() { Clear(); } - - T const& First() const { return first_; } - - T& First() { return first_; } - - T const& Last() const { return last_; } - - T& Last() { return last_; } - - bool IsEmpty() const { return size_ == 0; } - - int Size() const { return size_; } - - void Append(T child) - { - child->prev_ = last_; - child->next_ = nullptr; - - if (first_) - { - last_->next_ = child; - } - else - { - first_ = child; - } - - last_ = child; - ++size_; - -#ifdef E2D_DEBUG - Check(); -#endif - } - - void Prepend(T child) - { - child->prev_ = nullptr; - child->next_ = first_; - - if (first_) - { - first_->prev_ = child; - } - else - { - last_ = child; - } - - first_ = child; - ++size_; - -#ifdef E2D_DEBUG - Check(); -#endif - } - - void Remove(T child) - { -#ifdef E2D_DEBUG - T tmp = first_; - while (tmp != child) - { - if (tmp == last_) - throw std::logic_error("The node to be removed is not in this list"); - tmp = tmp->next_; - } -#endif - - if (child->next_) - { - child->next_->prev_ = child->prev_; - } - else - { - last_ = child->prev_; - } - - if (child->prev_) - { - child->prev_->next_ = child->next_; - } - else - { - first_ = child->next_; - } - - child->prev_ = nullptr; - child->next_ = nullptr; - --size_; - -#ifdef E2D_DEBUG - Check(); -#endif - } - - void Insert(T child, T before) - { - if (before->prev_) - before->prev_->next_ = child; - else - first_ = child; - - child->prev_ = before->prev_; - child->next_ = before; - before->prev_ = child; - ++size_; - -#ifdef E2D_DEBUG - Check(); -#endif - } - - void Clear() - { - T p = first_; - while (p) - { - T tmp = p; - p = p->next_; - if (tmp) - { - tmp->next_ = nullptr; - tmp->prev_ = nullptr; - } - } - first_ = nullptr; - last_ = nullptr; - size_ = 0; - } - - void Sort(std::function func) - { -#ifdef E2D_DEBUG - Check(); -#endif - } - -#ifdef E2D_DEBUG - - void Check() - { - if (!first_) - return; - - int pos = 0; - T p = first_; - T tmp = p; - do - { - tmp = p; - p = p->next_; - ++pos; - - if (p) - { - if (p->prev_ != tmp) - throw std::logic_error("Check list failed"); - } - else - { - if (tmp != last_) - throw std::logic_error("Check list failed"); - } - } while (p); - - if (pos != size_) - throw std::logic_error("Check list failed"); - } - -#endif - }; - - template - class IntrusiveItem - { - T prev_; - T next_; - - template - friend class IntrusiveList; - - public: - IntrusiveItem() : prev_(), next_() {} - - T const& Prev() const { return prev_; } - - T& Prev() { return prev_; } - - T const& Next() const { return next_; } - - T& Next() { return next_; } - }; -} diff --git a/core/base/IntrusivePtr.hpp b/core/base/IntrusivePtr.hpp deleted file mode 100644 index 0c70ac5e..00000000 --- a/core/base/IntrusivePtr.hpp +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright (c) 2016-2018 Easy2D - Nomango -// -// Permission is hereby granted, free of charge, to any person obtaining lhs copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#pragma once -#include - -namespace easy2d -{ - template - class IntrusivePtr - { - using ElemType = T; - - ElemType* ptr_{ nullptr }; - - public: - IntrusivePtr() {} - - IntrusivePtr(nullptr_t) {} - - IntrusivePtr(ElemType* p) : ptr_(p) - { - IntrusivePtrAddRef(ptr_); - } - - IntrusivePtr(const IntrusivePtr& other) : ptr_(other.ptr_) - { - IntrusivePtrAddRef(ptr_); - } - - template - IntrusivePtr(const IntrusivePtr& other) : ptr_(other.Get()) - { - IntrusivePtrAddRef(ptr_); - } - - IntrusivePtr(IntrusivePtr&& other) - { - ptr_ = other.ptr_; - other.ptr_ = nullptr; - } - - ~IntrusivePtr() - { - IntrusivePtrRelease(ptr_); - } - - inline ElemType* Get() const { return ptr_; } - - inline void Swap(IntrusivePtr& other) - { - std::swap(ptr_, other.ptr_); - } - - inline ElemType* operator ->() const - { - return ptr_; - } - - inline ElemType& operator *() const - { - return *ptr_; - } - - inline operator bool() const { return ptr_ != nullptr; } - - inline bool operator !() const { return ptr_ == 0; } - - inline IntrusivePtr& operator =(const IntrusivePtr& other) - { - IntrusivePtr(other).Swap(*this); - return *this; - } - - inline IntrusivePtr& operator =(IntrusivePtr&& other) - { - IntrusivePtrRelease(ptr_); - ptr_ = other.ptr_; - other.ptr_ = nullptr; - return *this; - } - - inline IntrusivePtr& operator =(ElemType* p) - { - IntrusivePtr(p).Swap(*this); - return *this; - } - - inline IntrusivePtr& operator =(nullptr_t) - { - IntrusivePtr{}.Swap(*this); - return *this; - } - }; - - template - inline bool operator==(IntrusivePtr const& lhs, IntrusivePtr const& rhs) - { - return lhs.Get() == rhs.Get(); - } - - template - inline bool operator!=(IntrusivePtr const& lhs, IntrusivePtr const& rhs) - { - return lhs.Get() != rhs.Get(); - } - - template - inline bool operator<(IntrusivePtr const& lhs, IntrusivePtr const& rhs) - { - return lhs.Get() < rhs.Get(); - } - - template - inline bool operator==(IntrusivePtr const& lhs, T* rhs) - { - return lhs.Get() == rhs; - } - - template - inline bool operator!=(IntrusivePtr const& lhs, T* rhs) - { - return lhs.Get() != rhs; - } - - template - inline bool operator==(T* lhs, IntrusivePtr const& rhs) - { - return lhs == rhs.Get(); - } - - template - inline bool operator!=(T* lhs, IntrusivePtr const& rhs) - { - return lhs != rhs.Get(); - } - - template - inline bool operator==(IntrusivePtr const& lhs, nullptr_t) - { - return !static_cast(lhs); - } - - template - inline bool operator!=(IntrusivePtr const& lhs, nullptr_t) - { - return static_cast(lhs); - } - - template - inline bool operator==(nullptr_t, IntrusivePtr const& rhs) - { - return !static_cast(rhs); - } - - template - inline bool operator!=(nullptr_t, IntrusivePtr const& rhs) - { - return static_cast(rhs); - } - - template - inline IntrusivePtr make_intrusive(T* ptr) - { - return IntrusivePtr(ptr); - } -} diff --git a/core/base/KeyEvent.h b/core/base/KeyEvent.h index 2e676868..c701abf4 100644 --- a/core/base/KeyEvent.h +++ b/core/base/KeyEvent.h @@ -20,7 +20,7 @@ #pragma once #include "macros.h" -#include "BaseTypes.h" +#include "BaseTypes.hpp" namespace easy2d { diff --git a/core/base/MouseEvent.h b/core/base/MouseEvent.h index 7201b11e..a77261e9 100644 --- a/core/base/MouseEvent.h +++ b/core/base/MouseEvent.h @@ -20,7 +20,7 @@ #pragma once #include "macros.h" -#include "BaseTypes.h" +#include "BaseTypes.hpp" namespace easy2d { diff --git a/core/base/Music.h b/core/base/Music.h index b79c280f..4987d5dc 100644 --- a/core/base/Music.h +++ b/core/base/Music.h @@ -19,7 +19,7 @@ // THE SOFTWARE. #pragma once -#include "base.h" +#include "base.hpp" #include "audio.h" #include "Resource.h" #include diff --git a/core/base/Node.cpp b/core/base/Node.cpp index 8276512e..8a2f5b44 100644 --- a/core/base/Node.cpp +++ b/core/base/Node.cpp @@ -97,7 +97,7 @@ namespace easy2d spNode child = children_.First(); for (spNode next; child; child = next) { - next = child->Next(); + next = child->NextItem(); if (child->GetOrder() < 0) { child->Visit(); @@ -113,7 +113,7 @@ namespace easy2d for (spNode next; child; child = next) { - next = child->Next(); + next = child->NextItem(); child->Visit(); } } @@ -141,7 +141,7 @@ namespace easy2d { if (child->GetOrder() < 0) { - next = child->Next(); + next = child->NextItem(); child->Update(dt); } else @@ -157,7 +157,7 @@ namespace easy2d for (spNode next; child; child = next) { - next = child->Next(); + next = child->NextItem(); child->Update(dt); } } @@ -172,7 +172,7 @@ namespace easy2d devices::Graphics::Instance()->DrawGeometry(border_, border_color_, 1.f, 1.5f); } - for (auto& child = children_.First(); child; child = child->Next()) + for (auto& child = children_.First(); child; child = child->NextItem()) { child->DrawBorder(); } @@ -203,7 +203,7 @@ namespace easy2d devices::Graphics::Instance()->CreateRectGeometry(final_matrix_, transform_.size, &border_) ); - for (auto& child = children_.First(); child; child = child->Next()) + for (auto& child = children_.First(); child; child = child->NextItem()) { child->dirty_transform_ = true; } @@ -216,7 +216,7 @@ namespace easy2d spNode prev; for (auto& child = children_.Last(); child; child = prev) { - prev = child->Prev(); + prev = child->PrevItem(); handled = child->Dispatch(e, handled); } @@ -235,7 +235,7 @@ namespace easy2d spNode prev; for (auto& child = children_.Last(); child; child = prev) { - prev = child->Prev(); + prev = child->PrevItem(); handled = child->Dispatch(e, handled); } @@ -253,7 +253,7 @@ namespace easy2d { display_opacity_ = real_opacity_ * parent_->display_opacity_; } - for (auto& child = children_.First(); child; child = child->Next()) + for (auto& child = children_.First(); child; child = child->NextItem()) { child->UpdateOpacity(); } @@ -543,28 +543,20 @@ namespace easy2d if (child) { +#ifdef E2D_DEBUG if (child->parent_) - { - throw std::logic_error("节点已有父节点, 不能再添加到其他节点"); - } + logs::Errorln("The node to be added already has a parent"); + for (Node* parent = parent_; parent; parent = parent->parent_) + if (parent == child) + logs::Errorln("A node cannot be its own parent"); +#endif // E2D_DEBUG - for (Node * parent = this; parent; parent = parent->GetParent().Get()) - { - if (child == parent) - { - throw std::logic_error("一个节点不能同时是另一个节点的父节点和子节点"); - } - } - - children_.Append(child); - child->SetOrder(order); + children_.PushBack(Node::ItemType(child)); child->parent_ = this; - - // 更新子节点透明度 - child->UpdateOpacity(); - // 更新节点转换 child->dirty_transform_ = true; - // 更新子节点排序 + child->SetOrder(order); + child->UpdateOpacity(); + dirty_sort_ = true; } } @@ -587,7 +579,7 @@ namespace easy2d Nodes children; size_t hash_code = std::hash{}(name); - for (auto child = children_.First(); child != children_.Last(); child = child->Next()) + for (auto child = children_.First(); child != children_.Last(); child = child->NextItem()) { if (child->hash_name_ == hash_code && child->name_ == name) { @@ -601,7 +593,7 @@ namespace easy2d { size_t hash_code = std::hash{}(name); - for (auto child = children_.First(); child != children_.Last(); child = child->Next()) + for (auto child = children_.First(); child != children_.Last(); child = child->NextItem()) { if (child->hash_name_ == hash_code && child->name_ == name) { @@ -618,7 +610,7 @@ namespace easy2d int Node::GetChildrenCount() const { - return children_.Size(); + return static_cast(children_.Size()); } void Node::RemoveFromParent() @@ -641,7 +633,7 @@ namespace easy2d if (child) { - children_.Remove(child); + children_.Remove(Node::ItemType(child)); return true; } return false; @@ -658,7 +650,7 @@ namespace easy2d spNode next; for (auto& child = children_.First(); child; child = next) { - next = child->Next(); + next = child->NextItem(); if (child->hash_name_ == hash_code && child->name_ == child_name) children_.Remove(child); diff --git a/core/base/Node.h b/core/base/Node.h index 3ccf10a3..8338f9c8 100644 --- a/core/base/Node.h +++ b/core/base/Node.h @@ -19,13 +19,13 @@ // THE SOFTWARE. #pragma once -#include "base.h" +#include "base.hpp" #include "time.h" #include "KeyEvent.h" #include "MouseEvent.h" #include "ActionManager.h" #include "TaskManager.h" -#include "IntrusiveList.hpp" +#include "intrusive/List.hpp" #include "../math/Transform.hpp" #include "../math/Matrix.hpp" @@ -38,16 +38,17 @@ namespace easy2d : public RefCounter , public ActionManager , public TaskManager - , public IntrusiveItem + , protected intrusive::ListItem { friend class Game; friend class Scene; friend class Transition; + friend class intrusive::List; E2D_DISABLE_COPY(Node); - using Nodes = std::vector< spNode >; - using Children = IntrusiveList; + using Nodes = std::vector; + using Children = intrusive::List; public: Node(); diff --git a/core/base/Task.h b/core/base/Task.h index 36410a2a..e070e1b8 100644 --- a/core/base/Task.h +++ b/core/base/Task.h @@ -19,9 +19,9 @@ // THE SOFTWARE. #pragma once -#include "base.h" +#include "base.hpp" #include "time.h" -#include "IntrusiveList.hpp" +#include "intrusive/List.hpp" #include namespace easy2d @@ -31,11 +31,12 @@ namespace easy2d // 定时任务 class Task : public RefCounter - , public IntrusiveItem + , protected intrusive::ListItem { friend class TaskManager; + friend class intrusive::List; - typedef std::function Callback; + using Callback = std::function; public: explicit Task( diff --git a/core/base/TaskManager.cpp b/core/base/TaskManager.cpp index e2c048b9..33511bb7 100644 --- a/core/base/TaskManager.cpp +++ b/core/base/TaskManager.cpp @@ -31,7 +31,7 @@ namespace easy2d spTask next; for (auto task = tasks_.First(); task; task = next) { - next = task->Next(); + next = task->NextItem(); task->Update(dt); @@ -48,13 +48,13 @@ namespace easy2d if (task) { task->Reset(); - tasks_.Append(task); + tasks_.PushBack(Task::ItemType(task)); } } void TaskManager::StopTasks(const String& name) { - for (auto& task = tasks_.First(); task; task = task->Next()) + for (auto& task = tasks_.First(); task; task = task->NextItem()) { if (task->GetName() == name) { @@ -65,7 +65,7 @@ namespace easy2d void TaskManager::StartTasks(const String& name) { - for (auto& task = tasks_.First(); task; task = task->Next()) + for (auto& task = tasks_.First(); task; task = task->NextItem()) { if (task->GetName() == name) { @@ -76,7 +76,7 @@ namespace easy2d void TaskManager::RemoveTasks(const String& name) { - for (auto& task = tasks_.First(); task; task = task->Next()) + for (auto& task = tasks_.First(); task; task = task->NextItem()) { if (task->GetName() == name) { @@ -87,7 +87,7 @@ namespace easy2d void TaskManager::StopAllTasks() { - for (auto& task = tasks_.First(); task; task = task->Next()) + for (auto& task = tasks_.First(); task; task = task->NextItem()) { task->Stop(); } @@ -95,7 +95,7 @@ namespace easy2d void TaskManager::StartAllTasks() { - for (auto& task = tasks_.First(); task; task = task->Next()) + for (auto& task = tasks_.First(); task; task = task->NextItem()) { task->Start(); } @@ -103,7 +103,7 @@ namespace easy2d void TaskManager::RemoveAllTasks() { - for (auto& task = tasks_.First(); task; task = task->Next()) + for (auto& task = tasks_.First(); task; task = task->NextItem()) { task->stopped_ = true; } diff --git a/core/base/TaskManager.h b/core/base/TaskManager.h index 3fb7c7cf..b15c4d8b 100644 --- a/core/base/TaskManager.h +++ b/core/base/TaskManager.h @@ -25,7 +25,7 @@ namespace easy2d { class TaskManager { - using Tasks = IntrusiveList; + using Tasks = intrusive::List; public: // 添加任务 diff --git a/core/base/Text.cpp b/core/base/Text.cpp index df4df087..76bb0fae 100644 --- a/core/base/Text.cpp +++ b/core/base/Text.cpp @@ -20,7 +20,7 @@ #include "Text.h" #include "render.h" -#include "base.h" +#include "base.hpp" #include "logs.h" namespace easy2d diff --git a/core/base/TextRenderer.cpp b/core/base/TextRenderer.cpp index 51ddceb8..bd5ce7b7 100644 --- a/core/base/TextRenderer.cpp +++ b/core/base/TextRenderer.cpp @@ -19,7 +19,7 @@ // THE SOFTWARE. #include "TextRenderer.h" -#include "base.h" +#include "base.hpp" #include "render.h" namespace easy2d diff --git a/core/base/TextStyle.hpp b/core/base/TextStyle.hpp index c1c57f79..37583ff9 100644 --- a/core/base/TextStyle.hpp +++ b/core/base/TextStyle.hpp @@ -19,7 +19,7 @@ // THE SOFTWARE. #pragma once -#include "base.h" +#include "base.hpp" namespace easy2d { diff --git a/core/base/Transition.h b/core/base/Transition.h index 921d05ba..8e4900c2 100644 --- a/core/base/Transition.h +++ b/core/base/Transition.h @@ -19,7 +19,7 @@ // THE SOFTWARE. #pragma once -#include "base.h" +#include "base.hpp" #include "time.h" namespace easy2d diff --git a/core/base/audio.cpp b/core/base/audio.cpp index 674d4bcd..f96b2ad4 100644 --- a/core/base/audio.cpp +++ b/core/base/audio.cpp @@ -19,7 +19,7 @@ // THE SOFTWARE. #include "audio.h" -#include "base.h" +#include "base.hpp" #include "modules.h" #include "logs.h" #include diff --git a/core/base/base.h b/core/base/base.hpp similarity index 92% rename from core/base/base.h rename to core/base/base.hpp index d8d9f50f..8a47ee2a 100644 --- a/core/base/base.h +++ b/core/base/base.hpp @@ -19,21 +19,21 @@ // THE SOFTWARE. #pragma once -#include "BaseTypes.h" -#include "IntrusivePtr.hpp" +#include "BaseTypes.hpp" +#include "intrusive/SmartPointer.hpp" #include "RefCounter.hpp" #ifndef E2D_DECLARE_SMART_PTR #define E2D_DECLARE_SMART_PTR(class_name)\ class class_name;\ - using sp##class_name = ::easy2d::IntrusivePtr< class_name > + using sp##class_name = ::easy2d::intrusive::SmartPointer< class_name > #define E2D_DECLARE_NS_SMART_PTR(ns_name, class_name)\ namespace ns_name\ {\ class class_name; \ - using sp##class_name = ::easy2d::IntrusivePtr< class_name >;\ + using sp##class_name = ::easy2d::intrusive::SmartPointer< class_name >;\ } #endif diff --git a/core/base/intrusive/List.hpp b/core/base/intrusive/List.hpp new file mode 100644 index 00000000..36aed978 --- /dev/null +++ b/core/base/intrusive/List.hpp @@ -0,0 +1,273 @@ +// Copyright (c) 2016-2018 Easy2D - Nomango +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#pragma once +#include +#include + +namespace easy2d +{ + namespace intrusive + { + template class List; + + template + class ListItem + { + T prev_; + T next_; + + template + friend class List; + + public: + using ItemType = T; + + ListItem() : prev_(), next_() {} + + T const& PrevItem() const { return prev_; } + + T& PrevItem() { return prev_; } + + T const& NextItem() const { return next_; } + + T& NextItem() { return next_; } + }; + + + template + class List + { + T first_; + T last_; + unsigned int size_; + + public: + using ItemType = T; + + List() : first_(), last_(), size_(0) {} + + ~List() { Clear(); } + + T const& First() const { return first_; } + + T& First() { return first_; } + + T const& Last() const { return last_; } + + T& Last() { return last_; } + + bool IsEmpty() const { return size_ == 0; } + + unsigned int Size() const { return size_; } + + void PushBack(T& child) + { + child->prev_ = last_; + child->next_ = nullptr; + + if (first_) + { + last_->next_ = child; + } + else + { + first_ = child; + } + + last_ = child; + ++size_; + +#ifdef E2D_DEBUG + Check(); +#endif + } + + void PushFront(T& child) + { + child->prev_ = nullptr; + child->next_ = first_; + + if (first_) + { + first_->prev_ = child; + } + else + { + last_ = child; + } + + first_ = child; + ++size_; + +#ifdef E2D_DEBUG + Check(); +#endif + } + + void Remove(T& child) + { +#ifdef E2D_DEBUG + T tmp = first_; + while (tmp != child) + { + if (tmp == last_) + throw std::logic_error("The node to be removed is not in this list"); + tmp = tmp->next_; + } +#endif + + if (child->next_) + { + child->next_->prev_ = child->prev_; + } + else + { + last_ = child->prev_; + } + + if (child->prev_) + { + child->prev_->next_ = child->next_; + } + else + { + first_ = child->next_; + } + + child->prev_ = nullptr; + child->next_ = nullptr; + --size_; + +#ifdef E2D_DEBUG + Check(); +#endif + } + + void Insert(T& child, T& before) + { + if (before->prev_) + before->prev_->next_ = child; + else + first_ = child; + + child->prev_ = before->prev_; + child->next_ = before; + before->prev_ = child; + ++size_; + +#ifdef E2D_DEBUG + Check(); +#endif + } + + void Clear() + { + T p = first_; + while (p) + { + T tmp = p; + p = p->next_; + if (tmp) + { + tmp->next_ = nullptr; + tmp->prev_ = nullptr; + } + } + first_ = nullptr; + last_ = nullptr; + size_ = 0; + } + + void Sort(std::function const& if_lt) + { + if (size_ < 2) + return; + + std::vector temp_vec; + temp_vec.reserve(size_); + for (ItemType p = first_; p; p = p->NextItem()) + { + temp_vec.push_back(p); + } + std::sort(temp_vec.begin(), temp_vec.end(), if_lt); + + for (unsigned int i = 0; i < size_; ++i) + { + if (i == 0) + temp_vec[i]->prev_ = ItemType(); + else + { + temp_vec[i]->prev_ = temp_vec[i - 1]; + temp_vec[i - 1]->next_ = temp_vec[i]; + } + if (i == size_ - 1) + temp_vec[i]->next_ = ItemType(); + else + { + temp_vec[i]->next_ = temp_vec[i + 1]; + temp_vec[i + 1]->prev_ = temp_vec[i]; + } + } + first_ = *temp_vec.begin(); + last_ = *temp_vec.rbegin(); + +#ifdef E2D_DEBUG + Check(); +#endif + } + +#ifdef E2D_DEBUG + + private: + void Check() + { + if (!first_) + return; + + int pos = 0; + T p = first_; + T tmp = p; + do + { + tmp = p; + p = p->next_; + ++pos; + + if (p) + { + if (p->prev_ != tmp) + throw std::logic_error("Check list failed"); + } + else + { + if (tmp != last_) + throw std::logic_error("Check list failed"); + } + } while (p); + + if (pos != size_) + throw std::logic_error("Check list failed"); + } + +#endif + }; + } +} diff --git a/core/base/intrusive/SmartPointer.hpp b/core/base/intrusive/SmartPointer.hpp new file mode 100644 index 00000000..d0b52a4d --- /dev/null +++ b/core/base/intrusive/SmartPointer.hpp @@ -0,0 +1,195 @@ +// Copyright (c) 2016-2018 Easy2D - Nomango +// +// Permission is hereby granted, free of charge, to any person obtaining lhs copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#pragma once +#include + +namespace easy2d +{ + namespace intrusive + { + template + class SmartPointer + { + T* ptr_{ nullptr }; + + public: + using Type = T; + + SmartPointer() {} + + SmartPointer(nullptr_t) {} + + SmartPointer(Type* p) : ptr_(p) + { + IntrusivePtrAddRef(ptr_); + } + + SmartPointer(const SmartPointer& other) : ptr_(other.ptr_) + { + IntrusivePtrAddRef(ptr_); + } + + template + SmartPointer(const SmartPointer& other) : ptr_(other.Get()) + { + IntrusivePtrAddRef(ptr_); + } + + SmartPointer(SmartPointer&& other) + { + ptr_ = other.ptr_; + other.ptr_ = nullptr; + } + + ~SmartPointer() + { + IntrusivePtrRelease(ptr_); + } + + inline Type* Get() const { return ptr_; } + + inline void Swap(SmartPointer& other) + { + std::swap(ptr_, other.ptr_); + } + + inline Type* operator ->() const + { + return ptr_; + } + + inline Type& operator *() const + { + return *ptr_; + } + + inline operator bool() const { return ptr_ != nullptr; } + + inline bool operator !() const { return ptr_ == 0; } + + inline SmartPointer& operator =(const SmartPointer& other) + { + SmartPointer(other).Swap(*this); + return *this; + } + + inline SmartPointer& operator =(SmartPointer&& other) + { + IntrusivePtrRelease(ptr_); + ptr_ = other.ptr_; + other.ptr_ = nullptr; + return *this; + } + + inline SmartPointer& operator =(Type* p) + { + SmartPointer(p).Swap(*this); + return *this; + } + + inline SmartPointer& operator =(nullptr_t) + { + SmartPointer{}.Swap(*this); + return *this; + } + }; + + template + inline bool operator==(SmartPointer const& lhs, SmartPointer const& rhs) + { + return lhs.Get() == rhs.Get(); + } + + template + inline bool operator!=(SmartPointer const& lhs, SmartPointer const& rhs) + { + return lhs.Get() != rhs.Get(); + } + + template + inline bool operator<(SmartPointer const& lhs, SmartPointer const& rhs) + { + return lhs.Get() < rhs.Get(); + } + + template + inline bool operator==(SmartPointer const& lhs, T* rhs) + { + return lhs.Get() == rhs; + } + + template + inline bool operator!=(SmartPointer const& lhs, T* rhs) + { + return lhs.Get() != rhs; + } + + template + inline bool operator==(T* lhs, SmartPointer const& rhs) + { + return lhs == rhs.Get(); + } + + template + inline bool operator!=(T* lhs, SmartPointer const& rhs) + { + return lhs != rhs.Get(); + } + + template + inline bool operator==(SmartPointer const& lhs, nullptr_t) + { + return !static_cast(lhs); + } + + template + inline bool operator!=(SmartPointer const& lhs, nullptr_t) + { + return static_cast(lhs); + } + + template + inline bool operator==(nullptr_t, SmartPointer const& rhs) + { + return !static_cast(rhs); + } + + template + inline bool operator!=(nullptr_t, SmartPointer const& rhs) + { + return static_cast(rhs); + } + + template + inline SmartPointer make_intrusive(T* ptr) + { + return SmartPointer(ptr); + } + + // template class cannot support std::swap, + // so implement a swap function in easy2d namespace + template + inline void swap(SmartPointer& lhs, SmartPointer& rhs) + { + lhs.Swap(rhs); + } + } +} diff --git a/core/base/render.cpp b/core/base/render.cpp index 2709d20a..ca8347ad 100644 --- a/core/base/render.cpp +++ b/core/base/render.cpp @@ -20,7 +20,7 @@ #include "render.h" #include "time.h" -#include "base.h" +#include "base.hpp" #include "logs.h" #include "modules.h" #include "Image.h" diff --git a/core/base/render.h b/core/base/render.h index f0ec43e9..536c48f6 100644 --- a/core/base/render.h +++ b/core/base/render.h @@ -19,7 +19,7 @@ // THE SOFTWARE. #pragma once -#include "base.h" +#include "base.hpp" #include "Singleton.hpp" #include "Font.hpp" #include "Resource.h" diff --git a/core/base/time.cpp b/core/base/time.cpp index 9bd94b47..1ae4ad01 100644 --- a/core/base/time.cpp +++ b/core/base/time.cpp @@ -440,7 +440,11 @@ namespace easy2d if (freq.QuadPart == 0LL) { if (QueryPerformanceFrequency(&freq) == 0) - throw std::runtime_error("QueryPerformanceFrequency not supported: " + std::to_string(GetLastError())); + { + const char* err = "QueryPerformanceFrequency not supported"; + logs::Errorln(HRESULT_FROM_WIN32(GetLastError()), err); + throw std::runtime_error(err); + } } LARGE_INTEGER count; diff --git a/core/base/window.cpp b/core/base/window.cpp index bec8e369..ed36bbec 100644 --- a/core/base/window.cpp +++ b/core/base/window.cpp @@ -117,7 +117,10 @@ namespace easy2d if (handle == nullptr) { ::UnregisterClass(REGISTER_CLASS, hinstance); - throw std::runtime_error("Create window failed!"); + + const char* err = "Create window failed!"; + logs::Errorln(err); + throw std::runtime_error(err); } // 禁用输入法 diff --git a/core/base/window.h b/core/base/window.h index 230a540f..0b4999a5 100644 --- a/core/base/window.h +++ b/core/base/window.h @@ -19,7 +19,7 @@ // THE SOFTWARE. #pragma once -#include "base.h" +#include "base.hpp" #include "Singleton.hpp" namespace easy2d diff --git a/core/easy2d.h b/core/easy2d.h index 90247436..c6602038 100644 --- a/core/easy2d.h +++ b/core/easy2d.h @@ -31,7 +31,7 @@ // #include "base/macros.h" -#include "base/base.h" +#include "base/base.hpp" #include "base/modules.h" #include "base/render.h" #include "base/window.h" @@ -47,8 +47,10 @@ #include "base/Color.h" #include "base/Resource.h" +#include "base/intrusive/SmartPointer.hpp" +#include "base/intrusive/List.hpp" + #include "base/RefCounter.hpp" -#include "base/IntrusivePtr.hpp" #include "base/Image.h" #include "base/Node.h" #include "base/Scene.h" diff --git a/core/math/Transform.hpp b/core/math/Transform.hpp index d15f762d..00fab384 100644 --- a/core/math/Transform.hpp +++ b/core/math/Transform.hpp @@ -19,7 +19,7 @@ // THE SOFTWARE. #pragma once -#include "../base/BaseTypes.h" +#include "../base/BaseTypes.hpp" #include "Matrix.hpp" namespace easy2d diff --git a/core/utils/Data.h b/core/utils/Data.h index 8bf6a153..53a98a16 100644 --- a/core/utils/Data.h +++ b/core/utils/Data.h @@ -19,7 +19,7 @@ // THE SOFTWARE. #pragma once -#include "../base/base.h" +#include "../base/base.hpp" namespace easy2d { diff --git a/core/utils/File.h b/core/utils/File.h index 52aa596d..cf6e4fe5 100644 --- a/core/utils/File.h +++ b/core/utils/File.h @@ -19,7 +19,7 @@ // THE SOFTWARE. #pragma once -#include "../base/base.h" +#include "../base/base.hpp" #include "../base/Resource.h" namespace easy2d diff --git a/core/utils/Path.h b/core/utils/Path.h index e68b8c7c..96a6a9e6 100644 --- a/core/utils/Path.h +++ b/core/utils/Path.h @@ -19,7 +19,7 @@ // THE SOFTWARE. #pragma once -#include "../base/base.h" +#include "../base/base.hpp" namespace easy2d { diff --git a/core/utils/Player.h b/core/utils/Player.h index d61b2452..e1c93eb4 100644 --- a/core/utils/Player.h +++ b/core/utils/Player.h @@ -19,7 +19,7 @@ // THE SOFTWARE. #pragma once -#include "../base/base.h" +#include "../base/base.hpp" #include "../base/Resource.h" namespace easy2d diff --git a/core/utils/Transcoder.cpp b/core/utils/Transcoder.cpp index 3a1ea09f..62a7095c 100644 --- a/core/utils/Transcoder.cpp +++ b/core/utils/Transcoder.cpp @@ -19,7 +19,7 @@ // THE SOFTWARE. #include "Transcoder.h" -#include "../base/base.h" +#include "../base/base.hpp" #include "../base/modules.h" #include "../base/logs.h" #include diff --git a/project/vs2013/Easy2D.vcxproj b/project/vs2013/Easy2D.vcxproj index c607b9cc..9a17c0ab 100644 --- a/project/vs2013/Easy2D.vcxproj +++ b/project/vs2013/Easy2D.vcxproj @@ -25,8 +25,8 @@ - - + + @@ -34,8 +34,8 @@ - - + + diff --git a/project/vs2013/Easy2D.vcxproj.filters b/project/vs2013/Easy2D.vcxproj.filters index e2834b4e..02fd62bd 100644 --- a/project/vs2013/Easy2D.vcxproj.filters +++ b/project/vs2013/Easy2D.vcxproj.filters @@ -14,12 +14,6 @@ base - - base - - - base - base @@ -134,9 +128,6 @@ base - - base - base @@ -155,7 +146,16 @@ base - + + base\intrusive + + + base\intrusive + + + base + + base @@ -172,6 +172,9 @@ {07b6d541-4a1b-472a-aae0-daf9d082fe84} + + {0f508149-735a-43da-ab16-36cc1e9ab63a} + diff --git a/project/vs2015/Easy2D.vcxproj b/project/vs2015/Easy2D.vcxproj index f7a4b810..c08148a4 100644 --- a/project/vs2015/Easy2D.vcxproj +++ b/project/vs2015/Easy2D.vcxproj @@ -25,8 +25,8 @@ - - + + @@ -34,8 +34,8 @@ - - + + diff --git a/project/vs2015/Easy2D.vcxproj.filters b/project/vs2015/Easy2D.vcxproj.filters index e2834b4e..02fd62bd 100644 --- a/project/vs2015/Easy2D.vcxproj.filters +++ b/project/vs2015/Easy2D.vcxproj.filters @@ -14,12 +14,6 @@ base - - base - - - base - base @@ -134,9 +128,6 @@ base - - base - base @@ -155,7 +146,16 @@ base - + + base\intrusive + + + base\intrusive + + + base + + base @@ -172,6 +172,9 @@ {07b6d541-4a1b-472a-aae0-daf9d082fe84} + + {0f508149-735a-43da-ab16-36cc1e9ab63a} + diff --git a/project/vs2017/Easy2D.vcxproj b/project/vs2017/Easy2D.vcxproj index 7ea6da5d..e6b5edb5 100644 --- a/project/vs2017/Easy2D.vcxproj +++ b/project/vs2017/Easy2D.vcxproj @@ -25,8 +25,8 @@ - - + + @@ -34,8 +34,8 @@ - - + + @@ -201,7 +201,7 @@ Disabled WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) false - None + EditAndContinue false true diff --git a/project/vs2017/Easy2D.vcxproj.filters b/project/vs2017/Easy2D.vcxproj.filters index e2834b4e..02fd62bd 100644 --- a/project/vs2017/Easy2D.vcxproj.filters +++ b/project/vs2017/Easy2D.vcxproj.filters @@ -14,12 +14,6 @@ base - - base - - - base - base @@ -134,9 +128,6 @@ base - - base - base @@ -155,7 +146,16 @@ base - + + base\intrusive + + + base\intrusive + + + base + + base @@ -172,6 +172,9 @@ {07b6d541-4a1b-472a-aae0-daf9d082fe84} + + {0f508149-735a-43da-ab16-36cc1e9ab63a} +