/// \file mingw.future.h
/// \brief Standard-compliant C++ futures for MinGW
///
/// (c) 2018 by Nathaniel J. McClatchey, San Jose, California
/// \author Nathaniel J. McClatchey, PhD
///
/// \copyright Simplified (2-clause) BSD License.
///
/// \note This file may become part of the mingw-w64 runtime package. If/when
/// this happens, the appropriate license will be added, i.e. this code will
/// become dual-licensed, and the current BSD 2-clause license will stay.
/// \note Target Windows version is determined by WINVER, which is determined in
/// <windows.h> from _WIN32_WINNT, which can itself be set by the user.

#ifndef MINGW_FUTURE_H_
#define MINGW_FUTURE_H_

#if !defined(__cplusplus) || (__cplusplus < 201103L)
#error The MinGW STD Threads library requires a compiler supporting C++11.
#endif

#include <future>

#include <cassert>
#include <vector>
#include <utility>        //  For std::pair
#include <type_traits>
#include <memory>
#include <functional>     //  For std::hash

#include "mingw.thread.h" //  Start new threads, and use invoke.

//  Mutexes and condition variables are used explicitly.
#include "mingw.mutex.h"
#include "mingw.condition_variable.h"

#if (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR))
#pragma message "The Windows API that MinGW-w32 provides is not fully compatible\
 with Microsoft's API. We'll try to work around this, but we can make no\
 guarantees. This problem does not exist in MinGW-w64."
#include <windows.h>    //  No further granularity can be expected.
#else
#include <synchapi.h>
#include <handleapi.h>
#include <processthreadsapi.h>
#endif

//  Note:
//    std::shared_ptr is the natural choice for this. However, a custom
//  implementation removes the need to keep a control block separate from the
//  class itself (no need to support weak pointers).

namespace mingw_stdthread
{
using std::future_errc;
using std::future_error;
using std::future_status;
using std::launch;
using std::future_category;

namespace detail
{
struct Empty { };

//    Use a class template to allow instantiation of statics in a header-only
//  library. Note: Template will only be instantiated once to avoid bloat.
template<bool>
struct FutureStatic
{
  enum Type : uint_fast8_t
  {
    kUndecided = 0x00,
    kValueFlag = 0x01,
    kExceptionFlag = 0x02,
    kDeferredFlag = 0x04, //  Needs special handling. Must not wait.
    kReadyFlag = 0x10,    //  Results are ready for consumption
    kTypeMask = 0x07,
    kNoWaitMask = 0x14    //  Indicates that waits should immediately exit.
  };

  static std::vector<std::pair<mutex, condition_variable> > sync_pool;

  static mutex & get_mutex (void const * ptr)
  {
    std::hash<void const *> hash_func;
    return sync_pool[hash_func(ptr) % sync_pool.size()].first;
  }
  static condition_variable & get_condition_variable (void const * ptr)
  {
    std::hash<void const *> hash_func;
    return sync_pool[hash_func(ptr) % sync_pool.size()].second;
  }
};
template<bool b>
std::vector<std::pair<mutex, condition_variable> > FutureStatic<b>::sync_pool (thread::hardware_concurrency() * 2 + 1);

struct FutureStateBase
{
  inline mutex & get_mutex (void) const
  {
    return FutureStatic<true>::get_mutex(this);
  }
  inline condition_variable & get_condition_variable (void) const
  {
    return FutureStatic<true>::get_condition_variable(this);
  }
  typedef typename FutureStatic<true>::Type Type;
//  Destroys this object. Used for allocator-awareness.
  virtual void deallocate_this (void) noexcept = 0;
  virtual ~FutureStateBase (void) = default;

  FutureStateBase (FutureStateBase const &) = delete;
  FutureStateBase & operator= (FutureStateBase const &) = delete;

  FutureStateBase(Type t) noexcept
    : mReferences(0), mType(t)
  {
  }

  void increment_references (void) noexcept
  {
    mReferences.fetch_add(1, std::memory_order_relaxed);
  }

  void decrement_references (void) noexcept
  {
    if (mReferences.fetch_sub(1, std::memory_order_acquire) == 0)
      deallocate_this();
  }

