初始提交: UE5.3项目基础框架

This commit is contained in:
2025-10-14 11:14:54 +08:00
commit 721d9fd98e
5334 changed files with 316782 additions and 0 deletions

View File

@ -0,0 +1,27 @@
#pragma once
#include "QueuedScheduler.h"
#include "TaskScheduler.h"
#include "cesium-async++.h"
namespace CesiumAsync {
class ITaskProcessor;
namespace CesiumImpl {
// Begin omitting doxygen warnings for Impl namespace
//! @cond Doxygen_Suppress
class AsyncSystemSchedulers {
public:
AsyncSystemSchedulers(const std::shared_ptr<ITaskProcessor>& pTaskProcessor)
: mainThread(), workerThread(pTaskProcessor) {}
QueuedScheduler mainThread;
TaskScheduler workerThread;
};
//! @endcond
// End omitting doxygen warnings for Impl namespace
} // namespace CesiumImpl
} // namespace CesiumAsync

View File

@ -0,0 +1,76 @@
#pragma once
#include "unwrapFuture.h"
namespace CesiumAsync {
namespace CesiumImpl {
// Begin omitting doxgen warnings for Impl namespace
//! @cond Doxygen_Suppress
template <
typename Func,
typename T,
typename Scheduler,
typename TaskParameter = async::task<T>&&>
struct CatchFunction {
Scheduler& scheduler;
Func f;
async::task<T> operator()(TaskParameter t) {
try {
return async::make_task(t.get());
} catch (...) {
// Make an exception_ptr task, then scheduler to a wrapper around f that
// throws it, catches it, and calls f with a reference to it.
auto ptrToException = [f = std::move(f)](std::exception_ptr&& e) mutable {
try {
std::rethrow_exception(e);
} catch (std::exception& e) {
return f(std::move(e));
} catch (...) {
return f(std::runtime_error("Unknown exception"));
}
};
return async::make_task(std::current_exception())
.then(
scheduler,
unwrapFuture<decltype(ptrToException), std::exception_ptr>(
std::move(ptrToException)));
}
}
};
template <typename Func, typename Scheduler, typename TaskParameter>
struct CatchFunction<Func, void, Scheduler, TaskParameter> {
Scheduler& scheduler;
Func f;
async::task<void> operator()(TaskParameter t) {
try {
t.get();
return async::make_task();
} catch (...) {
// Make an exception_ptr task, then scheduler to a wrapper around f that
// throws it, catches it, and calls f with a reference to it.
auto ptrToException = [f = std::move(f)](std::exception_ptr&& e) mutable {
try {
std::rethrow_exception(e);
} catch (std::exception& e) {
return f(std::move(e));
} catch (...) {
return f(std::runtime_error("Unknown exception"));
}
};
return async::make_task(std::current_exception())
.then(
scheduler,
unwrapFuture<decltype(ptrToException), std::exception_ptr>(
std::move(ptrToException)));
}
}
};
//! @endcond
// End omitting doxgen warnings for Impl namespace
} // namespace CesiumImpl
} // namespace CesiumAsync

View File

@ -0,0 +1,25 @@
#pragma once
#include "ContinuationReturnType.h"
#include "RemoveFuture.h"
namespace CesiumAsync {
template <typename T> class Future;
namespace CesiumImpl {
// Begin omitting doxgen warnings for Impl namespace
//! @cond Doxygen_Suppress
template <typename Func, typename T> struct ContinuationFutureType {
using type = Future<typename RemoveFuture<
typename ContinuationReturnType<Func, T>::type>::type>;
};
template <typename Func, typename T>
using ContinuationFutureType_t = typename ContinuationFutureType<Func, T>::type;
//! @endcond
// End omitting doxgen warnings for Impl namespace
} // namespace CesiumImpl
} // namespace CesiumAsync

View File

