-
Notifications
You must be signed in to change notification settings - Fork 934
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #864 from RuleOfThrees/multiasync
MultiAsync
- Loading branch information
Showing
16 changed files
with
774 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ add_library(cpr | |
async.cpp | ||
auth.cpp | ||
bearer.cpp | ||
callback.cpp | ||
cert_info.cpp | ||
cookies.cpp | ||
cprtypes.cpp | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
#include <cpr/callback.h> | ||
#include <curl/curl.h> | ||
#include <functional> | ||
|
||
namespace cpr { | ||
|
||
void CancellationCallback::SetProgressCallback(ProgressCallback& u_cb) { | ||
user_cb.emplace(std::reference_wrapper{u_cb}); | ||
} | ||
bool CancellationCallback::operator()(cpr_pf_arg_t dltotal, cpr_pf_arg_t dlnow, cpr_pf_arg_t ultotal, cpr_pf_arg_t ulnow) const { | ||
const bool cont_operation{!cancellation_state->load()}; | ||
return user_cb ? (cont_operation && (*user_cb)(dltotal, dlnow, ultotal, ulnow)) : cont_operation; | ||
} | ||
} // namespace cpr |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
#ifndef CPR_ASYNC_WRAPPER_H | ||
#define CPR_ASYNC_WRAPPER_H | ||
|
||
#include <atomic> | ||
#include <future> | ||
#include <memory> | ||
|
||
#include "cpr/response.h" | ||
|
||
namespace cpr { | ||
enum class [[nodiscard]] CancellationResult { failure, success, invalid_operation }; | ||
|
||
/** | ||
* A class template intended to wrap results of async operations (instances of std::future<T>) | ||
* and also provide extended capablilities relaed to these requests, for example cancellation. | ||
* | ||
* The RAII semantics are the same as std::future<T> - moveable, not copyable. | ||
*/ | ||
template <typename T, bool isCancellable = false> | ||
class AsyncWrapper { | ||
private: | ||
std::future<T> future; | ||
std::shared_ptr<std::atomic_bool> is_cancelled; | ||
|
||
public: | ||
// Constructors | ||
explicit AsyncWrapper(std::future<T>&& f) : future{std::move(f)} {} | ||
AsyncWrapper(std::future<T>&& f, std::shared_ptr<std::atomic_bool>&& cancelledState) : future{std::move(f)}, is_cancelled{std::move(cancelledState)} {} | ||
|
||
// Copy Semantics | ||
AsyncWrapper(const AsyncWrapper&) = delete; | ||
AsyncWrapper& operator=(const AsyncWrapper&) = delete; | ||
|
||
// Move Semantics | ||
AsyncWrapper(AsyncWrapper&&) noexcept = default; | ||
AsyncWrapper& operator=(AsyncWrapper&&) noexcept = default; | ||
|
||
// Destructor | ||
~AsyncWrapper() { | ||
if constexpr (isCancellable) { | ||
if(is_cancelled) { | ||
is_cancelled->store(true); | ||
} | ||
} | ||
} | ||
// These methods replicate the behaviour of std::future<T> | ||
[[nodiscard]] T get() { | ||
if constexpr (isCancellable) { | ||
if (IsCancelled()) { | ||
throw std::logic_error{"Calling AsyncWrapper::get on a cancelled request!"}; | ||
} | ||
} | ||
if (!future.valid()) { | ||
throw std::logic_error{"Calling AsyncWrapper::get when the associated future instance is invalid!"}; | ||
} | ||
return future.get(); | ||
} | ||
|
||
[[nodiscard]] bool valid() const noexcept { | ||
if constexpr (isCancellable) { | ||
return !is_cancelled->load() && future.valid(); | ||
} else { | ||
return future.valid(); | ||
} | ||
} | ||
|
||
void wait() const { | ||
if constexpr (isCancellable) { | ||
if (is_cancelled->load()) { | ||
throw std::logic_error{"Calling AsyncWrapper::wait when the associated future is invalid or cancelled!"}; | ||
} | ||
} | ||
if (!future.valid()) { | ||
throw std::logic_error{"Calling AsyncWrapper::wait_until when the associated future is invalid!"}; | ||
} | ||
future.wait(); | ||
} | ||
|
||
template <class Rep, class Period> | ||
std::future_status wait_for(const std::chrono::duration<Rep, Period>& timeout_duration) const { | ||
if constexpr (isCancellable) { | ||
if (IsCancelled()) { | ||
throw std::logic_error{"Calling AsyncWrapper::wait_for when the associated future is cancelled!"}; | ||
} | ||
} | ||
if (!future.valid()) { | ||
throw std::logic_error{"Calling AsyncWrapper::wait_until when the associated future is invalid!"}; | ||
} | ||
return future.wait_for(timeout_duration); | ||
} | ||
|
||
template <class Clock, class Duration> | ||
std::future_status wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time) const { | ||
if constexpr (isCancellable) { | ||
if (IsCancelled()) { | ||
throw std::logic_error{"Calling AsyncWrapper::wait_until when the associated future is cancelled!"}; | ||
} | ||
} | ||
if (!future.valid()) { | ||
throw std::logic_error{"Calling AsyncWrapper::wait_until when the associated future is invalid!"}; | ||
} | ||
return future.wait_until(timeout_time); | ||
} | ||
|
||
std::shared_future<T> share() noexcept { | ||
return future.share(); | ||
} | ||
|
||
// Cancellation-related methods | ||
CancellationResult Cancel() { | ||
if constexpr (!isCancellable) { | ||
return CancellationResult::invalid_operation; | ||
} | ||
if (!future.valid() || is_cancelled->load()) { | ||
return CancellationResult::invalid_operation; | ||
} | ||
is_cancelled->store(true); | ||
return CancellationResult::success; | ||
} | ||
|
||
[[nodiscard]] bool IsCancelled() const { | ||
if constexpr (isCancellable) { | ||
return is_cancelled->load(); | ||
} else { | ||
return false; | ||
} | ||
} | ||
}; | ||
|
||
// Deduction guides | ||
template <typename T> | ||
AsyncWrapper(std::future<T>&&) -> AsyncWrapper<T, false>; | ||
|
||
template <typename T> | ||
AsyncWrapper(std::future<T>&&, std::shared_ptr<std::atomic_bool>&&) -> AsyncWrapper<T, true>; | ||
|
||
} // namespace cpr | ||
|
||
|
||
#endif |
Oops, something went wrong.