  std::atomic<size_t> mReferences;
  std::atomic<uint_fast8_t> mType;
};

//  Reduce compilation time and improve code re-use.
struct FutureBase : public FutureStatic<true>
{
  typedef FutureStatic<true> Base;
  FutureStateBase * mState;

  mutex & get_mutex (void) const
  {
    return FutureStatic<true>::get_mutex(mState);
  }
  condition_variable & get_condition_variable (void) const
  {
    return FutureStatic<true>::get_condition_variable(mState);
  }

  FutureBase (FutureStateBase * ptr) noexcept
    : mState(ptr)
  {
  }

  FutureBase (FutureBase && source) noexcept
    : mState(source.mState)
  {
    source.mState = nullptr;
  }

  ~FutureBase (void)
  {
    release();
  }

  FutureBase (FutureBase const &) = delete;
  FutureBase & operator= (FutureBase const &) = delete;

  bool valid (void) const noexcept
  {
    return mState != nullptr;
  }

//    Releases this object's hold on its state. Requires a specification of
//  which state is being used.
  inline void release (void) noexcept
  {
    if (valid())
      mState->decrement_references();
    mState = nullptr;
  }

  void wait (std::unique_lock<mutex> & lock) const
  {
#if !defined(NDEBUG)
    if (!valid())
      throw future_error(future_errc::no_state);
#endif
//    If there's already a value or exception, don't do any extraneous
//  synchronization. The `get()` method will do that for us.
    if (mState->mType.load(std::memory_order_relaxed) & Type::kNoWaitMask)
      return;
    get_condition_variable().wait(lock, [this](void)->bool {
      return mState->mType.load(std::memory_order_relaxed) & Type::kNoWaitMask;
    });
  }

  template<class Rep, class Period>
  future_status wait_for (std::chrono::duration<Rep,Period> const & dur) const
  {
#if !defined(NDEBUG)
    if (!valid())
      throw future_error(future_errc::no_state);
#endif
    auto current_state = mState->mType.load(std::memory_order_relaxed);
    if (current_state & Type::kNoWaitMask)
      return (current_state & Type::kDeferredFlag) ? future_status::deferred : future_status::ready;
    std::unique_lock<mutex> lock { get_mutex() };
    if (get_condition_variable().wait_for(lock, dur,
          [this](void)->bool {
            return mState->mType.load(std::memory_order_relaxed) & Type::kNoWaitMask;
          }))
      return future_status::ready;
    else
      return future_status::timeout;
  }

  template<class Clock, class Duration>
  future_status wait_until(const std::chrono::time_point<Clock,Duration>& time) const
  {
    return wait_for(time - Clock::now());
  }
};

template<class T>
struct FutureState : public FutureStateBase
{
//    The state never needs more than one of these at any one time, so don't
//  waste space or allocation time.
  union {
    struct {} mUndecided;  //  Included to make the active member unambiguous.
    T mObject;
    std::exception_ptr mException;
    std::function<void(void)> mFunction;
  };

  FutureState (void) noexcept
    : FutureStateBase(Type::kUndecided), mUndecided()
  {
  }

  FutureState (std::function<void(void)> && deferred_function)
    : FutureStateBase(Type::kDeferredFlag), mFunction(std::move(deferred_function))
  {
  }

  void deallocate_this (void) noexcept override
  {
    delete this;
  }

  template<class Arg>
  void set_value (Arg && arg)
  {
    assert(!(mType.load(std::memory_order_relaxed) & Type::kReadyFlag));
    new(&mObject) T (std::forward<Arg>(arg));
    mType.store(Type::kValueFlag | Type::kReadyFlag, std::memory_order_release);
  }
  template<class Arg>
  void set_exception (Arg && arg)
  {
    assert(!(mType.load(std::memory_order_relaxed) & Type::kReadyFlag));
    new(&mException) std::exception_ptr (std::forward<Arg>(arg));
    mType.store(Type::kExceptionFlag | Type::kReadyFlag, std::memory_order_release);
  }
//  These overloads set value/exception, but don't make it ready.
  template<class Arg>
  void set_value (Arg && arg, bool)
  {
    assert(!(mType.load(std::memory_order_relaxed) & Type::kReadyFlag));
    new(&mObject) T (std::forward<Arg>(arg));
    mType.store(Type::kValueFlag, std::memory_order_release);
  }
  template<class Arg>
  void set_exception (Arg && arg, bool)
  {
    assert(!(mType.load(std::memory_order_relaxed) & Type::kReadyFlag));
    new(&mException) std::exception_ptr (std::forward<Arg>(arg));
    mType.store(Type::kExceptionFlag, std::memory_order_release);
  }
 //private:
  ~FutureState (void)
  {
    auto type = mType.load(std::memory_order_acquire);
    switch (type & Type::kTypeMask)
    {
    case Type::kDeferredFlag:
      mFunction.~function();
      break;
    case Type::kValueFlag:
      mObject.~T();
      break;
    case Type::kExceptionFlag:
      mException.~exception_ptr();
      break;
    default:
      assert(type == Type::kUndecided);
    }
  }
};

template<class T, class Alloc>
struct FutureStateAllocated : public FutureState<T>
{
  typedef typename std::allocator_traits<Alloc>::void_pointer void_pointer;
  void_pointer mThis;
  Alloc mAllocator;