@ -0,0 +1,21 @@
#pragma once
#include <type_traits>
namespace CesiumAsync {
namespace CesiumImpl {
// Begin omitting doxgen warnings for Impl namespace
//! @cond Doxygen_Suppress
template <typename Func, typename T> struct ContinuationReturnType {
using type = typename std::invoke_result<Func, T>::type;
};
template <typename Func> struct ContinuationReturnType<Func, void> {
using type = typename std::invoke_result<Func>::type;
};
//! @endcond
// End omitting doxgen warnings for Impl namespace
} // namespace CesiumImpl
} // namespace CesiumAsync

View File

@ -0,0 +1,97 @@
#pragma once
#include "cesium-async++.h"
#include <CesiumUtility/Assert.h>
#include <spdlog/spdlog.h>
namespace CesiumAsync {
// Begin omitting doxygen warnings for Impl namespace
//! @cond Doxygen_Suppress
namespace CesiumImpl {
template <typename TScheduler> class ImmediateScheduler {
public:
explicit ImmediateScheduler(TScheduler* pScheduler) noexcept
: _pScheduler(pScheduler) {}
void schedule(async::task_run_handle t) {
// Are we already in a suitable thread?
std::vector<TScheduler*>& inSuitable =
ImmediateScheduler<TScheduler>::getSchedulersCurrentlyDispatching();
if (std::find(inSuitable.begin(), inSuitable.end(), this->_pScheduler) !=
inSuitable.end()) {
// Yes, run this task directly.
t.run();
} else {
// No, schedule this task with the deferred scheduler.
this->_pScheduler->schedule(std::move(t));
}
}
class SchedulerScope {
public:
SchedulerScope(TScheduler* pScheduler = nullptr) : _pScheduler(pScheduler) {
if (this->_pScheduler) {
std::vector<TScheduler*>& inSuitable =
ImmediateScheduler<TScheduler>::getSchedulersCurrentlyDispatching();
inSuitable.push_back(this->_pScheduler);
}
}
~SchedulerScope() noexcept { this->reset(); }
SchedulerScope(SchedulerScope&& rhs) noexcept
: _pScheduler(rhs._pScheduler) {
rhs._pScheduler = nullptr;
}
SchedulerScope& operator=(SchedulerScope&& rhs) noexcept {
std::swap(this->_pScheduler, rhs._pScheduler);
return *this;
}
void reset() noexcept {
if (this->_pScheduler) {
std::vector<TScheduler*>& inSuitable =
ImmediateScheduler<TScheduler>::getSchedulersCurrentlyDispatching();
CESIUM_ASSERT(!inSuitable.empty());
CESIUM_ASSERT(inSuitable.back() == this->_pScheduler);
inSuitable.pop_back();
this->_pScheduler = nullptr;
}
}
SchedulerScope(const SchedulerScope&) = delete;
SchedulerScope& operator=(const SchedulerScope&) = delete;
private:
TScheduler* _pScheduler;
};
SchedulerScope scope() { return SchedulerScope(this->_pScheduler); }
private:
TScheduler* _pScheduler;
// If a TScheduler instance is found in this thread-local vector, then the
// current thread has been dispatched by this scheduler and therefore we can
// dispatch immediately.
static std::vector<TScheduler*>&
getSchedulersCurrentlyDispatching() noexcept {
// We're using a static local here rather than a static field because, on
// at least some Linux systems (mine), with Clang 12, in a Debug build, a
// thread_local static field causes a SEGFAULT on access.
// I don't understand why (despite hours trying), but making it a static
// local instead solves the problem and is arguably cleaner, anyway.
static thread_local std::vector<TScheduler*> schedulersCurrentlyDispatching;
return schedulersCurrentlyDispatching;
}
};
//! @endcond
// End omitting doxygen warnings for Impl namespace
} // namespace CesiumImpl
} // namespace CesiumAsync

View File

