diff options
Diffstat (limited to 'src/server/database')
-rw-r--r-- | src/server/database/Database/QueryCallback.cpp | 154 | ||||
-rw-r--r-- | src/server/database/Database/QueryCallback.h | 14 |
2 files changed, 23 insertions, 145 deletions
diff --git a/src/server/database/Database/QueryCallback.cpp b/src/server/database/Database/QueryCallback.cpp index f921eaa1e4d..528605da708 100644 --- a/src/server/database/Database/QueryCallback.cpp +++ b/src/server/database/Database/QueryCallback.cpp @@ -16,172 +16,69 @@ */ #include "QueryCallback.h" +#include "Duration.h" #include "Errors.h" -template<typename T, typename... Args> -inline void Construct(T& t, Args&&... args) +QueryCallback::QueryCallback(std::future<QueryResult>&& result) : _query(std::move(result)) { - new (&t) T(std::forward<Args>(args)...); } -template<typename T> -inline void Destroy(T& t) +QueryCallback::QueryCallback(std::future<PreparedQueryResult>&& result) : _query(std::move(result)) { - t.~T(); } -template<typename T> -inline void ConstructActiveMember(T* obj) +QueryCallback::QueryCallback(QueryCallback&& right) noexcept : _query(std::move(right._query)), _callbacks(std::move(right._callbacks)) { - if (!obj->_isPrepared) - Construct(obj->_string); - else - Construct(obj->_prepared); -} - -template<typename T> -inline void DestroyActiveMember(T* obj) -{ - if (!obj->_isPrepared) - Destroy(obj->_string); - else - Destroy(obj->_prepared); -} - -template<typename T> -inline void MoveFrom(T* to, T&& from) -{ - ASSERT(to->_isPrepared == from._isPrepared); - - if (!to->_isPrepared) - to->_string = std::move(from._string); - else - to->_prepared = std::move(from._prepared); -} - -struct QueryCallback::QueryCallbackData -{ -public: - friend class QueryCallback; - - QueryCallbackData(std::function<void(QueryCallback&, QueryResult)>&& callback) : _string(std::move(callback)), _isPrepared(false) { } - QueryCallbackData(std::function<void(QueryCallback&, PreparedQueryResult)>&& callback) : _prepared(std::move(callback)), _isPrepared(true) { } - QueryCallbackData(QueryCallbackData&& right) noexcept - { - _isPrepared = right._isPrepared; - ConstructActiveMember(this); - MoveFrom(this, std::move(right)); - } - QueryCallbackData& operator=(QueryCallbackData&& right) noexcept - { - if (this != &right) - { - if (_isPrepared != right._isPrepared) - { - DestroyActiveMember(this); - _isPrepared = right._isPrepared; - ConstructActiveMember(this); - } - MoveFrom(this, std::move(right)); - } - return *this; - } - ~QueryCallbackData() { DestroyActiveMember(this); } - -private: - QueryCallbackData(QueryCallbackData const&) = delete; - QueryCallbackData& operator=(QueryCallbackData const&) = delete; - - template<typename T> friend void ConstructActiveMember(T* obj); - template<typename T> friend void DestroyActiveMember(T* obj); - template<typename T> friend void MoveFrom(T* to, T&& from); - - union - { - std::function<void(QueryCallback&, QueryResult)> _string; - std::function<void(QueryCallback&, PreparedQueryResult)> _prepared; - }; - bool _isPrepared; -}; - -// Not using initialization lists to work around segmentation faults when compiling with clang without precompiled headers -QueryCallback::QueryCallback(std::future<QueryResult>&& result) -{ - _isPrepared = false; - Construct(_string, std::move(result)); -} - -QueryCallback::QueryCallback(std::future<PreparedQueryResult>&& result) -{ - _isPrepared = true; - Construct(_prepared, std::move(result)); -} - -QueryCallback::QueryCallback(QueryCallback&& right) noexcept -{ - _isPrepared = right._isPrepared; - ConstructActiveMember(this); - MoveFrom(this, std::move(right)); - _callbacks = std::move(right._callbacks); } QueryCallback& QueryCallback::operator=(QueryCallback&& right) noexcept { if (this != &right) { - if (_isPrepared != right._isPrepared) - { - DestroyActiveMember(this); - _isPrepared = right._isPrepared; - ConstructActiveMember(this); - } - MoveFrom(this, std::move(right)); + _query = std::move(right._query); _callbacks = std::move(right._callbacks); } return *this; } -QueryCallback::~QueryCallback() -{ - DestroyActiveMember(this); -} +QueryCallback::~QueryCallback() = default; QueryCallback&& QueryCallback::WithCallback(std::function<void(QueryResult)>&& callback) { - return WithChainingCallback([callback](QueryCallback& /*this*/, QueryResult result) { callback(std::move(result)); }); + return WithChainingCallback([callback = std::move(callback)](QueryCallback& /*this*/, QueryResult result) { callback(std::move(result)); }); } QueryCallback&& QueryCallback::WithPreparedCallback(std::function<void(PreparedQueryResult)>&& callback) { - return WithChainingPreparedCallback([callback](QueryCallback& /*this*/, PreparedQueryResult result) { callback(std::move(result)); }); + return WithChainingPreparedCallback([callback = std::move(callback)](QueryCallback& /*this*/, PreparedQueryResult result) { callback(std::move(result)); }); } QueryCallback&& QueryCallback::WithChainingCallback(std::function<void(QueryCallback&, QueryResult)>&& callback) { - ASSERT(!_callbacks.empty() || !_isPrepared, "Attempted to set callback function for string query on a prepared async query"); + ASSERT(!_callbacks.empty() || std::holds_alternative<std::future<QueryResult>>(_query), "Attempted to set callback function for string query on a prepared async query"); _callbacks.emplace(std::move(callback)); return std::move(*this); } QueryCallback&& QueryCallback::WithChainingPreparedCallback(std::function<void(QueryCallback&, PreparedQueryResult)>&& callback) { - ASSERT(!_callbacks.empty() || _isPrepared, "Attempted to set callback function for prepared query on a string async query"); + ASSERT(!_callbacks.empty() || std::holds_alternative<std::future<PreparedQueryResult>>(_query), "Attempted to set callback function for prepared query on a string async query"); _callbacks.emplace(std::move(callback)); return std::move(*this); } void QueryCallback::SetNextQuery(QueryCallback&& next) { - MoveFrom(this, std::move(next)); + if (this != &next) + _query = std::move(next)._query; } bool QueryCallback::InvokeIfReady() { - QueryCallbackData& callback = _callbacks.front(); auto checkStateAndReturnCompletion = [this]() { _callbacks.pop(); - bool hasNext = !_isPrepared ? _string.valid() : _prepared.valid(); + bool hasNext = std::visit([](auto const& future) { return future.valid(); }, _query); if (_callbacks.empty()) { ASSERT(!hasNext); @@ -192,30 +89,19 @@ bool QueryCallback::InvokeIfReady() if (!hasNext) return true; - ASSERT(_isPrepared == _callbacks.front()._isPrepared); + ASSERT(_query.index() == _callbacks.front().index()); return false; }; - if (!_isPrepared) - { - if (_string.valid() && _string.wait_for(std::chrono::seconds(0)) == std::future_status::ready) - { - std::future<QueryResult> f(std::move(_string)); - std::function<void(QueryCallback&, QueryResult)> cb(std::move(callback._string)); - cb(*this, f.get()); - return checkStateAndReturnCompletion(); - } - } - else + return std::visit([&]<typename Result>(std::future<Result>&& future) { - if (_prepared.valid() && _prepared.wait_for(std::chrono::seconds(0)) == std::future_status::ready) + if (future.valid() && future.wait_for(0s) == std::future_status::ready) { - std::future<PreparedQueryResult> f(std::move(_prepared)); - std::function<void(QueryCallback&, PreparedQueryResult)> cb(std::move(callback._prepared)); + std::future<Result> f(std::move(future)); + std::function<void(QueryCallback&, Result)> cb(std::get<std::function<void(QueryCallback&, Result)>>(std::move(_callbacks.front()))); cb(*this, f.get()); return checkStateAndReturnCompletion(); } - } - - return false; + return false; + }, std::move(_query)); } diff --git a/src/server/database/Database/QueryCallback.h b/src/server/database/Database/QueryCallback.h index bb3cc64559d..72b4ca1202a 100644 --- a/src/server/database/Database/QueryCallback.h +++ b/src/server/database/Database/QueryCallback.h @@ -24,6 +24,7 @@ #include <future> #include <list> #include <queue> +#include <variant> class TC_DATABASE_API QueryCallback { @@ -50,18 +51,9 @@ private: QueryCallback(QueryCallback const& right) = delete; QueryCallback& operator=(QueryCallback const& right) = delete; - template<typename T> friend void ConstructActiveMember(T* obj); - template<typename T> friend void DestroyActiveMember(T* obj); - template<typename T> friend void MoveFrom(T* to, T&& from); + std::variant<std::future<QueryResult>, std::future<PreparedQueryResult>> _query; - union - { - std::future<QueryResult> _string; - std::future<PreparedQueryResult> _prepared; - }; - bool _isPrepared; - - struct QueryCallbackData; + using QueryCallbackData = std::variant<std::function<void(QueryCallback&, QueryResult)>, std::function<void(QueryCallback&, PreparedQueryResult)>>; std::queue<QueryCallbackData, std::list<QueryCallbackData>> _callbacks; }; |