  FutureStateAllocated (Alloc const & alloc, void_pointer const & vptr) noexcept
    : FutureState<T>(), mThis(vptr), mAllocator(alloc)
  {
  }

  FutureStateAllocated (FutureStateAllocated<T,Alloc> const &) = delete;
  FutureStateAllocated<T,Alloc> & operator= (FutureStateAllocated<T,Alloc> const &) = delete;

  void deallocate_this (void) noexcept override
  {
    typedef typename std::allocator_traits<Alloc>::template rebind_traits<FutureStateAllocated<T, Alloc> > allocator_traits;
    typename allocator_traits::allocator_type alloc(std::move(mAllocator));
    typedef typename allocator_traits::pointer pointer;
    pointer ptr(static_cast<pointer>(mThis));
    allocator_traits::destroy(alloc, this);
    allocator_traits::deallocate(alloc, ptr, 1);
  }
};
} //  Namespace "detail"

#if (defined(__MINGW32__ ) && !defined(_GLIBCXX_HAS_GTHREADS))
}
namespace std {
#else
template<class T>
class future;
template<class T>
class shared_future;
template<class T>
class promise;
#endif

template<class T>
class future : mingw_stdthread::detail::FutureBase
{
  typedef mingw_stdthread::detail::FutureState<T> state_type;
  future (state_type * ptr) noexcept
    : FutureBase(ptr)
  {
  }

  friend class shared_future<T>;
  friend class promise<T>;

  template<class U>
  friend class future;

  template<class _Fn, class ... _Args>
  friend future<__async_result_of<_Fn, _Args...>> async (std::launch, _Fn &&, _Args&&...);
 public:
  using FutureBase::valid;
  using FutureBase::wait_for;
  using FutureBase::wait_until;

  future (void) noexcept
    : FutureBase(nullptr)
  {
  }
  future<T> & operator= (future<T> && source) noexcept
  {
//  Check for this atypical behavior rather than creating a nonsensical state.
    if (this != &source)
    {
      release();
      mState = source.mState;
      source.mState = nullptr;
    }
    return *this;
  }
  future (future<T> && source) noexcept
    : FutureBase(std::move(source))
  {
  }

  ~future (void) = default;

  future (future<T> const &) = delete;
  future<T> & operator= (future<T> const &) = delete;

  T const & get (void) const
  {
    wait();
    auto type = mState->mType.load(std::memory_order_acquire);
    if (type == (Type::kValueFlag | Type::kReadyFlag))
      return static_cast<state_type *>(mState)->mObject;
    else
    {
      assert(type == (Type::kExceptionFlag | Type::kReadyFlag));
      std::rethrow_exception(static_cast<state_type *>(mState)->mException);
    }
  }

  shared_future<T> share (void) noexcept;

  void wait (void) const
  {
    auto state = mState->mType.load(std::memory_order_relaxed);
    if (state & Type::kReadyFlag)
      return;
    std::unique_lock<mingw_stdthread::mutex> lock { get_mutex() };
    FutureBase::wait(lock);
    if (mState->mType.load(std::memory_order_acquire) & Type::kDeferredFlag)
    {
      state_type * ptr = static_cast<state_type *>(mState);
      decltype(ptr->mFunction) func = std::move(ptr->mFunction);
      ptr->mFunction.~function();
      func();
      lock.unlock();
      ptr->get_condition_variable().notify_all();
    }
  }
};

template<class T>
class shared_future : future<T>
{
  typedef typename future<T>::state_type state_type;
 public:
  using future<T>::get;
  using future<T>::wait;
  using future<T>::wait_for;
  using future<T>::wait_until;
  using future<T>::valid;