@ -0,0 +1,95 @@
#pragma once
#include "ImmediateScheduler.h"
#include "cesium-async++.h"
#include <atomic>
namespace CesiumAsync {
// Begin omitting doxygen warnings for Impl namespace
//! @cond Doxygen_Suppress
namespace CesiumImpl {
class QueuedScheduler {
public:
QueuedScheduler();
~QueuedScheduler();
void schedule(async::task_run_handle t);
void dispatchQueuedContinuations();
bool dispatchZeroOrOneContinuation();
template <typename T> T dispatchUntilTaskCompletes(async::task<T>&& task) {
// Set up a continuation to unblock the blocking dispatch when this task
// completes.
//
// We use the `isDone` flag as the loop termination condition to
// avoid a race condition that can lead to a deadlock. If we used
// `unblockTask.ready()` as the termination condition instead, then it's
// possible for events to happen as follows:
//
// 1. The original `task` completes in a worker thread and the `unblockTask`
// continuation is invoked immediately in the same thread.
// 2. The unblockTask continuation calls `unblock`, which terminates the
// `wait` on the condition variable in the main thread.
// 3. The main thread resumes and the while loop in this function spins back
// around and evaluates `unblockTask.ready()`. This returns false because
// the unblockTask continuation has not actually finished running in the
// worker thread yet. The main thread starts waiting on the condition
// variable again.
// 4. The `unblockTask` continuation finally finishes, making
// `unblockTask.ready()` return true, but it's too late. The main thread is
// already waiting on the condition variable.
//
// By setting the atomic `isDone` flag before calling `unblock`, we ensure
// that the loop termination condition is satisfied before the main thread
// is awoken, avoiding the potential deadlock.
std::atomic<bool> isDone = false;
async::task<T> unblockTask = task.then(
async::inline_scheduler(),
[this, &isDone](async::task<T>&& task) {
isDone = true;
this->unblock();
return task.get();
});
while (!isDone) {
this->dispatchInternal(true);
}
return std::move(unblockTask).get();
}
template <typename T>
T dispatchUntilTaskCompletes(const async::shared_task<T>& task) {
// Set up a continuation to unblock the blocking dispatch when this task
// completes. This case is simpler than the one above because a SharedFuture
// supports multiple continuations. We can use readiness of the _original_
// task to terminate the loop while unblocking in a separate continuation
// guaranteed to run only after that termination condition is satisfied.
async::task<void> unblockTask = task.then(
async::inline_scheduler(),
[this](const async::shared_task<T>&) { this->unblock(); });
while (!task.ready()) {
this->dispatchInternal(true);
}
return task.get();
}
ImmediateScheduler<QueuedScheduler> immediate{this};
private:
bool dispatchInternal(bool blockIfNoTasks);
void unblock();
struct Impl;
std::unique_ptr<Impl> _pImpl;
};
//! @endcond
// End omitting doxygen warnings for Impl namespace
} // namespace CesiumImpl
} // namespace CesiumAsync

View File

@ -0,0 +1,45 @@
#pragma once
#include "cesium-async++.h"
namespace CesiumAsync {
template <class T> class Future;
template <class T> class SharedFuture;
namespace CesiumImpl {
// Begin omitting doxgen warnings for Impl namespace
//! @cond Doxygen_Suppress
template <typename T> struct RemoveFuture {
typedef T type;
};
template <typename T> struct RemoveFuture<Future<T>> {
typedef T type;
};
template <typename T> struct RemoveFuture<const Future<T>> {
typedef T type;
};
template <typename T> struct RemoveFuture<SharedFuture<T>> {
typedef T type;
};
template <typename T> struct RemoveFuture<const SharedFuture<T>> {
typedef T type;
};
template <typename T> struct RemoveFuture<async::task<T>> {
typedef T type;
};
template <typename T> struct RemoveFuture<const async::task<T>> {
typedef T type;
};
template <typename T> struct RemoveFuture<async::shared_task<T>> {
typedef T type;
};
template <typename T> struct RemoveFuture<const async::shared_task<T>> {
typedef T type;
};
//! @endcond
// End omitting doxgen warnings for Impl namespace
} // namespace CesiumImpl
} // namespace CesiumAsync

View File

