diff --git a/.clang-format b/.clang-format index 515fe06..aecc7e3 100644 Binary files a/.clang-format and b/.clang-format differ diff --git a/.clangd b/.clangd index 92534a6..8e3ed0a 100644 Binary files a/.clangd and b/.clangd differ diff --git a/CMakeLists.txt b/CMakeLists.txt index c334a80..60bd3ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,10 @@ set(CMAKE_WIN32_EXECUTABLE true) if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") add_compile_options(${PROJECT_NAME} -Wno-microsoft-string-literal-from-predefined) endif () -#add_compile_options(${PROJECT_NAME} /utf-8) +if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + add_compile_options(/source-charset:utf-8) + add_compile_options(/execution-charset:utf-8) +endif () include(CTest) enable_testing() @@ -44,3 +47,4 @@ add_executable(${PROJECT_NAME} set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) include(CPack) + diff --git a/Chars.h b/Chars.h index 3574f16..1a15acc 100644 Binary files a/Chars.h and b/Chars.h differ diff --git a/Game.cpp b/Game.cpp index a9934ed..27c0215 100644 Binary files a/Game.cpp and b/Game.cpp differ diff --git a/Game.h b/Game.h index 7e00c90..9c8533d 100644 Binary files a/Game.h and b/Game.h differ diff --git a/Hud.h b/Hud.h index 493a557..7791094 100644 Binary files a/Hud.h and b/Hud.h differ diff --git a/IText.cpp b/IText.cpp index fc9f53e..e69cb48 100644 Binary files a/IText.cpp and b/IText.cpp differ diff --git a/IText.h b/IText.h index 6f292a4..b3543ad 100644 Binary files a/IText.h and b/IText.h differ diff --git a/InteractManager.cpp b/InteractManager.cpp index 02d94c1..c8b27b2 100644 Binary files a/InteractManager.cpp and b/InteractManager.cpp differ diff --git a/InteractManager.h b/InteractManager.h index dc9dce0..81cc607 100644 Binary files a/InteractManager.h and b/InteractManager.h differ diff --git a/Renderer.cpp b/Renderer.cpp index b00bc05..3b49ecd 100644 Binary files a/Renderer.cpp and b/Renderer.cpp differ diff --git a/Renderer.h b/Renderer.h index cef4ab3..3cfdfba 100644 Binary files a/Renderer.h and b/Renderer.h differ diff --git a/Task.h b/Task.h new file mode 100644 index 0000000..a31825d --- /dev/null +++ b/Task.h @@ -0,0 +1,43 @@ +// +// Created by EmsiaetKadosh on 25-3-4. +// +#pragma once + +#include "utils.h" + +class Task; +class TaskScheduler; + +class Task final : public AnywhereEditable { + friend class TaskScheduler; + +public: + Function func; + + explicit Task(const Function& func) : func(func) {} + explicit Task(Function&& func) : func(std::move(func)) {} + void schedulePop(const bool pop) noexcept { reserved[0] = pop; } + bool scheduledPop() const noexcept { return reserved[0]; } + + int pop() noexcept override { + schedulePop(true); + Success(); + } +}; + +class TaskScheduler { +public: + AnywhereEditableList tasks; + + void runAll() { + for (Task& task : tasks) { + task.func(task); + if (task.scheduledPop()) tasks.pop(&task); + } + } + + void pushCopy(Task& task) { tasks.pushCopy(&task); } + /* 必须是new Task,交付托管 */ + void pushNewed(Task* task) { tasks.pushNewed(task); } + void pushThis(Task& task) { tasks.pushThis(&task); } +}; diff --git a/TestCode.h b/TestCode.h index f4211eb..06a1968 100644 Binary files a/TestCode.h and b/TestCode.h differ diff --git a/Window.cpp b/Window.cpp index b66e3e9..76fd8c2 100644 Binary files a/Window.cpp and b/Window.cpp differ diff --git a/Window.h b/Window.h index 09d8e24..da7920a 100644 Binary files a/Window.h and b/Window.h differ diff --git a/def.cpp b/def.cpp index f64fd5c..67eb6c8 100644 Binary files a/def.cpp and b/def.cpp differ diff --git a/def.h b/def.h index c223548..34c97cc 100644 Binary files a/def.h and b/def.h differ diff --git a/exception.cpp b/exception.cpp index 240c22b..c23b1a3 100644 Binary files a/exception.cpp and b/exception.cpp differ diff --git a/exception.h b/exception.h index 49926f3..2952734 100644 Binary files a/exception.h and b/exception.h differ diff --git a/gc.cpp b/gc.cpp new file mode 100644 index 0000000..95f84a6 --- /dev/null +++ b/gc.cpp @@ -0,0 +1,5 @@ +// +// Created by EmsiaetKadosh on 25-3-6. +// + +#include "gc.h" diff --git a/gc.h b/gc.h new file mode 100644 index 0000000..edacaa4 --- /dev/null +++ b/gc.h @@ -0,0 +1,142 @@ +// +// Created by EmsiaetKadosh on 25-3-6. +// + +#pragma once + +#include "def.h" + +struct IGarbage; +template +class Garbage; +class GarbageCollector; + +struct IGarbage { +private: + friend class GarbageCollector; + IGarbage* next = nullptr; + +protected: + void* ptr; + explicit IGarbage(void* ptr) : ptr(ptr) {} + virtual ~IGarbage() = default; + virtual void collect() = 0; + virtual void deleteThis() = 0; +}; + +template +class Garbage final : public IGarbage { + friend class GarbageCollector; + +public: + explicit Garbage(T* ptr) : IGarbage(ptr) {} + void collect() override { delete static_cast(ptr); } + +protected: + void deleteThis() override { delete this; } +}; + +class GarbageCollector { + IGarbage* submitted = nullptr; + IGarbage* submittedEnd = nullptr; + IGarbage* packed = nullptr; + IGarbage* packedEnd = nullptr; + IGarbage* processing = nullptr; + +public: + GarbageCollector() = default; + GarbageCollector(const GarbageCollector&) = delete; + GarbageCollector(GarbageCollector&&) = delete; + GarbageCollector& operator=(const GarbageCollector&) = delete; + GarbageCollector& operator=(GarbageCollector&&) = delete; + + ~GarbageCollector() { + IGarbage* iter = processing; + while (processing) { + iter = processing->next; + processing->collect(); + processing->deleteThis(); + processing = iter; + } + while (packed) { + iter = packed->next; + packed->collect(); + packed->deleteThis(); + packed = iter; + } + while (submitted) { + iter = submitted->next; + submitted->collect(); + submitted->deleteThis(); + submitted = iter; + } + submittedEnd = nullptr; + } + + /** 只能在gameThread调用 */ + template + void submit(T* ptr) noexcept(false) { + IGarbage* garbage = new Garbage(ptr); + if (IGarbage* end = submittedEnd) { // 后续添加,可能存在线程竞争 + while (end->next) end = end->next; // 理论上不会进入循环,但防止万一 + end->next = garbage; + if (submitted) submittedEnd = garbage; // 参考pack(),submitted会被先置空 + std::atomic_thread_fence(std::memory_order_acquire); + if (!submitted) submittedEnd = nullptr; // 防止submittedEnd = garbage在pack()中置空后进行。此函数是同步的,所以可以这样操作。 + } + else { // 添加首个,一定不会有线程竞争;或先前的已经pack + submitted = garbage; + submittedEnd = garbage; + } + } + + /** 只能在renderThread调用 */ + void pack() { + if (!submitted) return; // 提交链为空,不进行后续操作,防止竞争 + std::atomic_thread_fence(std::memory_order_acquire); + IGarbage* submit = submitted; + IGarbage* submitEnd = submittedEnd; + submitted = nullptr; // 先把这个置为nullptr + std::atomic_thread_fence(std::memory_order_acquire); + submittedEnd = nullptr; + if (IGarbage* end = packedEnd) { + while (end->next) end = end->next; // 以防万一 + end->next = submit; + if (packed) packedEnd = submitEnd; + std::atomic_thread_fence(std::memory_order_acquire); + if (!packed) packedEnd = nullptr; + } + else { + packed = submit; + packedEnd = submitEnd; + } + while (packedEnd->next) packedEnd = packedEnd->next; + } + + /** 只能在gameThread调用 */ + void collect() { + IGarbage* next = processing; + while (processing) { + next = processing->next; + processing->next = nullptr; + processing->collect(); + processing->deleteThis(); + processing = next; + } + if (!packed) return; + // 搬运packed且搬运期间的packed链必须必须完全固定 + // 保证运行顺序 + processing = packed; + packed = nullptr; + std::atomic_thread_fence(std::memory_order_acquire); + packedEnd = nullptr; + std::atomic_thread_fence(std::memory_order_acquire); + while (processing) { + next = processing->next; + processing->next = nullptr; + processing->collect(); + processing->deleteThis(); + processing = next; + } + } +}; diff --git a/includes.h b/includes.h index afb8b7c..307b69e 100644 Binary files a/includes.h and b/includes.h differ diff --git a/main.cpp b/main.cpp index 8e8696c..9346221 100644 Binary files a/main.cpp and b/main.cpp differ diff --git a/utils.h b/utils.h new file mode 100644 index 0000000..562f9d6 --- /dev/null +++ b/utils.h @@ -0,0 +1,210 @@ +// +// Created by EmsiaetKadosh on 25-3-4. +// +#pragma once + +template +class AnywhereEditable; +template +class AnywhereEditableList; +template +class AnywhereIterator; +class AnywhereIteratorEnd; + +/** + * 此处无法进行代码编译层面的直接约束 + * @tparam T 满足T extends AnywhereEditable + * @tparam L 满足L extends AnywhereEditableList + */ +template +class AnywhereEditable { +public: + using Lst = std::conditional_t, AnywhereEditableList, L>; + +private: + friend class AnywhereIterator; + friend class AnywhereEditableList; + friend class AnywhereIteratorEnd; + friend L; + AnywhereEditable* prev = nullptr; + AnywhereEditable* next = nullptr; + AnywhereEditableList* list = nullptr; // 指示自身属于某个列表 +protected: + bool managedByList = false; // 指示是否在列表内管理内存,而非列表外管理内存 + byte reserved[7]{}; // reserved[0]: Task::schedulePop + +public: + AnywhereEditable() = default; + AnywhereEditable(const AnywhereEditable& other) {} + + AnywhereEditable(AnywhereEditable&& other) noexcept : prev(other->prev), next(other->next), list(other->list) { + other->prev = nullptr; + other->next = nullptr; + other->list = nullptr; + } + + virtual ~AnywhereEditable() { + if (list) { + managedByList = false; + auto lst = list; + list = nullptr; + lst->pop(static_cast(this)); + Logger.warn(L"~AnywhereEditable() : 析构时没有清除list,导致了析构时pop"); + } + } + + int pushCopy(AnywhereEditableList& list) noexcept; + int pushThis(AnywhereEditableList& list) noexcept; + virtual int pop() noexcept; + AnywhereEditableList* getContainer() const noexcept { return list; } +}; + +template +class AnywhereIterator { + friend class AnywhereIteratorEnd; + AnywhereEditable* current; + +public: + explicit AnywhereIterator(AnywhereEditable* current) : current(current) {} + AnywhereIterator(const AnywhereIterator& other) = default; + + T& operator*() noexcept(false) { + if (current->next) return static_cast(*current); + throw RuntimeException(L"AnywhereIterator::operator*() : next is null, end of list"); + } + + T* operator->() noexcept(false) { + if (current->next) return &static_cast(*current); + throw RuntimeException(L"AnywhereIterator::operator*() : next is null, end of list"); + } + + bool operator!=(const AnywhereIterator& other) const noexcept { return current != other.current; } + bool operator==(const AnywhereIterator& other) const noexcept { return current == other.current; } + bool operator!=(const AnywhereIteratorEnd& other) const noexcept; + bool operator==(const AnywhereIteratorEnd& other) const noexcept; + + AnywhereIterator& operator++() noexcept(false) { + if (current->next) current = current->next; + else throw InvalidOperationException(L"AnywhereIterator::operator++() : end of list"); + return *this; + } + + AnywhereIterator operator++(int) noexcept(false) { + if (current->next) { + AnywhereIterator ret = *this; + current = current->next; + return ret; + } + throw InvalidOperationException(L"AnywhereIterator::operator++() : end of list"); + } + + AnywhereIterator& operator--() noexcept(false) { + if (current->prev) current = current->prev; + else throw InvalidOperationException(L"AnywhereIterator::operator--() : begin of list"); + return *this; + } + + AnywhereIterator operator--(int) noexcept(false) { + if (current->prev) { + AnywhereIterator ret = *this; + current = current->prev; + return ret; + } + throw InvalidOperationException(L"AnywhereIterator::operator--() : begin of list"); + } +}; + +class AnywhereIteratorEnd { +public: + AnywhereIteratorEnd() {} + AnywhereIteratorEnd(const AnywhereIteratorEnd& other) = delete; + AnywhereIteratorEnd(AnywhereIteratorEnd&& other) = delete; + + template + bool operator!=(const AnywhereIterator& other) const noexcept { return other.current && other.current->next; } + + template + bool operator==(const AnywhereIterator& other) const noexcept { return !operator!=(other); } +}; + +template +class AnywhereEditableList { +protected: + AnywhereEditable head; + AnywhereEditable tail; + +public: + AnywhereEditableList() { + head.next = &tail; + tail.prev = &head; + } + + virtual ~AnywhereEditableList() { for (AnywhereIterator it = begin(); it != end(); ++it) {} } + + int pushCopy(T* value) noexcept; + int pushThis(T* value) noexcept; + int pushNewed(T* value) noexcept; + virtual int pop(T* value) noexcept; + AnywhereIterator begin() noexcept { return AnywhereIterator(head.next); } + AnywhereIteratorEnd end() noexcept { return AnywhereIteratorEnd(); } + AnywhereIterator begin() const noexcept { return AnywhereIterator(head.next); } + AnywhereIteratorEnd end() const noexcept { return AnywhereIteratorEnd(); } + AnywhereEditable* front() const noexcept { return head.next == &tail ? nullptr : head.next; } + AnywhereEditable* back() const noexcept { return tail.prev == &head ? nullptr : tail.prev; } +}; + +template +int AnywhereEditable::pushCopy(AnywhereEditableList& list) noexcept { return list.pushCopy(static_cast(this)); } + +template +int AnywhereEditable::pushThis(AnywhereEditableList& list) noexcept { return list.pushThis(static_cast(this)); } + +template +int AnywhereEditable::pop() noexcept { return list->pop(static_cast(this)); } + +template +bool AnywhereIterator::operator!=(const AnywhereIteratorEnd& other) const noexcept { return other != *this; } + +template +bool AnywhereIterator::operator==(const AnywhereIteratorEnd& other) const noexcept { return other == *this; } + +template +int AnywhereEditableList::pushCopy(T* value) noexcept { + T* nv = new T(*value); + return pushNewed(nv); +} + +template +int AnywhereEditableList::pushThis(T* value) noexcept { + if (value->list) { + Logger.error(L"AnywhereEditableList::pushThis() : value is already in a list"); + Failed(); + } + value->list = this; + tail.prev->next = value; + value->prev = tail.prev; + value->next = &tail; + tail.prev = value; + Success(); +} + +template +int AnywhereEditableList::pushNewed(T* value) noexcept { + const int ret = pushThis(value); + if (ret) delete value; + else value->managedByList = true; + return ret; +} + +template +int AnywhereEditableList::pop(T* value) noexcept { + if (value->list != this) { + Logger.error(L"AnywhereEditableList::pop() : value is not in this list"); + Failed(); + } + value->list = nullptr; + value->next->prev = value->prev; + value->prev->next = value->next; + if (value->managedByList) delete value; + Success(); +} diff --git a/xWindows.h b/xWindows.h index 1224074..4755984 100644 Binary files a/xWindows.h and b/xWindows.h differ