  shared_future (void) noexcept : future<T>()
  {
  }

  shared_future (shared_future<T> && source) noexcept
    : future<T>(std::move(source))
  {
  }

  shared_future<T> & operator= (shared_future<T> && source) noexcept
  {
    return future<T>::operator=(std::move(source));
  }

  shared_future (shared_future<T> const & source) noexcept(__cplusplus >= 201703L)
    : future<T>(static_cast<state_type *>(source.mState))
  {
    future<T>::mState->increment_references();
  }

  shared_future<T> & operator= (shared_future<T> const & source) noexcept(__cplusplus >= 201703L)
  {
    if (future<T>::mState == source.mState)
      return *this;
    future<T>::release();
    future<T>::mState = source.mState;
    future<T>::mState->increment_references();
    return *this;
  }

  shared_future (future<T> && source) noexcept
    : future<T>(std::move(source))
  {
  }

  shared_future<T> & operator= (future<T> && source) noexcept
  {
    future<T>::operator=(std::move(source));
    return *this;
  }

  ~shared_future (void) = default;
};

template<class T>
class promise : mingw_stdthread::detail::FutureBase
{
  bool mRetrieved;
  typedef mingw_stdthread::detail::FutureState<T> state_type;
  void check_before_set (void) const
  {
    if (!valid())
      throw future_error(future_errc::no_state);
    if (mState->mType.load(std::memory_order_relaxed) & Type::kReadyFlag)
      throw future_error(future_errc::promise_already_satisfied);
  }