@ -0,0 +1,27 @@
#pragma once
#include "../ITaskProcessor.h"
#include "ImmediateScheduler.h"
#include <memory>
namespace CesiumAsync {
namespace CesiumImpl {
// Begin omitting doxygen warnings for Impl namespace
//! @cond Doxygen_Suppress
class TaskScheduler {
public:
TaskScheduler(const std::shared_ptr<ITaskProcessor>& pTaskProcessor);
void schedule(async::task_run_handle t);
ImmediateScheduler<TaskScheduler> immediate{this};
private:
std::shared_ptr<ITaskProcessor> _pTaskProcessor;
};
//! @endcond
// End omitting doxygen warnings for Impl namespace
} // namespace CesiumImpl
} // namespace CesiumAsync

View File

@ -0,0 +1,124 @@
#pragma once
#include "unwrapFuture.h"
#include <CesiumUtility/Tracing.h>
namespace CesiumAsync {
namespace CesiumImpl {
// Begin omitting doxgen warnings for Impl namespace
//! @cond Doxygen_Suppress
template <typename T> struct WithTracing {
template <typename Func>
static auto
begin([[maybe_unused]] const char* tracingName, [[maybe_unused]] Func&& f) {
#if CESIUM_TRACING_ENABLED
return
[tracingName, CESIUM_TRACE_LAMBDA_CAPTURE_TRACK()](T&& result) mutable {
CESIUM_TRACE_USE_CAPTURED_TRACK();
if (tracingName) {
CESIUM_TRACE_BEGIN_IN_TRACK(tracingName);
}
return std::move(result);
};
#else
return CesiumImpl::unwrapFuture<Func, T>(std::forward<Func>(f));
#endif
}
template <typename Func>
static auto end([[maybe_unused]] const char* tracingName, Func&& f) {
#if CESIUM_TRACING_ENABLED
return [tracingName,
f = CesiumImpl::unwrapFuture<Func, T>(std::forward<Func>(f)),
CESIUM_TRACE_LAMBDA_CAPTURE_TRACK()](T&& result) mutable {
CESIUM_TRACE_USE_CAPTURED_TRACK();
if (tracingName) {
CESIUM_TRACE_END_IN_TRACK(tracingName);
}
return f(std::move(result));
};
#else
return CesiumImpl::unwrapFuture<Func, T>(std::forward<Func>(f));
#endif
}
};
template <typename T> struct WithTracingShared {
template <typename Func>
static auto
begin([[maybe_unused]] const char* tracingName, [[maybe_unused]] Func&& f) {
#if CESIUM_TRACING_ENABLED
return [tracingName,
CESIUM_TRACE_LAMBDA_CAPTURE_TRACK()](const T& result) mutable {
CESIUM_TRACE_USE_CAPTURED_TRACK();
if (tracingName) {
CESIUM_TRACE_BEGIN_IN_TRACK(tracingName);
}
return result;
};
#else
return CesiumImpl::unwrapSharedFuture<Func, T>(std::forward<Func>(f));
#endif
}
template <typename Func>
static auto end([[maybe_unused]] const char* tracingName, Func&& f) {
#if CESIUM_TRACING_ENABLED
return [tracingName,
f = CesiumImpl::unwrapSharedFuture<Func, T>(std::forward<Func>(f)),
CESIUM_TRACE_LAMBDA_CAPTURE_TRACK()](const T& result) mutable {
CESIUM_TRACE_USE_CAPTURED_TRACK();
if (tracingName) {
CESIUM_TRACE_END_IN_TRACK(tracingName);
}
return f(result);
};
#else
return CesiumImpl::unwrapSharedFuture<Func, T>(std::forward<Func>(f));
#endif
}
};
template <> struct WithTracing<void> {
template <typename Func>
static auto
begin([[maybe_unused]] const char* tracingName, [[maybe_unused]] Func&& f) {
#if CESIUM_TRACING_ENABLED
return [tracingName, CESIUM_TRACE_LAMBDA_CAPTURE_TRACK()]() mutable {
CESIUM_TRACE_USE_CAPTURED_TRACK();
if (tracingName) {
CESIUM_TRACE_END_IN_TRACK(tracingName);
}
};
#else
return CesiumImpl::unwrapFuture<Func>(std::forward<Func>(f));
#endif
}
template <typename Func>
static auto end([[maybe_unused]] const char* tracingName, Func&& f) {
#if CESIUM_TRACING_ENABLED
return [tracingName,
f = CesiumImpl::unwrapFuture<Func>(std::forward<Func>(f)),
CESIUM_TRACE_LAMBDA_CAPTURE_TRACK()]() mutable {
CESIUM_TRACE_USE_CAPTURED_TRACK();
if (tracingName) {
CESIUM_TRACE_END_IN_TRACK(tracingName);
}
return f();
};
#else
return CesiumImpl::unwrapFuture<Func>(std::forward<Func>(f));
#endif
}
};
// With a void Future, shared and non-shared are identical.
template <> struct WithTracingShared<void> : public WithTracing<void> {};
//! @endcond
// End omitting doxgen warnings for Impl namespace
} // namespace CesiumImpl
} // namespace CesiumAsync

