Bugfix: sinkhandle can now be used to call, asynchronously, functions with more return types than std::string

This commit is contained in:
KjellKod 2014-02-11 20:00:20 -07:00
parent ffb4d86c1e
commit 1ed4bcb38c
3 changed files with 81 additions and 6 deletions

View File

@ -9,6 +9,7 @@
#include <memory>
#include <functional>
#include <type_traits>
#include "g2sinkwrapper.hpp"
#include "active.hpp"
@ -64,7 +65,7 @@ struct Sink : public SinkWrapper {
}
template<typename Call, typename... Args>
auto send(Call call, Args... args)-> std::future < decltype(bind(call, _real_sink.get(), args...)()) > {
auto async(Call call, Args... args)-> std::future< typename std::result_of<decltype(call)(T, Args...)>::type> {
return g2::spawn_task(std::bind(call, _real_sink.get(), args...), _bg.get());
}
};

View File

@ -9,6 +9,7 @@
#include <memory>
#include <functional>
#include <type_traits>
#include "g2sink.hpp"
namespace g2 {
@ -34,14 +35,13 @@ namespace g2 {
// Asynchronous call to the real sink. If the real sink is already deleted
// the returned future will contain a bad_weak_ptr exception instead of the
// call result.
template<typename Call, typename... Args>
auto call(Call call, Args... args) -> decltype(_sink.lock()->send(call, args...)) {
template<typename AsyncCall, typename... Args>
auto call(AsyncCall func , Args... args) -> std::future<typename std::result_of<decltype(func)(T, Args...)>::type> {
try {
std::shared_ptr<internal::Sink<T>> sink(_sink);
return sink->send(call, args...);
return sink->async(func, args...);
} catch (const std::bad_weak_ptr& e) {
T* t = nullptr;
typedef decltype(std::bind(call, t, args...)()) PromiseType;
typedef typename std::result_of<decltype(func)(T, Args...)>::type PromiseType;
std::promise<PromiseType> promise;
promise.set_exception(std::make_exception_ptr(e));
return std::move(promise.get_future());

View File

@ -11,10 +11,12 @@
#include <memory>
#include <thread>
#include <chrono>
#include <string>
#include "testing_helpers.h"
#include "g2logmessage.hpp"
#include "g2logworker.hpp"
#include "std2_make_unique.hpp"
using namespace testing_helpers;
using namespace std;
@ -88,3 +90,75 @@ TEST(ConceptSink, OneHundredSinks) {
cout << "test one hundred sinks is finished finished\n";
}
struct VoidReceiver {
std::atomic<int>* _atomicCounter;
explicit VoidReceiver(std::atomic<int>* counter) : _atomicCounter(counter){}
void receiveMsg(std::string msg){ /*ignored*/}
void incrementAtomic(){
(*_atomicCounter)++;
}
};
TEST(ConceptSink, VoidCall__NoCall_ExpectingNoAdd) {
std::atomic<int> counter{0};
{
std::unique_ptr<g2::LogWorker> worker{g2::LogWorker::createWithNoSink()};
auto handle = worker->addSink(std2::make_unique<VoidReceiver>(&counter), &VoidReceiver::receiveMsg);
}
EXPECT_EQ(counter, 0);
}
TEST(ConceptSink, VoidCall__OneCall_ExpectingOneAdd) {
std::atomic<int> counter{0};
{
std::unique_ptr<g2::LogWorker> worker{g2::LogWorker::createWithNoSink()};
auto handle = worker->addSink(std2::make_unique<VoidReceiver>(&counter), &VoidReceiver::receiveMsg);
std::future<void> ignored = handle->call(&VoidReceiver::incrementAtomic);
}
EXPECT_EQ(counter, 1);
}
TEST(ConceptSink, VoidCall__TwoCalls_ExpectingTwoAdd) {
std::atomic<int> counter{0};
{
std::unique_ptr<g2::LogWorker> worker{g2::LogWorker::createWithNoSink()};
auto handle = worker->addSink(std2::make_unique<VoidReceiver>(&counter), &VoidReceiver::receiveMsg);
auto voidFuture1 = handle->call(&VoidReceiver::incrementAtomic);
auto voidFuture2 = handle->call(&VoidReceiver::incrementAtomic);
voidFuture1.wait();
EXPECT_TRUE(counter >= 1);
}
EXPECT_EQ(counter, 2);
}
struct IntReceiver {
std::atomic<int>* _atomicCounter;
explicit IntReceiver(std::atomic<int>* counter) : _atomicCounter(counter){}
void receiveMsg(std::string msg){ /*ignored*/}
int incrementAtomic(){
(*_atomicCounter)++;
int value = *_atomicCounter;
return value;
}
};
TEST(ConceptSink, IntCall__TwoCalls_ExpectingTwoAdd) {
std::atomic<int> counter{0};
{
std::unique_ptr<g2::LogWorker> worker{g2::LogWorker::createWithNoSink()};
auto handle = worker->addSink(std2::make_unique<IntReceiver>(&counter), &IntReceiver::receiveMsg);
std::future<int> intFuture1 = handle->call(&IntReceiver::incrementAtomic);
EXPECT_EQ(intFuture1.get(), 1);
EXPECT_EQ(counter, 1);
auto intFuture2 = handle->call(&IntReceiver::incrementAtomic);
EXPECT_EQ(intFuture2.get(), 2);
}
EXPECT_EQ(counter, 2);
}