  void check_abandon (void)
  {
    if (valid() && !(mState->mType.load(std::memory_order_relaxed) & Type::kReadyFlag))
    {
      set_exception(std::make_exception_ptr(future_error(future_errc::broken_promise)));
    }
  }
/// \bug Might throw more exceptions than specified by the standard...
//  Need OS support for this...
  void make_ready_at_thread_exit (void)
  {
    static constexpr DWORD kInfinite = 0xffffffffl;
//  Need to turn the pseudohandle from GetCurrentThread() into a true handle...
    HANDLE thread_handle;
    BOOL success = DuplicateHandle(GetCurrentProcess(),
                                   GetCurrentThread(),
                                   GetCurrentProcess(),
                                   &thread_handle,
                                   0, //  Access doesn't matter. Will be duplicated.
                                   FALSE, //  No need for this to be inherited.
                                   DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
    if (!success)
      throw std::runtime_error("MinGW STD Threads library failed to make a promise ready after thread exit.");

    mState->increment_references();
    bool handle_handled = false;
    try {
      state_type * ptr = static_cast<state_type *>(mState);
      mingw_stdthread::thread watcher_thread ([ptr, thread_handle, &handle_handled](void)
        {
          {
            std::lock_guard<mingw_stdthread::mutex> guard (ptr->get_mutex());
            handle_handled = true;
          }
          ptr->get_condition_variable().notify_all();
//  Wait for the original thread to die.
          WaitForSingleObject(thread_handle, kInfinite);
          CloseHandle(thread_handle);

          {
            std::lock_guard<mingw_stdthread::mutex> guard (ptr->get_mutex());
            ptr->mType.fetch_or(Type::kReadyFlag, std::memory_order_relaxed);
          }
          ptr->get_condition_variable().notify_all();

          ptr->decrement_references();
        });
      {
        std::unique_lock<mingw_stdthread::mutex> guard (ptr->get_mutex());
        ptr->get_condition_variable().wait(guard, [&handle_handled](void)->bool
          {
            return handle_handled;
          });
      }
      watcher_thread.detach();
    }
    catch (...)
    {
//    Because the original promise is still alive, this can't be the decrement
//  destroys it.
      mState->decrement_references();
      if (!handle_handled)
        CloseHandle(thread_handle);
    }
  }

  template<class U>
  future<U> make_future (void)
  {
    if (!valid())
      throw future_error(future_errc::no_state);
    if (mRetrieved)
      throw future_error(future_errc::future_already_retrieved);
    mState->increment_references();
    mRetrieved = true;
    return future<U>(static_cast<state_type *>(mState));
  }

  template<class U>
  friend class promise;
 public:
//    Create a promise with an empty state, with the reference counter set to
//  indicate that the state is only held by this promise (i.e. not by any
//  futures).
  promise (void)
    : FutureBase(new state_type ()), mRetrieved(false)
  {
  }

  template<typename Alloc>
  promise (std::allocator_arg_t, Alloc const & alloc)
    : FutureBase(nullptr), mRetrieved(false)
  {
    typedef mingw_stdthread::detail::FutureStateAllocated<T,Alloc> State;
    typedef typename std::allocator_traits<Alloc>::template rebind_traits<State> Traits;
    typename Traits::allocator_type rebound_alloc(alloc);
    typename Traits::pointer ptr = Traits::allocate(rebound_alloc, 1);
    typename Traits::void_pointer vptr = ptr;
    State * sptr = std::addressof(*ptr);
    Traits::construct(rebound_alloc, sptr, std::move(rebound_alloc), vptr);
    mState = static_cast<state_type *>(sptr);
  }

  promise (promise<T> && source) noexcept
    : FutureBase(std::move(source)), mRetrieved(source.mRetrieved)
  {
  }

  ~promise (void)
  {
    check_abandon();
  }

  promise<T> & operator= (promise<T> && source) noexcept
  {
    if (this == &source)
      return *this;
    check_abandon();
    release();
    mState = source.mState;
    mRetrieved = source.mRetrieved;
    source.mState = nullptr;
    return *this;
  }

  void swap (promise<T> & other) noexcept
  {
    std::swap(mState, other.mState);
    std::swap(mRetrieved, other.mRetrieved);
  }

  promise (promise<T> const &) = delete;
  promise<T> & operator= (promise<T> const &) = delete;

  future<T> get_future (void)
  {
    return make_future<T>();
  }

  void set_value (T const & value)
  {
    {
      std::lock_guard<mingw_stdthread::mutex> lock { get_mutex() };
      check_before_set();
      static_cast<state_type *>(mState)->set_value(value);
    }
    get_condition_variable().notify_all();
  }

  void set_value (T && value)
  {
    {
      std::lock_guard<mingw_stdthread::mutex> lock { get_mutex() };
      check_before_set();
      static_cast<state_type *>(mState)->set_value(std::move(value));
    }
    get_condition_variable().notify_all();
  }

  void set_value_at_thread_exit (T const & value)
  {
    {
      std::lock_guard<mingw_stdthread::mutex> lock { get_mutex() };
      check_before_set();
      static_cast<state_type *>(mState)->set_value(value, false);
    }
    make_ready_at_thread_exit();
  }

  void set_value_at_thread_exit (T && value)
  {
    {
      std::lock_guard<mingw_stdthread::mutex> lock { get_mutex() };
      check_before_set();
      static_cast<state_type *>(mState)->set_value(std::move(value), false);
    }
    make_ready_at_thread_exit();
  }

  void set_exception (std::exception_ptr eptr)
  {
    {
      std::lock_guard<mingw_stdthread::mutex> lock { get_mutex() };
      check_before_set();
      static_cast<state_type *>(mState)->set_exception(eptr);
    }
    get_condition_variable().notify_all();
  }

  void set_exception_at_thread_exit (std::exception_ptr eptr)
  {
    {
      std::lock_guard<mingw_stdthread::mutex> lock { get_mutex() };
      check_before_set();
      static_cast<state_type *>(mState)->set_exception(eptr, false);
    }
    make_ready_at_thread_exit();
  }
};

////////////////////////////////////////////////////////////////////////////////
//                           Reference Specialization                         //
////////////////////////////////////////////////////////////////////////////////

template<class T>
class future<T&> : future<void *>
{
  typedef future<void *> Base;
  template<class U>
  friend class shared_future;
  template<class U>
  friend class promise;

  future (typename Base::state_type * state)
    : Base(state)
  {
  }

  template<class _Fn, class ... _Args>
  friend future<__async_result_of<_Fn, _Args...>> async (std::launch, _Fn &&, _Args&&...);
 public:
  using Base::valid;
  using Base::wait_for;
  using Base::wait_until;
  using Base::wait;