View File

@ -0,0 +1,16 @@
#pragma once
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4458 4324 4702)
#endif
#ifndef _MSC_VER
#pragma GCC diagnostic ignored "-Wshadow"
#endif
#include <async++.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif

View File

@ -0,0 +1,77 @@
#pragma once
#include "ContinuationFutureType.h"
#include "ContinuationReturnType.h"
namespace CesiumAsync {
namespace CesiumImpl {
// Begin omitting doxgen warnings for Impl namespace
//! @cond Doxygen_Suppress
struct IdentityUnwrapper {
template <typename Func> static Func unwrap(Func&& f) {
return std::forward<Func>(f);
}
template <typename Func> static Func unwrapShared(Func&& f) {
return std::forward<Func>(f);
}
};
template <typename T> struct ParameterizedTaskUnwrapper {
template <typename Func> static auto unwrap(Func&& f) {
return [f = std::forward<Func>(f)](T&& t) mutable {
return f(std::move(t))._task;
};
}
template <typename Func> static auto unwrapShared(Func&& f) {
return
[f = std::forward<Func>(f)](const T& t) mutable { return f(t)._task; };
}
};
struct TaskUnwrapper {
template <typename Func> static auto unwrap(Func&& f) {
return [f = std::forward<Func>(f)]() mutable { return f()._task; };
}
};
template <typename Func, typename T> auto unwrapFuture(Func&& f) {
return std::conditional<
std::is_same<
typename ContinuationReturnType<Func, T>::type,
typename RemoveFuture<
typename ContinuationFutureType<Func, T>::type>::type>::value,
IdentityUnwrapper,
ParameterizedTaskUnwrapper<T>>::type::unwrap(std::forward<Func>(f));
}
template <typename Func, typename T> auto unwrapSharedFuture(Func&& f) {
return std::conditional<
std::is_same<
typename ContinuationReturnType<Func, T>::type,
typename RemoveFuture<
typename ContinuationFutureType<Func, T>::type>::type>::value,
IdentityUnwrapper,
ParameterizedTaskUnwrapper<T>>::type::unwrapShared(std::forward<Func>(f));
}
template <typename Func> auto unwrapFuture(Func&& f) {
return std::conditional<
std::is_same<
typename ContinuationReturnType<Func, void>::type,
typename RemoveFuture<
typename ContinuationFutureType<Func, void>::type>::type>::value,
IdentityUnwrapper,
TaskUnwrapper>::type::unwrap(std::forward<Func>(f));
}
template <typename Func> auto unwrapSharedFuture(Func&& f) {
return unwrapFuture(std::forward<Func>(f));
}
//! @endcond
// End omitting doxgen warnings for Impl namespace
} // namespace CesiumImpl
} // namespace CesiumAsync