/* Copyright (C) 2010 and 2012 Chris Vine

The library comprised in this file or of which this file is part is
distributed by Chris Vine under the GNU Lesser General Public
License as follows:

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public License
   as published by the Free Software Foundation; either version 2.1 of
   the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License, version 2.1, for more details.

   You should have received a copy of the GNU Lesser General Public
   License, version 2.1, along with this library (see the file LGPL.TXT
   which came with this source code package in the src/utils sub-directory);
   if not, write to the Free Software Foundation, Inc.,
   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

However, it is not intended that the object code of a program whose
source code instantiates a template from this file or uses macros or
inline functions (of any length) should by reason only of that
instantiation or use be subject to the restrictions of use in the GNU
Lesser General Public License.  With that in mind, the words "and
macros, inline functions and instantiations of templates (of any
length)" shall be treated as substituted for the words "and small
macros and small inline functions (ten lines or less in length)" in
the fourth paragraph of section 5 of that licence.  This does not
affect any other reason why object code may be subject to the
restrictions in that licence (nor for the avoidance of doubt does it
affect the application of section 2 of that licence to modifications
of the source code in this file).

*/

#ifndef CGU_FUTURE_TPP
#define CGU_FUTURE_TPP

namespace Cgu {

namespace Thread {

namespace FutureHelper {

/* 
 * The FunctorCallback class is a specialised class which is necessary
 * because the 'functor' member needs to be declared mutable so that
 * it can bind to the reference to non-const argument of the member
 * function pointed to by 'func', and thus so that a mutable lambda
 * can be executed by that member function.  Because it is so
 * specialised, it is not suitable for inclusion in the generic
 * interfaces provided in callback.h.  (Except in this specialised
 * usage, it can also be dangerous, as it allows a member of the
 * callback object to be mutated: normally this would be undesirable.)
 * An alternative would have been to put the 'functor' member in a
 * wrapper struct like WhenWrapperArg or WhenWrapperArgRel, but if
 * 'functor' were an lvalue that would mean it being copied twice.
 * This is the most efficient implementation.
 */
template <class Val, class FType>
class FunctorCallback: public Cgu::Callback::Callback {
public:
  typedef void (Future<Val>::* MemFunc)(FType&);
private:
  Future<Val>* obj;
  MemFunc func;
  mutable FType functor;
public:
  void dispatch() const {(obj->*func)(functor);}
  template <class Func>
  FunctorCallback(Future<Val>& obj_, MemFunc func_,
		  Func&& functor_): obj(&obj_), func(func_), functor(std::forward<Func>(functor_)) {}
};

} // namespace FutureHelper

extern "C" {
inline void cgu_future_cancel_cleanup_handler(void* arg) {
  Cgu::Callback::Callback* cb = static_cast<Cgu::Callback::Callback*>(arg);
  cb->dispatch();
  delete cb;
}
}

template <class Val>
void Future<Val>::cancel_cleanup() {
  {
    Mutex::Lock lock{mutex};
    error = true;
    done = true;
    running = false;
    cond.broadcast();  // any threads waiting on Future<Val>::get() will
                       // have their own reference, so we can unref() now
  }
  unref();
}

template <class Val>
template <class T, class Ret, class... Args>
void Future<Val>::run_wrapper(T* obj, Ret (T::*func)(Args...),
                              const Args&... args) {

  Cgu::Callback::Callback* cb;
  {
    CancelBlock b;
    try {
      cb = Callback::make(*this, &Future<Val>::cancel_cleanup);
    }
    catch (...) {
      cancel_cleanup();      
      return;
    }
  }

  pthread_cleanup_push(cgu_future_cancel_cleanup_handler, cb);

  try {
    // we don't want to hold the mutex when executing the callback (we may
    // be creating deadlocks from out of order locking) and we don't need
    // to when assigning to val, because before the get() method can proceed
    // this thread will have released the mutex below and the thread calling
    // get() will have since acquired it
    val = (obj->*func)(args...);
  }
  catch (Exit&) {
    Mutex::Lock lock{mutex};
    error = true;
  }
  catch (std::exception&) {
    Mutex::Lock lock{mutex};
    error = true;
  }
  // we won't catch with the elypsis argument because NPTL forced stack
  // unwinding would require the exception to be rethrown.  For any exceptions
  // other than Thread::Exit and those derived from std::exception we will
  // have to rely on the user stopping them reaching this far.

  // don't allow any further thread cancellation, and particularly when
  // any callback connected to done_emitter is executed
  CancelBlock b;
  pthread_cleanup_pop(false);
  delete cb;

  mutex.lock();
  done = true;
  cond.broadcast();
  if (!error) {
    mutex.unlock();
    try {
      done_emitter();
      Mutex::Lock lock{mutex};
      // we use running also to indicate whether done_emitter() has
      // completed
      running = false;
    }
    catch (...) {
      Mutex::Lock lock{mutex};
      emitter_error = true;
      running = false;
    }
  }
  else {
    running = false;
    mutex.unlock();
  }
  this->unref();  // any threads waiting on Future<Val>::get() will
                  // have their own reference, so we can unref() now
}

template <class Val>
template <class T, class Ret, class... Args>
void Future<Val>::run_wrapper_const(const T* obj, Ret (T::*func)(Args...) const,
                                    const Args&... args) {

  Cgu::Callback::Callback* cb;
  {
    CancelBlock b;
    try {
      cb = Callback::make(*this, &Future<Val>::cancel_cleanup);
    }
    catch (...) {
      cancel_cleanup();      
      return;
    }
  }

  pthread_cleanup_push(cgu_future_cancel_cleanup_handler, cb);

  try {
    // we don't want to hold the mutex when executing the callback (we may
    // be creating deadlocks from out of order locking) and we don't need
    // to when assigning to val, because before the get() method can proceed
    // this thread will have released the mutex below and the thread calling
    // get() will have since acquired it
    val = (obj->*func)(args...);
  }
  catch (Exit&) {
    Mutex::Lock lock{mutex};
    error = true;
  }
  catch (std::exception&) {
    Mutex::Lock lock{mutex};
    error = true;
  }
  // we won't catch with the elypsis argument because NPTL forced stack
  // unwinding would require the exception to be rethrown.  For any exceptions
  // other than Thread::Exit and those derived from std::exception we will
  // have to rely on the user stopping them reaching this far.

  // don't allow any further thread cancellation, and particularly when
  // any callback connected to done_emitter is executed
  CancelBlock b;
  pthread_cleanup_pop(false);
  delete cb;

  mutex.lock();
  done = true;
  cond.broadcast();
  if (!error) {
    mutex.unlock();
    try {
      done_emitter();
      Mutex::Lock lock{mutex};
      // we use running also to indicate whether done_emitter() has
      // completed
      running = false;
    }
    catch (...) {
      Mutex::Lock lock{mutex};
      emitter_error = true;
      running = false;
    }
  }
  else {
    running = false;
    mutex.unlock();
  }
  this->unref();  // any threads waiting on Future<Val>::get() will
                  // have their own reference, so we can unref() now
}

template <class Val>
template <class Ret, class... Args>
void Future<Val>::run_wrapper_static(Ret (*func)(Args...), const Args&... args) {

  Cgu::Callback::Callback* cb;
  {
    CancelBlock b;
    try {
      cb = Callback::make(*this, &Future<Val>::cancel_cleanup);
    }
    catch (...) {
      cancel_cleanup();      
      return;
    }
  }

  pthread_cleanup_push(cgu_future_cancel_cleanup_handler, cb);

  try {
    // we don't want to hold the mutex when executing the callback (we may
    // be creating deadlocks from out of order locking) and we don't need
    // to when assigning to val, because before the get() method can proceed
    // this thread will have released the mutex below and the thread calling
    // get() will have since acquired it
    val = func(args...);
  }
  catch (Exit&) {
    Mutex::Lock lock{mutex};
    error = true;
  }
  catch (std::exception&) {
    Mutex::Lock lock{mutex};
    error = true;
  }
  // we won't catch with the elypsis argument because NPTL forced stack
  // unwinding would require the exception to be rethrown.  For any exceptions
  // other than Thread::Exit and those derived from std::exception we will
  // have to rely on the user stopping them reaching this far.

  // don't allow any further thread cancellation, and particularly when
  // any callback connected to done_emitter is executed
  CancelBlock b;
  pthread_cleanup_pop(false);
  delete cb;

  mutex.lock();
  done = true;
  cond.broadcast();
  if (!error) {
    mutex.unlock();
    try {
      done_emitter();
      Mutex::Lock lock{mutex};
      // we use running also to indicate whether done_emitter() has
      // completed
      running = false;
    }
    catch (...) {
      Mutex::Lock lock{mutex};
      emitter_error = true;
      running = false;
    }
  }
  else {
    running = false;
    mutex.unlock();
  }
  this->unref();  // any threads waiting on Future<Val>::get() will
                  // have their own reference, so we can unref() now
}

// functor needs to be a non-const reference so that we can execute
// mutable lambdas: we make the Func member mutable in
// FutureHelper::FunctorCallback for that reason
template <class Val>
template <class Func>
void Future<Val>::run_wrapper_functor(Func& functor) {

  Cgu::Callback::Callback* cb;
  {
    CancelBlock b;
    try {
      cb = Callback::make(*this, &Future<Val>::cancel_cleanup);
    }
    catch (...) {
      cancel_cleanup();      
      return;
    }
  }

  pthread_cleanup_push(cgu_future_cancel_cleanup_handler, cb);

  try {
    // we don't want to hold the mutex when executing the callback (we may
    // be creating deadlocks from out of order locking) and we don't need
    // to when assigning to val, because before the get() method can proceed
    // this thread will have released the mutex below and the thread calling
    // get() will have since acquired it
    val = functor();
  }
  catch (Exit&) {
    Mutex::Lock lock{mutex};
    error = true;
  }
  catch (std::exception&) {
    Mutex::Lock lock{mutex};
    error = true;
  }
  // we won't catch with the elypsis argument because NPTL forced stack
  // unwinding would require the exception to be rethrown.  For any exceptions
  // other than Thread::Exit and those derived from std::exception we will
  // have to rely on the user stopping them reaching this far.

  // don't allow any further thread cancellation, and particularly when
  // any callback connected to done_emitter is executed
  CancelBlock b;
  pthread_cleanup_pop(false);
  delete cb;

  mutex.lock();
  done = true;
  cond.broadcast();
  if (!error) {
    mutex.unlock();
    try {
      done_emitter();
      Mutex::Lock lock{mutex};
      // we use running also to indicate whether done_emitter() has
      // completed
      running = false;
    }
    catch (...) {
      Mutex::Lock lock{mutex};
      emitter_error = true;
      running = false;
    }
  }
  else {
    running = false;
    mutex.unlock();
  }
  this->unref();  // any threads waiting on Future<Val>::get() will
                  // have their own reference, so we can unref() now
}

template <class Val>
template <class Ret, class T>
IntrusivePtr<Future<Val>> Future<Val>::make(T& t,
					    Ret (T::*func)()) {
  
  IntrusivePtr<Future<Val>> instance{new Future<Val>};
  // Give the compiler maximum help: gcc requires explicit type
  // specification for run_wrapper(), let's give it a static_cast as well
  instance->cb_u.reset(Callback::make(*instance,
                                      static_cast<void(Future<Val>::*)(T*,
								       Ret(T::*)())>(&Future<Val>::run_wrapper<T, Ret>),
                                      &t, func));
  return instance;
}

template <class Val>
template <class Ret, class Param1, class Arg1, class T>
IntrusivePtr<Future<Val>> Future<Val>::make(T& t,
					    Ret (T::*func)(Param1),
					    Arg1&& arg1) {

  IntrusivePtr<Future<Val>> instance{new Future<Val>};
  // Give the compiler maximum help: gcc requires explicit type
  // specification for run_wrapper(), let's give it a static_cast as well
  instance->cb_u.reset(Callback::make_ref(*instance,
                                          static_cast<void(Future<Val>::*)(T*,
									   Ret(T::*)(Param1),
									   const Param1&)>(&Future<Val>::run_wrapper<T, Ret, Param1>),
                                          &t, func,
					  std::forward<Arg1>(arg1)));
  return instance;
}

template <class Val>
template <class Ret, class Param1, class Param2, class Arg1, class Arg2, class T>
IntrusivePtr<Future<Val>> Future<Val>::make(T& t,
					    Ret (T::*func)(Param1, Param2),
					    Arg1&& arg1,
					    Arg2&& arg2) {

  IntrusivePtr<Future<Val>> instance{new Future<Val>};
  // Give the compiler maximum help: gcc requires explicit type
  // specification for run_wrapper(), let's give it a static_cast as well
  instance->cb_u.reset(Callback::make_ref(*instance,
                                          static_cast<void(Future<Val>::*)(T*,
									   Ret(T::*)(Param1, Param2),
									   const Param1&,
									   const Param2&)>(&Future<Val>::run_wrapper<T, Ret, Param1, Param2>),
                                          &t, func,
					  std::forward<Arg1>(arg1),
					  std::forward<Arg2>(arg2)));
  return instance;
}

template <class Val>
template <class Ret, class Param1, class Param2, class Param3,
          class Arg1, class Arg2, class Arg3, class T>
IntrusivePtr<Future<Val>> Future<Val>::make(T& t,
					    Ret (T::*func)(Param1, Param2, Param3),
					    Arg1&& arg1,
					    Arg2&& arg2,
					    Arg3&& arg3) {

  IntrusivePtr<Future<Val>> instance{new Future<Val>};
  // Give the compiler maximum help: gcc requires explicit type
  // specification for run_wrapper(), let's give it a static_cast as well
  instance->cb_u.reset(Callback::make_ref(*instance,
                                          static_cast<void(Future<Val>::*)(T*,
									   Ret(T::*)(Param1, Param2, Param3),
									   const Param1&,
									   const Param2&,
									   const Param3&)>(&Future<Val>::run_wrapper<T, Ret, Param1, Param2, Param3>),
                                          &t, func,
					  std::forward<Arg1>(arg1),
					  std::forward<Arg2>(arg2),
					  std::forward<Arg3>(arg3)));
  return instance;
}

template <class Val>
template <class Ret, class T>
IntrusivePtr<Future<Val>> Future<Val>::make(const T& t,
					    Ret (T::*func)() const) {

  IntrusivePtr<Future<Val>> instance{new Future<Val>};
  // Give the compiler maximum help: gcc requires explicit type
  // specification for run_wrapper_const(), let's give it a static_cast as well
  instance->cb_u.reset(Callback::make(*instance,
                                      static_cast<void(Future<Val>::*)(const T*,
								       Ret(T::*)() const)>(&Future<Val>::run_wrapper_const<T, Ret>),
                                      &t, func));
  return instance;
}

template <class Val>
template <class Ret, class Param1, class Arg1, class T>
IntrusivePtr<Future<Val>> Future<Val>::make(const T& t,
					    Ret (T::*func)(Param1) const,
					    Arg1&& arg1) {

  IntrusivePtr<Future<Val>> instance{new Future<Val>};
  // Give the compiler maximum help: gcc requires explicit type
  // specification for run_wrapper_const(), let's give it a static_cast as well
  instance->cb_u.reset(Callback::make_ref(*instance,
					  static_cast<void(Future<Val>::*)(const T*,
									   Ret(T::*)(Param1) const,
									   const Param1&)>(&Future<Val>::run_wrapper_const<T, Ret, Param1>),
                                          &t, func,
					  std::forward<Arg1>(arg1)));
  return instance;
}

template <class Val>
template <class Ret, class Param1, class Param2, class Arg1, class Arg2, class T>
IntrusivePtr<Future<Val>> Future<Val>::make(const T& t,
					    Ret (T::*func)(Param1, Param2) const,
					    Arg1&& arg1,
					    Arg2&& arg2) {

  IntrusivePtr<Future<Val>> instance{new Future<Val>};
  // Give the compiler maximum help: gcc requires explicit type
  // specification for run_wrapper_const(), let's give it a static_cast as well
  instance->cb_u.reset(Callback::make_ref(*instance,
					  static_cast<void(Future<Val>::*)(const T*,
									   Ret(T::*)(Param1, Param2) const,
									   const Param1&,
									   const Param2&)>(&Future<Val>::run_wrapper_const<T, Ret, Param1, Param2>),
                                          &t, func,
					  std::forward<Arg1>(arg1),
					  std::forward<Arg2>(arg2)));
  return instance;
}

template <class Val>
template <class Ret, class Param1, class Param2, class Param3,
          class Arg1, class Arg2, class Arg3, class T>
IntrusivePtr<Future<Val>> Future<Val>::make(const T& t,
					    Ret (T::*func)(Param1, Param2, Param3) const,
					    Arg1&& arg1,
					    Arg2&& arg2,
					    Arg3&& arg3) {

  IntrusivePtr<Future<Val>> instance{new Future<Val>};
  // Give the compiler maximum help: gcc requires explicit type
  // specification for run_wrapper_const(), let's give it a static_cast as well
  instance->cb_u.reset(Callback::make_ref(*instance,
					  static_cast<void(Future<Val>::*)(const T*,
									   Ret(T::*)(Param1, Param2, Param3) const,
									   const Param1&,
									   const Param2&,
									   const Param3&)>(&Future<Val>::run_wrapper_const<T, Ret, Param1, Param2, Param3>),
                                          &t, func,
					  std::forward<Arg1>(arg1),
					  std::forward<Arg2>(arg2),
					  std::forward<Arg3>(arg3)));
  return instance;
}

template <class Val>
template <class Ret>
IntrusivePtr<Future<Val>> Future<Val>::make(Ret (*func)()) {

  IntrusivePtr<Future<Val>> instance{new Future<Val>};
  // Give the compiler maximum help: gcc requires explicit type
  // specification for run_wrapper_static(), let's give it a static_cast as well
  instance->cb_u.reset(Callback::make(*instance,
                                      static_cast<void(Future<Val>::*)(Ret(*)())>(&Future<Val>::run_wrapper_static<Ret>),
                                      func));
  return instance;
}

template <class Val>
template <class Ret, class Param1, class Arg1>
IntrusivePtr<Future<Val>> Future<Val>::make(Ret (*func)(Param1),
					    Arg1&& arg1) {

  IntrusivePtr<Future<Val>> instance{new Future<Val>};
  // Give the compiler maximum help: gcc requires explicit type
  // specification for run_wrapper_static(), let's give it a static_cast as well
  instance->cb_u.reset(Callback::make_ref(*instance,
					  static_cast<void(Future<Val>::*)(Ret(*)(Param1),
									   const Param1&)>(&Future<Val>::run_wrapper_static<Ret, Param1>),
                                          func,
					  std::forward<Arg1>(arg1)));
  return instance;
}

template <class Val>
template <class Ret, class Param1, class Param2, class Arg1, class Arg2>
IntrusivePtr<Future<Val>> Future<Val>::make(Ret (*func)(Param1, Param2),
					    Arg1&& arg1,
					    Arg2&& arg2) {

  IntrusivePtr<Future<Val>> instance{new Future<Val>};
  // Give the compiler maximum help: gcc requires explicit type
  // specification for run_wrapper_static(), let's give it a static_cast as well
  instance->cb_u.reset(Callback::make_ref(*instance,
					  static_cast<void(Future<Val>::*)(Ret(*)(Param1, Param2),
									   const Param1&,
									   const Param2&)>(&Future<Val>::run_wrapper_static<Ret, Param1, Param2>),
                                          func,
					  std::forward<Arg1>(arg1),
					  std::forward<Arg2>(arg2)));
  return instance;
}

template <class Val>
template <class Ret, class Param1, class Param2, class Param3,
	  class Arg1, class Arg2, class Arg3>
IntrusivePtr<Future<Val>> Future<Val>::make(Ret (*func)(Param1, Param2, Param3),
					    Arg1&& arg1,
					    Arg2&& arg2,
					    Arg3&& arg3) {

  IntrusivePtr<Future<Val>> instance{new Future<Val>};
  // Give the compiler maximum help: gcc requires explicit type
  // specification for run_wrapper_static(), let's give it a static_cast as well
  instance->cb_u.reset(Callback::make_ref(*instance,
					  static_cast<void(Future<Val>::*)(Ret(*)(Param1, Param2, Param3),
									   const Param1&,
									   const Param2&,
									   const Param3&)>(&Future<Val>::run_wrapper_static<Ret, Param1, Param2, Param3>),
                                          func,
					  std::forward<Arg1>(arg1),
					  std::forward<Arg2>(arg2),
					  std::forward<Arg3>(arg3)));
  return instance;
}

template <class Val>
template <class Ret, class Param1, class Param2, class Param3, class Param4,
	  class Arg1, class Arg2, class Arg3, class Arg4>
IntrusivePtr<Future<Val>> Future<Val>::make(Ret (*func)(Param1, Param2, Param3, Param4),
					    Arg1&& arg1,
					    Arg2&& arg2,
					    Arg3&& arg3,
					    Arg4&& arg4) {

  IntrusivePtr<Future<Val>> instance{new Future<Val>};
  // Give the compiler maximum help: gcc requires explicit type
  // specification for run_wrapper_static(), let's give it a static_cast as well
  instance->cb_u.reset(Callback::make_ref(*instance,
					  static_cast<void(Future<Val>::*)(Ret(*)(Param1, Param2, Param3, Param4),
									   const Param1&,
									   const Param2&,
									   const Param3&,
									   const Param4&)>(&Future<Val>::run_wrapper_static<Ret, Param1, Param2, Param3, Param4>),
                                          func,
					  std::forward<Arg1>(arg1),
					  std::forward<Arg2>(arg2),
					  std::forward<Arg3>(arg3),
					  std::forward<Arg4>(arg4)));
  return instance;
}

template <class Val>
template <class Func>
IntrusivePtr<Future<Val>> Future<Val>::make(Func&& functor) {

  // there are two types related to the functor to be executed by the
  // thread.  'Func' is the transient type provided by argument
  // deduction for forwarding, and will vary depending on whether the
  // functor object is a lvalue (which will deduce it as a reference
  // type) or rvalue (which will not).  'FType' is the type to be held
  // by the callback object generated in this function, and is never a
  // reference type.  It is also never const, because the FType member
  // is marked mutable in the callback object so that it can execute
  // mutable lambdas (or other functors with a non-const operator()()
  // method).
  typedef typename std::remove_const<typename std::remove_reference<Func>::type>::type FType;

  IntrusivePtr<Future<Val>> instance{new Future<Val>};
  instance->cb_u.reset(new FutureHelper::FunctorCallback<Val, FType>(*instance,
								     &Future<Val>::run_wrapper_functor<FType>,
								     std::forward<Func>(functor)));
  return instance;
}

template <class Val>
bool Future<Val>::run() {

  // take a reference so that this object will exist at least
  // until the worker thread has completed (we release in one
  // of the run_wrapper() methods, in cancel_cleanup() or on
  // throwing below)
  ref();

  Mutex::Lock lock{mutex};
  // we don't want to throw an exception if run() has already been
  // called - that may not be a programming error - the user may not
  // care whether it has been called, just that it should have been
  // called (Future<>::get() can be called any number of times by
  // any number of threads).  So provide a return value which can be
  // inspected where it is relevant to the particular usage case
  if (running || done || error) { // if run() has previously thrown, although 'running'
                                  // and 'done' will be false, error will be true
    unref();
    return false;
  }
  running = true;

  try {
    // the following formula will work for both std::auto_ptr and std::unique_ptr
    // return values of Cgu::Thread::Thread::start()
    thread_u.reset(Cgu::Thread::Thread::start(cb_u.release(), false).release());
  }
  catch (...) {
    error = true;
    running = false;
    unref();
    throw;
  }
  if (!thread_u.get()) {
    error = true;
    running = false;
    unref();
    throw FutureThreadError();
  }
  return true;
}

template <class Val>
Val Future<Val>::get() {

  // make sure run() has been called: if run() has previously thrown,
  // although 'running' and 'done' will be false, 'error' will be true
  mutex.lock();
  if (!running && !done && !error) {
    CancelBlock b;
    mutex.unlock();
    run();                 // there is no race - if another thread beats us
                           // to it after unlocking, run() will just return
    mutex.lock();
  }
  Mutex::Lock lock{mutex, locked};
  if (!error) {            // we don't want to hang if run() threw because
                           // it could not start a worker thread
    while (!done) cond.wait(mutex);
  }
  CancelBlock b;
  return val;
}

template <class Val>
Val Future<Val>::move_get() {

  // make sure run() has been called: if run() has previously thrown,
  // although 'running' and 'done' will be false, 'error' will be true
  mutex.lock();
  if (!running && !done && !error) {
    CancelBlock b;
    mutex.unlock();
    run();
    mutex.lock();
  }
  Mutex::Lock lock{mutex, locked};
  if (!error) {            // we don't want to hang if run() threw because
                           // it could not start a worker thread
    while (!done) cond.wait(mutex);
  }
  CancelBlock b;
  return std::move(val);
}

template <class Val>
bool Future<Val>::cancel() {
  Mutex::Lock lock{mutex};
  if (!done && thread_u.get()) {
    thread_u->cancel();
    return true;
  }
  return false;     
}

template <class Val>
void Future<Val>::execute_done(const std::unique_ptr<const Cgu::Callback::CallbackArg<const Val&>>& f) {
  // take an additional reference in an intrusive pointer in case
  // dispatch() throws, so we can call unref() before the call to
  // dispatch()
  Cgu::IntrusivePtr<Future<Val>> temp{this};
  unref();  // remove reference added in post_done()

  // we can access 'val' directly here, rather than calling 'get()'
  // because attaching to and dispatching via the main loop will
  // guarantee memory visibility
  f->dispatch(val);
}

template <class Val>
void Future<Val>::post_done(const FutureHelper::WhenWrapperArg<Val>& w,
			    gint priority,
			    GMainContext* context) {
  // take an additional reference in an intrusive pointer in case
  // Callback::post() throws.  We must acquire a reference before
  // Callback::post() returns to avoid a race condition with the main
  // loop thread.
  Cgu::IntrusivePtr<Future<Val>> temp{this};
  Cgu::Callback::post(Cgu::Callback::make_ref(*this,
					      &Future<Val>::execute_done,
					      std::move(w.when)),
		      priority,
		      context);
  // the Future object is guaranteed to be in existence until after
  // done_emitter has completed all its emissions, but we need to add
  // another reference in this method to also make sure that the
  // Future object lasts until execute_done executes.  We don't need
  // to put the call to Callback::post in a try block, because the
  // run_wrapper methods catch any exceptions when done_emitter emits
  // and set emitter_error in such a case.
  ref();
}

template <class Val>
Cgu::Callback::SafeFunctor Future<Val>::when(const Cgu::Callback::CallbackArg<const Val&>* cb,
					     gint priority,
					     GMainContext* context) {

  std::unique_ptr<const Cgu::Callback::CallbackArg<const Val&>> f(cb);   // take ownership

  Mutex::Lock lock{mutex};
  if (done) throw FutureWhenError();
  return done_emitter.connect(Cgu::Callback::make_ref(*this,
						      &Future<Val>::post_done, 
						      Cgu::Thread::FutureHelper::WhenWrapperArg<Val>{std::move(f)},
						      priority,
						      context));
}

template <class Val>
void Future<Val>::execute_done_rel(const std::unique_ptr<Cgu::SafeEmitterArg<const Val&>>& s) {
  // take an additional reference in an intrusive pointer in case
  // emit() throws, so we can call unref() before the call to emit()
  Cgu::IntrusivePtr<Future<Val>> temp{this};
  unref();  // remove reference added in post_done_rel()

  // we can access 'val' directly here, rather than calling 'get()'
  // because attaching to and dispatching via the main loop will
  // guarantee memory visibility
  s->emit(val);
}

template <class Val>
void Future<Val>::post_done_rel(const FutureHelper::WhenWrapperArgRel<Val>& w,
				gint priority,
				GMainContext* context) {

  // take an additional reference in an intrusive pointer in case
  // Callback::post() throws.  We must acquire a reference before
  // Callback::post() returns to avoid a race condition with the main
  // loop thread
  Cgu::IntrusivePtr<Future<Val>> temp{this};
  Cgu::Callback::post(Cgu::Callback::make_ref(*this,
					      &Future<Val>::execute_done_rel,
					      std::move(w.when)),
		      priority,
		      context);
  // the Future object is guaranteed to be in existence until after
  // done_emitter has completed all its emissions, but we need to add
  // another reference in this method to also make sure that the
  // Future object lasts until execute_done_rel() executes.  We don't
  // need to put the call to Callback::post in a try block, because
  // the run_wrapper methods catch any exceptions when done_emitter
  // emits and set emitter_error in such a case.
  ref();
}

template <class Val>
Cgu::Callback::SafeFunctor Future<Val>::when(const Cgu::Callback::CallbackArg<const Val&>* cb,
					     Cgu::Releaser& r,
					     gint priority,
					     GMainContext* context) {

  Cgu::Callback::SafeFunctorArg<const Val&> f{cb};   // take ownership
  std::unique_ptr<Cgu::SafeEmitterArg<const Val&>> s(new Cgu::SafeEmitterArg<const Val&>);
  s->connect(f, r);

  Mutex::Lock lock{mutex};
  if (done) throw FutureWhenError();
  return done_emitter.connect(Cgu::Callback::make_ref(*this,
						      &Future<Val>::post_done_rel,
						      FutureHelper::WhenWrapperArgRel<Val>{std::move(s)},
						      priority,
						      context));
}

template <class Val>
void Future<Val>::fail_cb(const Cgu::IntrusivePtr<Future<Val>>& future,
			  const std::unique_ptr<const Cgu::Callback::Callback>& func,
			  bool& ret) {
  Mutex::TrackLock lock{future->mutex};
  if (!future->running && future->done) { // everything finished
    // remove timeout
    ret = false;
    if (future->error || future->emitter_error) {
      // we failed, execute 'func'
      lock.unlock();
      func->dispatch();
    }
  }
  else if (!future->running && !future->done && future->error) {
    // if (!running && !done && error) then run() has thrown and the
    // thread never launched - stop timeout
    ret = false;
  }
}

template <class Val>
void Future<Val>::fail(const Cgu::Callback::Callback* cb,
		       Cgu::Releaser& r,
		       GMainContext* context) {

  std::unique_ptr<const Cgu::Callback::Callback> func(cb);   // take ownership
  Cgu::start_timeout(100,
		     Cgu::Callback::make_ref(&Future<Val>::fail_cb,
					     Cgu::IntrusivePtr<Future<Val>>{this},
					     std::move(func)),
		     r,
		     G_PRIORITY_DEFAULT,
		     context);
}

template <class Val>
void Future<Val>::fail(const Cgu::Callback::Callback* cb,
		       GMainContext* context) {

  std::unique_ptr<const Cgu::Callback::Callback> func(cb);   // take ownership
  Cgu::start_timeout(100,
		     Cgu::Callback::make_ref(&Future<Val>::fail_cb,
					     Cgu::IntrusivePtr<Future<Val>>{this},
					     std::move(func)),
		     G_PRIORITY_DEFAULT,
		     context);
}

template <class Val>
bool Future<Val>::is_done() const {
  Mutex::Lock lock{mutex};
  return done;
}

template <class Val>
bool Future<Val>::is_emitter_done() const {
  Mutex::Lock lock{mutex};
  return (done && !running);   //'running' does not return to a false value until
                               // 'done_emitter' has completed emitting
}

template <class Val>
bool Future<Val>::is_error() const {
  Mutex::Lock lock{mutex};
  return error;
}

template <class Val>
bool Future<Val>::is_emitter_error() const {
  Mutex::Lock lock{mutex};
  return emitter_error;
}

} // namespace Thread

} // namespace Cgu

#endif // CGU_FUTURE_TPP