  future (void) noexcept = default;

  inline T& get (void) const
  {
    return *static_cast<T *>(Base::get());
  }

  shared_future<T&> share (void) noexcept;
};

template<class T>
class shared_future<T&> : shared_future<void *>
{
  typedef shared_future<void *> Base;
 public:
  using Base::wait;
  using Base::wait_for;
  using Base::wait_until;
  using Base::valid;

  inline T& get (void) const
  {
    return *static_cast<T *>(Base::get());
  }

  shared_future (future<T&> && source) noexcept
    : Base(std::move(source))
  {
  }

  shared_future<T&> & operator= (future<T&> && source) noexcept
  {
    Base::operator=(std::move(source));
    return *this;
  }

  ~shared_future (void) = default;
};

template<class T>
class promise<T&> : private promise<void *>
{
  typedef promise<void *> Base;
 public:
  using Base::set_exception;
  using Base::set_exception_at_thread_exit;

  promise (void) = default;
  template<typename Alloc>
  promise (std::allocator_arg_t arg, Alloc const & alloc)
    : Base(arg, alloc)
  {
  }

  inline void set_value (T & value)
  {
    typedef typename std::remove_cv<T>::type T_non_cv;
    Base::set_value(const_cast<T_non_cv *>(std::addressof(value)));
  }

  inline void set_value_at_thread_exit (T & value)
  {
    typedef typename std::remove_cv<T>::type T_non_cv;
    Base::set_value_at_thread_exit(const_cast<T_non_cv *>(std::addressof(value)));
  }

  inline future<T&> get_future (void)
  {
    return Base::template make_future<T&>();
  }

  void swap (promise<T&> & other) noexcept
  {
    Base::swap(other);
  }
};

////////////////////////////////////////////////////////////////////////////////
//                              Void Specialization                           //
////////////////////////////////////////////////////////////////////////////////

template<>
class future<void> : future<mingw_stdthread::detail::Empty>
{
  typedef mingw_stdthread::detail::Empty Empty;
  template<class U>
  friend class shared_future;
  template<class U>
  friend class promise;

  future(future<Empty>::state_type * state)
    : future<Empty>(state)
  {
  }

  template<class _Fn, class ... _Args>
  friend future<__async_result_of<_Fn, _Args...>> async (std::launch, _Fn &&, _Args&&...);

 public:
  using future<Empty>::valid;
  using future<Empty>::wait_for;
  using future<Empty>::wait_until;
  using future<Empty>::wait;

  future (void) noexcept = default;

  void get (void) const
  {
    future<Empty>::get();
  }

  shared_future<void> share (void) noexcept;
};

template<>
class shared_future<void> : shared_future<mingw_stdthread::detail::Empty>
{
  typedef mingw_stdthread::detail::Empty Empty;
 public:
  using shared_future<Empty>::wait;
  using shared_future<Empty>::wait_for;
  using shared_future<Empty>::wait_until;
  using shared_future<Empty>::valid;

  void get (void) const
  {
    shared_future<Empty>::get();
  }

  shared_future (void) noexcept = default;

  shared_future (shared_future<void> && source) noexcept = default;

  shared_future<void> & operator= (shared_future<void> && source) noexcept = default;

  shared_future (shared_future<void> const & source) noexcept(__cplusplus >= 201703L) = default;

  shared_future<void> & operator= (shared_future<void> const & source) noexcept(__cplusplus >= 201703L) = default;

  shared_future (future<void> && source) noexcept
    : shared_future<Empty>(std::move(source))
  {
  }

  shared_future<void> & operator= (future<void> && source) noexcept
  {
    shared_future<Empty>::operator=(std::move(source));
    return *this;
  }

  ~shared_future (void) = default;
};

inline shared_future<void> future<void>::share (void) noexcept
{
  return shared_future<void>(std::move(*this));
}

template<class T>
shared_future<T> future<T>::share (void) noexcept
{
  return shared_future<T>(std::move(*this));
}

template<class T>
shared_future<T&> future<T&>::share (void) noexcept
{
  return shared_future<T&>(std::move(*this));
}

template<>
class promise<void> : private promise<mingw_stdthread::detail::Empty>
{
  typedef mingw_stdthread::detail::Empty Empty;
 public:
  using promise<Empty>::set_exception;
  using promise<Empty>::set_exception_at_thread_exit;

