#ifndef ASYNCHRONOUS_CONTINUATION_H #define ASYNCHRONOUS_CONTINUATION_H #include #include #include #include namespace smo { /** * AsynchronousContinuation - Template base class for async sequence management * * This template provides a common pattern for managing asynchronous operations * that need to maintain object lifetime through a sequence of callbacks. * * The template parameter OriginalCbFnT represents the signature of the original * callback that will be invoked when the async sequence completes. */ template class AsynchronousContinuation { public: explicit AsynchronousContinuation(OriginalCbFnT originalCbFn) : originalCbFn(std::move(originalCbFn)) {} /** EXPLANATION: * Each numbered segmented sequence persists the lifetime of the * continuation object by taking a copy of its shared_ptr. */ typedef void (SegmentFn)( std::shared_ptr> lifetimePreservingConveyance); /** * @brief Call the original callback with perfect forwarding * * IMPORTANT: This method cannot be virtual because templates cannot be * virtual in C++. Therefore, this method MUST be called from the * most-derived class reference/pointer context. Never call this method * through a polymorphic base class reference/pointer, as it will not * dispatch to the correct derived class implementation. * * @param args Arguments to forward to the original callback */ template void callOriginalCb(Args&&... args) { if (originalCbFn) { originalCbFn(std::forward(args)...); } } public: OriginalCbFnT originalCbFn; }; /** * NonPostedAsynchronousContinuation - For continuations that don't post * callbacks * * Note: We intentionally do not create a * LockedNonPostedAsynchronousContinuation because the only way to implement * non-posted locking would be via busy-spinning or sleeplocks. This would * eliminate the throughput advantage from our Qspinning mechanism, which * relies on re-posting to the io_service queue when locks are unavailable. */ template class NonPostedAsynchronousContinuation : public AsynchronousContinuation { public: explicit NonPostedAsynchronousContinuation(OriginalCbFnT originalCbFn) : AsynchronousContinuation(originalCbFn) {} public: using AsynchronousContinuation::callOriginalCb; }; template class PostedAsynchronousContinuation : public AsynchronousContinuation { public: PostedAsynchronousContinuation( const std::shared_ptr &caller, OriginalCbFnT originalCbFn) : AsynchronousContinuation(originalCbFn), caller(caller) {} template void callOriginalCb(Args&&... args) { if (AsynchronousContinuation::originalCbFn) { caller->getIoService().post( std::bind( AsynchronousContinuation::originalCbFn, std::forward(args)...)); } } public: std::shared_ptr caller; using AsynchronousContinuation::callOriginalCb; }; template class SerializedAsynchronousContinuation : public PostedAsynchronousContinuation, public LockSpec { public: SerializedAsynchronousContinuation( const std::shared_ptr &caller, OriginalCbFnT originalCbFn, std::vector> requiredLocks = {}) : PostedAsynchronousContinuation(caller, originalCbFn), LockSpec(std::move(requiredLocks)) {} template void callOriginalCb(Args&&... args) { LockSpec::release(); PostedAsynchronousContinuation::callOriginalCb( std::forward(args)...); } public: using AsynchronousContinuation::callOriginalCb; }; } // namespace smo #endif // ASYNCHRONOUS_CONTINUATION_H