  promise (void) = default;
  template<typename Alloc>
  promise (std::allocator_arg_t arg, Alloc const & alloc)
    : promise<Empty>(arg, alloc)
  {
  }

  inline void set_value (void)
  {
    promise<Empty>::set_value(Empty());
  }

  inline void set_value_at_thread_exit (void)
  {
    promise<Empty>::set_value_at_thread_exit(Empty());
  }

  inline future<void> get_future (void)
  {
    return promise<Empty>::template make_future<void>();
  }

  void swap (promise<void> & other) noexcept
  {
    promise<Empty>::swap(other);
  }
};



template<class T>
void swap(promise<T> & lhs, promise<T> & rhs) noexcept
{
  lhs.swap(rhs);
}
} //  Namespace "std"

namespace mingw_stdthread
{
namespace detail
{
template<class Ret>
struct StorageHelper
{
  template<class Func, class ... Args>
  static void store_deferred (FutureState<Ret> * state_ptr, Func && func, Args&&... args)
  {
    try {
      state_ptr->set_value(invoke(std::forward<Func>(func), std::forward<Args>(args)...));
    } catch (...) {
      state_ptr->set_exception(std::current_exception());
    }
  }
  template<class Func, class ... Args>
  static void store (FutureState<Ret> * state_ptr, Func && func, Args&&... args)
  {
    try {
      auto result = invoke(std::forward<Func>(func), std::forward<Args>(args)...);
      std::lock_guard<mingw_stdthread::mutex> lock { state_ptr->get_mutex() };  //  Reveal the results of the above action to
      state_ptr->set_value(std::move(result));
    } catch (...) {
      std::lock_guard<mingw_stdthread::mutex> lock { state_ptr->get_mutex() };  //  Reveal the results of the above action to
      state_ptr->set_exception(std::current_exception());
    }
    state_ptr->get_condition_variable().notify_all();
  }
};

template<class Ref>
struct StorageHelper<Ref&>
{
  template<class Func, class ... Args>
  static void store_deferred (FutureState<void*> * state_ptr, Func && func, Args&&... args)
  {
    try {
      typedef typename std::remove_cv<Ref>::type Ref_non_cv;
      Ref & rf = invoke(std::forward<Func>(func), std::forward<Args>(args)...);
      state_ptr->set_value(const_cast<Ref_non_cv *>(std::addressof(rf)));
    } catch (...) {
      state_ptr->set_exception(std::current_exception());
    }
  }
  template<class Func, class ... Args>
  static void store (FutureState<void*> * state_ptr, Func && func, Args&&... args)
  {
    try {
      typedef typename std::remove_cv<Ref>::type Ref_non_cv;
      Ref & rf = invoke(std::forward<Func>(func), std::forward<Args>(args)...);
      std::lock_guard<mingw_stdthread::mutex> lock { state_ptr->get_mutex() };
      state_ptr->set_value(const_cast<Ref_non_cv *>(std::addressof(rf)));
    } catch (...) {
      std::lock_guard<mingw_stdthread::mutex> lock { state_ptr->get_mutex() };
      state_ptr->set_exception(std::current_exception());
    }
    state_ptr->get_condition_variable().notify_all();
  }
};

template<>
struct StorageHelper<void>
{
  template<class Func, class ... Args>
  static void store_deferred (FutureState<Empty> * state_ptr, Func && func, Args&&... args)
  {
    try {
      invoke(std::forward<Func>(func), std::forward<Args>(args)...);
      state_ptr->set_value(Empty{});
    } catch (...) {
      state_ptr->set_exception(std::current_exception());
    }
  }
  template<class Func, class ... Args>
  static void store (FutureState<Empty> * state_ptr, Func && func, Args&&... args)
  {
    try {
      invoke(std::forward<Func>(func), std::forward<Args>(args)...);
      std::lock_guard<mingw_stdthread::mutex> lock { state_ptr->get_mutex() };
      state_ptr->set_value(Empty{});
    } catch (...) {
      std::lock_guard<mingw_stdthread::mutex> lock { state_ptr->get_mutex() };
      state_ptr->set_exception(std::current_exception());
    }
    state_ptr->get_condition_variable().notify_all();
  }
};
} //  Namespace "detail"
} //  Namespace "mingw_stdthread"
namespace std
{


//    Unfortunately, MinGW's <future> locks us into a particular (non-standard)
//  signature for async.
template< class Function, class... Args>
/*#if (__cplusplus < 201703L)
std::future<std::result_of<std::decay<Function>::type(std::decay<Args>::type...)>::type>
#else
#if (__cplusplus > 201703L)
[[nodiscard]]
#endif
std::future<std::invoke_result_t<std::decay_t<Function>, std::decay_t<Args>...>>
#endif*/
#if (__cplusplus > 201703L)
[[nodiscard]]
#endif
std::future<__async_result_of<Function, Args...> >
  async(Function&& f, Args&&... args)
{
  return async(launch::async | launch::deferred, std::forward<Function>(f), std::forward<Args>(args)...);
}
template< class Function, class... Args >
/*#if (__cplusplus < 201703L)
std::future<std::result_of<std::decay<Function>::type(std::decay<Args>::type...)>::type>
#else
#if (__cplusplus > 201703L)
[[nodiscard]]
#endif
std::future<std::invoke_result_t<std::decay_t<Function>, std::decay_t<Args>...> >
#endif*/
#if (__cplusplus > 201703L)
[[nodiscard]]
#endif
std::future<__async_result_of<Function, Args...> >
  async(std::launch policy, Function&& f, Args&&... args)
{
  typedef __async_result_of<Function, Args...> result_type;
/*#if (__cplusplus < 201703L)
  typedef std::result_of<std::decay<Function>::type(std::decay<Args>::type...)>::type result_type;
#else
  typedef std::invoke_result_t<std::decay_t<Function>, std::decay_t<Args>...> result_type;
#endif*/
  typedef future<result_type> future_type;
  typedef typename future_type::state_type state_type;

  //auto setter = []

  state_type * state_ptr = nullptr;
  /*if ((policy & std::launch::async) == std::launch::async)
    state_ptr = new state_type ();
  else
    state_ptr = new state_type (std::function<result_type(void)>(std::bind(std::forward<Function>(f), std::forward<Args>(args)...)));*/


  if ((policy & std::launch::async) == std::launch::async)
  {
    auto deleter = [](state_type * ptr) { ptr->decrement_references(); };
    state_ptr = new state_type ();
    state_ptr->increment_references();
    std::unique_ptr<state_type, decltype(deleter)> ooptr { state_ptr, deleter };
    mingw_stdthread::thread t ([](decltype(ooptr) ptr, typename std::decay<Function>::type f2, typename std::decay<Args>::type... args2)
      {
        typedef mingw_stdthread::detail::StorageHelper<result_type> s_helper;
        s_helper::store(ptr.get(), f2, args2...);
      }, std::move(ooptr), std::forward<Function>(f), std::forward<Args>(args)...);
    t.detach();
  } else {
    typedef std::function<result_type(void)> func_type;
    struct Packed
    {
      func_type func;
      state_type * ptr;
    };
    std::shared_ptr<Packed>  bound { new Packed { std::bind(std::forward<Function>(f), std::forward<Args>(args)...), nullptr } };
    state_ptr = new state_type (std::function<void(void)>([bound](void)
      {
        typedef mingw_stdthread::detail::StorageHelper<result_type> s_helper;
        s_helper::store_deferred(bound->ptr, std::move(bound->func));
      }));
    bound->ptr = state_ptr;
  }
  assert(state_ptr != nullptr);
  return future<result_type> { state_ptr };
}

#if (defined(__MINGW32__ ) && !defined(_GLIBCXX_HAS_GTHREADS))
} //  Namespace std
namespace mingw_stdthread
{
using std::future;
using std::shared_future;
using std::promise;
using std::async;
#else
} //  Namespace mingw_stdthread
namespace std
{
template<class T>
void swap(mingw_stdthread::promise<T> & lhs, mingw_stdthread::promise<T> & rhs) noexcept
{
  lhs.swap(rhs);
}
#endif
} //  Namespace

template<class T, class Alloc>
struct std::uses_allocator<mingw_stdthread::promise<T>, Alloc> : ::std::true_type
{
};

#endif // MINGW_FUTURE_H_
