// <experimental/executor> -*- C++ -*-

// Copyright (C) 2015-2024 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, 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 General Public License for more details.

// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.

// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>.

/** @file experimental/executor
 *  This is a TS C++ Library header.
 *  @ingroup networking-ts
 */

#ifndef _GLIBCXX_EXPERIMENTAL_EXECUTOR
#define _GLIBCXX_EXPERIMENTAL_EXECUTOR 1

#pragma GCC system_header

#include <bits/requires_hosted.h> // experimental is currently omitted

#if __cplusplus >= 201402L

#include <algorithm>
#include <condition_variable>
#include <functional>
#include <future>
#include <list>
#include <queue>
#include <thread>
#include <tuple>
#include <unordered_map>
#include <experimental/netfwd>
#include <bits/unique_ptr.h>
#include <experimental/bits/net.h>

namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
namespace experimental
{
namespace net
{
inline namespace v1
{

  /** @addtogroup networking-ts
   *  @{
   */

  /// Customization point for asynchronous operations.
  template<typename _CompletionToken, typename _Signature, typename = void>
    class async_result;

  /// Convenience utility to help implement asynchronous operations.
  template<typename _CompletionToken, typename _Signature>
    class async_completion;

  template<typename _Tp, typename _ProtoAlloc, typename = __void_t<>>
    struct __associated_allocator_impl
    {
      using type = _ProtoAlloc;

      static type
      _S_get(const _Tp&, const _ProtoAlloc& __a) noexcept { return __a; }
    };

  template<typename _Tp, typename _ProtoAlloc>
    struct __associated_allocator_impl<_Tp, _ProtoAlloc,
				       __void_t<typename _Tp::allocator_type>>
    {
      using type = typename _Tp::allocator_type;

      static type
      _S_get(const _Tp& __t, const _ProtoAlloc&) noexcept
      { return __t.get_allocator(); }
    };

  /// Helper to associate an allocator with a type.
  template<typename _Tp, typename _ProtoAllocator = allocator<void>>
    struct associated_allocator
    : __associated_allocator_impl<_Tp, _ProtoAllocator>
    {
      static auto
      get(const _Tp& __t,
	  const _ProtoAllocator& __a = _ProtoAllocator()) noexcept
      {
	using _Impl = __associated_allocator_impl<_Tp, _ProtoAllocator>;
	return _Impl::_S_get(__t, __a);
      }
    };

  /// Alias template for associated_allocator.
  template<typename _Tp, typename _ProtoAllocator = allocator<void>>
    using associated_allocator_t
      = typename associated_allocator<_Tp, _ProtoAllocator>::type;

  // get_associated_allocator:

  template<typename _Tp>
    inline associated_allocator_t<_Tp>
    get_associated_allocator(const _Tp& __t) noexcept
    { return associated_allocator<_Tp>::get(__t); }

  template<typename _Tp, typename _ProtoAllocator>
    inline associated_allocator_t<_Tp, _ProtoAllocator>
    get_associated_allocator(const _Tp& __t,
			     const _ProtoAllocator& __a) noexcept
    { return associated_allocator<_Tp, _ProtoAllocator>::get(__t, __a); }

  enum class fork_event { prepare, parent, child };

  /// An extensible, type-safe, polymorphic set of services.
  class execution_context;

  class service_already_exists : public logic_error
  {
  public:
    // _GLIBCXX_RESOLVE_LIB_DEFECTS
    // 3414. service_already_exists has no usable constructors
    service_already_exists() : logic_error("service already exists") { }
  };

  template<typename _Tp> struct is_executor;

  struct executor_arg_t { };

  constexpr executor_arg_t executor_arg = executor_arg_t();

  /// Trait for determining whether to construct an object with an executor.
  template<typename _Tp, typename _Executor> struct uses_executor;

  template<typename _Tp, typename _Executor, typename = __void_t<>>
    struct __associated_executor_impl
    {
      using type = _Executor;

      static type
      _S_get(const _Tp&, const _Executor& __e) noexcept { return __e; }
    };

  template<typename _Tp, typename _Executor>
    struct __associated_executor_impl<_Tp, _Executor,
				       __void_t<typename _Tp::executor_type>>
    {
      using type = typename _Tp::executor_type;

      static type
      _S_get(const _Tp& __t, const _Executor&) noexcept
      { return __t.get_executor(); }
    };

  /// Helper to associate an executor with a type.
  template<typename _Tp, typename _Executor = system_executor>
    struct associated_executor
    : __associated_executor_impl<_Tp, _Executor>
    {
      static auto
      get(const _Tp& __t, const _Executor& __e = _Executor()) noexcept
      { return __associated_executor_impl<_Tp, _Executor>::_S_get(__t, __e); }
    };


  template<typename _Tp, typename _Executor = system_executor>
    using associated_executor_t
      = typename associated_executor<_Tp, _Executor>::type;

  template<typename _ExecutionContext>
    using __is_exec_context
      = is_convertible<_ExecutionContext&, execution_context&>;

  template<typename _Tp>
    using __executor_t = typename _Tp::executor_type;

  // get_associated_executor:

  template<typename _Tp>
    inline associated_executor_t<_Tp>
    get_associated_executor(const _Tp& __t) noexcept
    { return associated_executor<_Tp>::get(__t); }

  template<typename _Tp, typename _Executor>
    inline
    enable_if_t<is_executor<_Executor>::value,
		associated_executor_t<_Tp, _Executor>>
    get_associated_executor(const _Tp& __t, const _Executor& __ex)
    { return associated_executor<_Tp, _Executor>::get(__t, __ex); }

  template<typename _Tp, typename _ExecutionContext>
    inline
    enable_if_t<__is_exec_context<_ExecutionContext>::value,
		associated_executor_t<_Tp, __executor_t<_ExecutionContext>>>
    get_associated_executor(const _Tp& __t, _ExecutionContext& __ctx) noexcept
    { return net::get_associated_executor(__t, __ctx.get_executor()); }


  /// Helper to bind an executor to an object or function.
  template<typename _Tp, typename _Executor>
    class executor_binder;

  template<typename _Tp, typename _Executor, typename _Signature>
    class async_result<executor_binder<_Tp, _Executor>, _Signature>;

  template<typename _Tp, typename _Executor, typename _ProtoAllocator>
    struct associated_allocator<executor_binder<_Tp, _Executor>,
				_ProtoAllocator>;

  template<typename _Tp, typename _Executor, typename _Executor1>
    struct associated_executor<executor_binder<_Tp, _Executor>, _Executor1>;

  // bind_executor:

  template<typename _Executor, typename _Tp>
    inline
    enable_if_t<is_executor<_Executor>::value,
		executor_binder<decay_t<_Tp>, _Executor>>
    bind_executor(const _Executor& __ex, _Tp&& __t)
    { return { std::forward<_Tp>(__t), __ex }; }

  template<typename _ExecutionContext, typename _Tp>
    inline
    enable_if_t<__is_exec_context<_ExecutionContext>::value,
		executor_binder<decay_t<_Tp>, __executor_t<_ExecutionContext>>>
    bind_executor(_ExecutionContext& __ctx, _Tp&& __t)
    { return { __ctx.get_executor(), forward<_Tp>(__t) }; }


  /// A scope-guard type to record when work is started and finished.
  template<typename _Executor>
    class executor_work_guard;

  // make_work_guard:

  template<typename _Executor>
    inline
    enable_if_t<is_executor<_Executor>::value, executor_work_guard<_Executor>>
    make_work_guard(const _Executor& __ex)
    { return executor_work_guard<_Executor>(__ex); }

  template<typename _ExecutionContext>
    inline
    enable_if_t<__is_exec_context<_ExecutionContext>::value,
		executor_work_guard<__executor_t<_ExecutionContext>>>
    make_work_guard(_ExecutionContext& __ctx)
    { return net::make_work_guard(__ctx.get_executor()); }

  template<typename _Tp>
    inline
    enable_if_t<__not_<__or_<is_executor<_Tp>, __is_exec_context<_Tp>>>::value,
		executor_work_guard<associated_executor_t<_Tp>>>
    make_work_guard(const _Tp& __t)
    { return net::get_associated_executor(__t); }

  template<typename _Tp, typename _Up>
    auto
    make_work_guard(const _Tp& __t, _Up&& __u)
    -> decltype(net::make_work_guard(
	  net::get_associated_executor(__t, forward<_Up>(__u))))
    {
      return net::make_work_guard(
	  net::get_associated_executor(__t, forward<_Up>(__u)));
    }

  /// Allows function objects to execute on any thread.
  class system_executor;

  /// The execution context associated with system_executor objects.
  class system_context;

  inline bool
  operator==(const system_executor&, const system_executor&) { return true; }

  inline bool
  operator!=(const system_executor&, const system_executor&) { return false; }

  /// Exception thrown by empty executors.
  class bad_executor;

  /// Polymorphic wrapper for types satisfying the Executor requirements.
  class executor;

  bool
  operator==(const executor&, const executor&) noexcept;

  bool
  operator==(const executor&, nullptr_t) noexcept;

  bool
  operator==(nullptr_t, const executor&) noexcept;

  bool
  operator!=(const executor&, const executor&) noexcept;

  bool
  operator!=(const executor&, nullptr_t) noexcept;

  bool
  operator!=(nullptr_t, const executor&) noexcept;

  void swap(executor&, executor&) noexcept;

  // dispatch:

  template<typename _CompletionToken>
    __deduced_t<_CompletionToken, void()>
    dispatch(_CompletionToken&& __token);

  template<typename _Executor, typename _CompletionToken>
    __deduced_t<_CompletionToken, void()>
    dispatch(const _Executor& __ex, _CompletionToken&& __token);

  template<typename _ExecutionContext, typename _CompletionToken>
    __deduced_t<_CompletionToken, void()>
    dispatch(_ExecutionContext& __ctx, _CompletionToken&& __token);

  // post:

  template<typename _CompletionToken>
    __deduced_t<_CompletionToken, void()>
    post(_CompletionToken&& __token);
  template<typename _Executor, typename _CompletionToken>
    enable_if_t<is_executor<_Executor>::value,
		__deduced_t<_CompletionToken, void()>>
    post(const _Executor& __ex, _CompletionToken&& __token);
  template<typename _ExecutionContext, typename _CompletionToken>
    enable_if_t<__is_exec_context<_ExecutionContext>::value,
		__deduced_t<_CompletionToken, void()>>
    post(_ExecutionContext& __ctx, _CompletionToken&& __token);

  // defer:

  template<typename _CompletionToken>
    __deduced_t<_CompletionToken, void()>
    defer(_CompletionToken&& __token);
  template<typename _Executor, typename _CompletionToken>
    __deduced_t<_CompletionToken, void()>
    defer(const _Executor& __ex, _CompletionToken&& __token);
  template<typename _ExecutionContext, typename _CompletionToken>
    __deduced_t<_CompletionToken, void()>
    defer(_ExecutionContext& __ctx, _CompletionToken&& __token);

  template<typename _Executor>
    class strand;

  template<typename _Executor>
    bool
    operator==(const strand<_Executor>& __a, const strand<_Executor>& __b);

  template<typename _Executor>
    bool
    operator!=(const strand<_Executor>& __a, const strand<_Executor>& __b)
    { return !(__a == __b); }

  template<typename _CompletionToken, typename _Signature, typename>
    class async_result
    {
    public:
      using completion_handler_type = _CompletionToken;
      using return_type = void;

      explicit async_result(completion_handler_type&) {}
      async_result(const async_result&) = delete;
      async_result& operator=(const async_result&) = delete;

      return_type get() {}
    };

  template<typename _CompletionToken, typename _Signature>
    class async_completion
    {
      using __result_type
	= async_result<decay_t<_CompletionToken>, _Signature>;

    public:
      using completion_handler_type
	= typename __result_type::completion_handler_type;

    private:
      using __handler_type = __conditional_t<
	is_same<_CompletionToken, completion_handler_type>::value,
	completion_handler_type&,
	completion_handler_type>;

    public:
      explicit
      async_completion(_CompletionToken& __t)
      : completion_handler(std::forward<__handler_type>(__t)),
	result(completion_handler)
      { }

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

      __handler_type	completion_handler;
      __result_type	result;
    };


  class execution_context
  {
  public:
    class service
    {
    protected:
      // construct / copy / destroy:

      explicit
      service(execution_context& __owner) : _M_context(__owner) { }

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

      virtual ~service() { } // TODO should not be inline

      // service observers:

      execution_context& context() const noexcept { return _M_context; }

    private:
      // service operations:

      virtual void shutdown() noexcept = 0;
      virtual void notify_fork(fork_event) { }

      friend class execution_context;
      execution_context& _M_context;
    };

    // construct / copy / destroy:

    execution_context() { }

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

    virtual ~execution_context()
    {
      shutdown();
      destroy();
    }

    // execution context operations:

    void
    notify_fork(fork_event __e)
    {
      auto __l = [=](auto& __svc) { __svc._M_ptr->notify_fork(__e); };
      if (__e == fork_event::prepare)
	std::for_each(_M_services.rbegin(), _M_services.rend(), __l);
      else
	std::for_each(_M_services.begin(), _M_services.end(), __l);
    }

  protected:
    // execution context protected operations:

    void
    shutdown()
    {
      std::for_each(_M_services.rbegin(), _M_services.rend(),
	  [=](auto& __svc) {
	    if (__svc._M_active)
	      {
	        __svc._M_ptr->shutdown();
		__svc._M_active = false;
	      }
	  });
    }

    void
    destroy()
    {
      while (_M_services.size())
	_M_services.pop_back();
      _M_keys.clear();
    }

  protected:

    template<typename _Service>
      static void
      _S_deleter(service* __svc) { delete static_cast<_Service*>(__svc); }

    struct _ServicePtr
    {
      template<typename _Service>
	explicit
	_ServicePtr(_Service* __svc)
	: _M_ptr(__svc, &_S_deleter<_Service>), _M_active(true) { }

      std::unique_ptr<service, void(*)(service*)> _M_ptr;
      bool _M_active;
    };

#if defined(_GLIBCXX_HAS_GTHREADS)
    using mutex_type = std::mutex;
#else
    struct mutex_type
    {
      void lock() const { }
      void unlock() const { }
    };
#endif
    mutable mutex_type _M_mutex;

    // Sorted in order of beginning of service object lifetime.
    std::list<_ServicePtr> _M_services;

    template<typename _Service, typename... _Args>
      service*
      _M_add_svc(_Args&&... __args)
      {
	_M_services.push_back(
	    _ServicePtr{new _Service{*this, std::forward<_Args>(__args)...}} );
	return _M_services.back()._M_ptr.get();
      }

    using __key_type = void(*)();

    template<typename _Key>
      static __key_type
      _S_key() { return reinterpret_cast<__key_type>(&_S_key<_Key>); }

    std::unordered_map<__key_type, service*> _M_keys;

    template<typename _Service>
      friend typename _Service::key_type&
      use_service(execution_context&);

    template<typename _Service, typename... _Args>
      friend _Service&
      make_service(execution_context&, _Args&&...);

    template<typename _Service>
      friend bool
      has_service(const execution_context&) noexcept;
  };

  // service access:

  template<typename _Service>
    typename _Service::key_type&
    use_service(execution_context& __ctx)
    {
      using _Key = typename _Service::key_type;
      static_assert(is_base_of<execution_context::service, _Key>::value,
	  "a service type must derive from execution_context::service");
      static_assert(is_base_of<_Key, _Service>::value,
	  "a service type must match or derive from its key_type");
      auto __key = execution_context::_S_key<_Key>();
      lock_guard<execution_context::mutex_type> __lock(__ctx._M_mutex);
      auto& __svc = __ctx._M_keys[__key];
      if (__svc == nullptr)
	{
	  __try {
	    __svc = __ctx._M_add_svc<_Service>();
	  } __catch(...) {
	    __ctx._M_keys.erase(__key);
	    __throw_exception_again;
	  }
	}
      return static_cast<_Key&>(*__svc);
    }

  template<typename _Service, typename... _Args>
    _Service&
    make_service(execution_context& __ctx, _Args&&... __args)
    {
      using _Key = typename _Service::key_type;
      static_assert(is_base_of<execution_context::service, _Key>::value,
	  "a service type must derive from execution_context::service");
      static_assert(is_base_of<_Key, _Service>::value,
	  "a service type must match or derive from its key_type");
      auto __key = execution_context::_S_key<_Key>();
      lock_guard<execution_context::mutex_type> __lock(__ctx._M_mutex);
      auto& __svc = __ctx._M_keys[__key];
      if (__svc != nullptr)
	throw service_already_exists();
      __try {
	__svc = __ctx._M_add_svc<_Service>(std::forward<_Args>(__args)...);
      } __catch(...) {
	__ctx._M_keys.erase(__key);
	__throw_exception_again;
      }
      return static_cast<_Service&>(*__svc);
    }

  template<typename _Service>
    inline bool
    has_service(const execution_context& __ctx) noexcept
    {
      using _Key = typename _Service::key_type;
      static_assert(is_base_of<execution_context::service, _Key>::value,
	  "a service type must derive from execution_context::service");
      static_assert(is_base_of<_Key, _Service>::value,
	  "a service type must match or derive from its key_type");
      lock_guard<execution_context::mutex_type> __lock(__ctx._M_mutex);
      return __ctx._M_keys.count(execution_context::_S_key<_Key>());
    }

  template<typename _Tp, typename = __void_t<>>
    struct __is_executor_impl : false_type
    { };

  // Check Executor requirements.
  template<typename _Tp, typename _Up = remove_const_t<_Tp>>
    auto
    __executor_reqs(_Up* __x = 0, const _Up* __cx = 0, void(*__f)() = 0,
		    const allocator<int>& __a = {})
    -> enable_if_t<__is_value_constructible<_Tp>::value, __void_t<
      decltype(*__cx == *__cx),
      decltype(*__cx != *__cx),
      decltype(__x->context()),
      decltype(__x->on_work_started()),
      decltype(__x->on_work_finished()),
      decltype(__x->dispatch(std::move(__f), __a)),
      decltype(__x->post(std::move(__f), __a)),
      decltype(__x->defer(std::move(__f), __a))
    >>;

  template<typename _Tp>
    struct __is_executor_impl<_Tp, decltype(__executor_reqs<_Tp>())>
    : true_type
    { };

  template<typename _Tp>
    struct is_executor : __is_executor_impl<_Tp>
    { };

  template<typename _Tp>
    constexpr bool is_executor_v = is_executor<_Tp>::value;

  template<typename _Tp, typename _Executor, typename = __void_t<>>
    struct __uses_executor_impl : false_type
    { };

  template<typename _Tp, typename _Executor>
    struct __uses_executor_impl<_Tp, _Executor,
				__void_t<typename _Tp::executor_type>>
    : is_convertible<_Executor, typename _Tp::executor_type>
    { };

  template<typename _Tp, typename _Executor>
    struct uses_executor : __uses_executor_impl<_Tp, _Executor>::type
    { };

  template<typename _Tp, typename _Executor>
    constexpr bool uses_executor_v = uses_executor<_Tp, _Executor>::value;

  template<typename _Tp, typename _Executor>
    class executor_binder
    {
      struct __use_exec { };

    public:
      // types:

      using target_type = _Tp;
      using executor_type = _Executor;

      // construct / copy / destroy:

      executor_binder(_Tp __t, const _Executor& __ex)
      : executor_binder(__use_exec{}, std::move(__t), __ex)
      { }

      executor_binder(const executor_binder&) = default;
      executor_binder(executor_binder&&) = default;

      template<typename _Up, typename _OtherExecutor>
	executor_binder(const executor_binder<_Up, _OtherExecutor>& __other)
	: executor_binder(__use_exec{}, __other.get(), __other.get_executor())
	{ }

      template<typename _Up, typename _OtherExecutor>
	executor_binder(executor_binder<_Up, _OtherExecutor>&& __other)
	: executor_binder(__use_exec{}, std::move(__other.get()),
			  __other.get_executor())
	{ }

      template<typename _Up, typename _OtherExecutor>
	executor_binder(executor_arg_t, const _Executor& __ex,
			const executor_binder<_Up, _OtherExecutor>& __other)
	: executor_binder(__use_exec{}, __other.get(), __ex)
	{ }

      template<typename _Up, typename _OtherExecutor>
	executor_binder(executor_arg_t, const _Executor& __ex,
			executor_binder<_Up, _OtherExecutor>&& __other)
	: executor_binder(__use_exec{}, std::move(__other.get()), __ex)
	{ }

      ~executor_binder();

      // executor binder access:

      _Tp& get() noexcept { return _M_target; }
      const _Tp& get() const noexcept { return _M_target; }
      executor_type get_executor() const noexcept { return _M_ex; }

      // executor binder invocation:

      template<class... _Args>
	result_of_t<_Tp&(_Args&&...)>
	operator()(_Args&&... __args)
	{ return std::__invoke(get(), std::forward<_Args>(__args)...); }

      template<class... _Args>
	result_of_t<const _Tp&(_Args&&...)>
	operator()(_Args&&... __args) const
	{ return std::__invoke(get(), std::forward<_Args>(__args)...); }

    private:
      template<typename _Up>
	using __use_exec_cond
	  = __and_<uses_executor<_Tp, _Executor>,
		   is_constructible<_Tp, executor_arg_t, _Executor, _Up>>;

      template<typename _Up, typename _Exec, typename =
	       enable_if_t<__use_exec_cond<_Up>::value>>
	executor_binder(__use_exec, _Up&& __u, _Exec&& __ex)
	: _M_ex(std::forward<_Exec>(__ex)),
	  _M_target(executor_arg, _M_ex, std::forward<_Up>(__u))
	{ }

      template<typename _Up, typename _Exec, typename =
	       enable_if_t<!__use_exec_cond<_Up>::value>>
	executor_binder(__use_exec, _Up&& __u, const _Exec& __ex)
	: _M_ex(std::forward<_Exec>(__ex)),
	  _M_target(std::forward<_Up>(__u))
	{ }

      _Executor	_M_ex;
      _Tp	_M_target;
    };

  template<typename _Tp, typename _Executor, typename _Signature>
    class async_result<executor_binder<_Tp, _Executor>, _Signature>
    {
      using __inner = async_result<_Tp, _Signature>;

    public:
      using completion_handler_type =
	executor_binder<typename __inner::completion_handler_type, _Executor>;

      using return_type = typename __inner::return_type;

      explicit
      async_result(completion_handler_type& __h)
      : _M_target(__h.get()) { }

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

      return_type get() { return _M_target.get(); }

    private:
      __inner _M_target;
    };

  template<typename _Tp, typename _Executor, typename _ProtoAlloc>
    struct associated_allocator<executor_binder<_Tp, _Executor>, _ProtoAlloc>
    {
      using type = associated_allocator_t<_Tp, _ProtoAlloc>;

      static type
      get(const executor_binder<_Tp, _Executor>& __b,
	  const _ProtoAlloc& __a = _ProtoAlloc()) noexcept
      { return associated_allocator<_Tp, _ProtoAlloc>::get(__b.get(), __a); }
    };

  template<typename _Tp, typename _Executor, typename _Executor1>
    struct associated_executor<executor_binder<_Tp, _Executor>, _Executor1>
    {
      using type = _Executor;

      static type
      get(const executor_binder<_Tp, _Executor>& __b,
	  const _Executor1& = _Executor1()) noexcept
      { return __b.get_executor(); }
    };

  template<typename _Executor>
    class executor_work_guard
    {
    public:
      // types:

      using executor_type = _Executor;

      // construct / copy / destroy:

      explicit
      executor_work_guard(const executor_type& __ex) noexcept
      : _M_ex(__ex), _M_owns(true)
      { _M_ex.on_work_started(); }

      executor_work_guard(const executor_work_guard& __other) noexcept
      : _M_ex(__other._M_ex), _M_owns(__other._M_owns)
      {
	if (_M_owns)
	  _M_ex.on_work_started();
      }

      executor_work_guard(executor_work_guard&& __other) noexcept
      : _M_ex(__other._M_ex), _M_owns(__other._M_owns)
      { __other._M_owns = false; }

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

      ~executor_work_guard()
      {
	if (_M_owns)
	  _M_ex.on_work_finished();
      }

      // executor work guard observers:

      executor_type get_executor() const noexcept { return _M_ex; }

      bool owns_work() const noexcept { return _M_owns; }

      // executor work guard modifiers:

      void reset() noexcept
      {
	if (_M_owns)
	  _M_ex.on_work_finished();
	_M_owns = false;
      }

    private:
      _Executor	_M_ex;
      bool	_M_owns;
    };


  class system_context : public execution_context
  {
  public:
    // types:

    using executor_type = system_executor;

    // construct / copy / destroy:

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

    ~system_context()
    {
      stop();
      join();
    }

    // system_context operations:

    executor_type get_executor() noexcept;

    void stop()
    {
      lock_guard<mutex_type> __lock(_M_mtx);
      _M_stopped = true;
      _M_cv.notify_all();
    }

    bool stopped() const noexcept
    {
      lock_guard<mutex_type> __lock(_M_mtx);
      return _M_stopped;
    }

    void join()
    {
      if (_M_thread.joinable())
	_M_thread.join();
    }

  private:
    friend system_executor;

    struct __tag { explicit __tag() = default; };
    system_context(__tag) { }

#ifndef _GLIBCXX_HAS_GTHREADS
    struct thread
    {
      bool joinable() const { return false; }
      void join() { }
    };
    struct condition_variable
    {
      void notify_all() { }
    };
#endif

    thread			_M_thread;
    mutable mutex_type		_M_mtx; // XXX can we reuse base's _M_mutex?
    condition_variable		_M_cv;
    queue<function<void()>>	_M_tasks;
    bool			_M_stopped = false;

#ifdef _GLIBCXX_HAS_GTHREADS
    void
    _M_run()
    {
      while (true)
	{
	  function<void()> __f;
	  {
	    unique_lock<mutex_type> __lock(_M_mtx);
	    _M_cv.wait(__lock,
		       [this]{ return _M_stopped || !_M_tasks.empty(); });
	    if (_M_stopped)
	      return;
	    __f = std::move(_M_tasks.front());
	    _M_tasks.pop();
	  }
	  __f();
	}
    }
#endif

    void
    _M_post(std::function<void()> __f __attribute__((__unused__)))
    {
      lock_guard<mutex_type> __lock(_M_mtx);
      if (_M_stopped)
	return;
#ifdef _GLIBCXX_HAS_GTHREADS
      if (!_M_thread.joinable())
	_M_thread = std::thread(&system_context::_M_run, this);
      _M_tasks.push(std::move(__f)); // XXX allocator not used
      _M_cv.notify_one();
#else
      __throw_system_error(EOPNOTSUPP);
#endif
    }

    static system_context&
    _S_get() noexcept
    {
      static system_context __sc(__tag{});
      return __sc;
    }
  };

  class system_executor
  {
  public:
    // executor operations:

    system_executor() { }

    system_context&
    context() const noexcept { return system_context::_S_get(); }

    void on_work_started() const noexcept { }
    void on_work_finished() const noexcept { }

    template<typename _Func, typename _ProtoAlloc>
      void
      dispatch(_Func&& __f, const _ProtoAlloc& __a) const
      { decay_t<_Func>{std::forward<_Func>(__f)}(); }

    template<typename _Func, typename _ProtoAlloc>
      void
      post(_Func&& __f, const _ProtoAlloc&) const // XXX allocator not used
      {
	system_context::_S_get()._M_post(std::forward<_Func>(__f));
      }

    template<typename _Func, typename _ProtoAlloc>
      void
      defer(_Func&& __f, const _ProtoAlloc& __a) const
      { post(std::forward<_Func>(__f), __a); }
  };

  inline system_executor
  system_context::get_executor() noexcept
  { return {}; }

  class bad_executor : public std::exception
  {
    virtual const char* what() const noexcept { return "bad executor"; }
  };

  inline void __throw_bad_executor() // TODO make non-inline
  {
#if __cpp_exceptions
    throw bad_executor();
#else
    __builtin_abort();
#endif
  }

  class executor
  {
    template<typename _Executor>
      using _Context_t = decltype(std::declval<_Executor&>().context());

  public:
    // construct / copy / destroy:

    executor() noexcept = default;

    executor(nullptr_t) noexcept { }
    executor(const executor&) noexcept = default;
    executor(executor&&) noexcept = default;

    template<typename _Executor,
	     typename = _Require<is_lvalue_reference<_Context_t<_Executor>>>>
      executor(_Executor __e)
      : _M_target(make_shared<_Tgt1<_Executor>>(std::move(__e)))
      { }

    template<typename _Executor, typename _ProtoAlloc,
	     typename = _Require<is_lvalue_reference<_Context_t<_Executor>>>>
      executor(allocator_arg_t, const _ProtoAlloc& __a, _Executor __e)
      : _M_target(allocate_shared<_Tgt2<_Executor, _ProtoAlloc>>(__a,
	    std::move(__e), __a))
      { }

    executor& operator=(const executor&) noexcept = default;
    executor& operator=(executor&&) noexcept = default;

    executor&
    operator=(nullptr_t) noexcept
    {
      _M_target = nullptr;
      return *this;
    }

    template<typename _Executor>
      executor&
      operator=(_Executor __e)
      {
	executor(std::move(__e)).swap(*this);
	return *this;
      }

    ~executor() = default;

    // executor modifiers:

    void
    swap(executor& __other) noexcept
    { _M_target.swap(__other._M_target); }

    template<typename _Executor, typename _Alloc>
      void
      assign(_Executor __e, const _Alloc& __a)
      { executor(allocator_arg, __a, std::move(__e)).swap(*this); }

    // executor operations:

    execution_context&
    context() const noexcept
    {
      __glibcxx_assert( _M_target );
      return _M_target->context();
    }

    void
    on_work_started() const noexcept
    {
      __glibcxx_assert( _M_target );
      return _M_target->on_work_started();
    }

    void
    on_work_finished() const noexcept
    {
      __glibcxx_assert( _M_target );
      return _M_target->on_work_finished();
    }

    template<typename _Func, typename _Alloc>
      void
      dispatch(_Func&& __f, const _Alloc& __a) const
      {
	if (!_M_target)
	  __throw_bad_executor();
	// _M_target->dispatch({allocator_arg, __a, std::forward<_Func>(__f)});
	_M_target->dispatch(std::forward<_Func>(__f));
      }

    template<typename _Func, typename _Alloc>
      void
      post(_Func&& __f, const _Alloc& __a) const
      {
	if (!_M_target)
	  __throw_bad_executor();
	// _M_target->post({allocator_arg, __a, std::forward<_Func>(__f)});
	_M_target->post(std::forward<_Func>(__f));
      }

    template<typename _Func, typename _Alloc>
      void
      defer(_Func&& __f, const _Alloc& __a) const
      {
	if (!_M_target)
	  __throw_bad_executor();
	// _M_target->defer({allocator_arg, __a, std::forward<_Func>(__f)});
	_M_target->defer(std::forward<_Func>(__f));
      }

    // executor capacity:

    explicit operator bool() const noexcept
    { return static_cast<bool>(_M_target); }

    // executor target access:

#if __cpp_rtti
    const type_info&
    target_type() const noexcept
    {
      if (_M_target)
	return *static_cast<const type_info*>(_M_target->target_type());
      return typeid(void);
    }
#endif

    template<typename _Executor>
      _Executor*
      target() noexcept
      {
	void* __p = nullptr;
	if (_M_target)
	  {
	    if (_M_target->_M_func == &_Tgt1<remove_cv_t<_Executor>>::_S_func)
	      __p = _M_target->_M_func(_M_target.get(), nullptr);
#if __cpp_rtti
	    else
	      __p = _M_target->target(&typeid(_Executor));
#endif
	  }
	return static_cast<_Executor*>(__p);
      }

    template<typename _Executor>
      const _Executor*
      target() const noexcept
      {
	const void* __p = nullptr;
	if (_M_target)
	  {
	    if (_M_target->_M_func == &_Tgt1<remove_cv_t<_Executor>>::_S_func)
	      return (_Executor*)_M_target->_M_func(_M_target.get(), nullptr);
#if __cpp_rtti
	    else
	      __p = _M_target->target(&typeid(_Executor));
#endif
	  }
	return static_cast<const _Executor*>(__p);
      }

  private:
    struct _Tgt
    {
      virtual void on_work_started() const noexcept = 0;
      virtual void on_work_finished() const noexcept = 0;
      virtual execution_context& context() const noexcept = 0;
      virtual void dispatch(std::function<void()>) const = 0;
      virtual void post(std::function<void()>) const = 0;
      virtual void defer(std::function<void()>) const = 0;
      virtual const void* target_type() const noexcept = 0;
      virtual void* target(const void*) noexcept = 0;
      virtual bool _M_equals(_Tgt*) const noexcept = 0;

      using _Func = void* (_Tgt*, const _Tgt*);
      _Func* _M_func; // Provides access to target without RTTI
    };

    template<typename _Ex>
      struct _Tgt1 : _Tgt
      {
	explicit
	_Tgt1(_Ex&& __ex)
	: _M_ex(std::move(__ex))
	{ this->_M_func = &_S_func; }

	void
	on_work_started() const noexcept override
	{ _M_ex.on_work_started(); }

	void
	on_work_finished() const noexcept override
	{ _M_ex.on_work_finished(); }

	execution_context&
	context() const noexcept override
	{ return _M_ex.context(); }

	void
	dispatch(std::function<void()> __f) const override
	{ _M_ex.dispatch(std::move(__f), allocator<void>()); }

	void
	post(std::function<void()> __f) const override
	{ _M_ex.post(std::move(__f), allocator<void>()); }

	void
	defer(std::function<void()> __f) const override
	{ _M_ex.defer(std::move(__f), allocator<void>()); }

	const void*
	target_type() const noexcept override
	{
#if __cpp_rtti
	  return &typeid(_Ex);
#else
	  return nullptr;
#endif
	}

	void*
	target(const void* __ti) noexcept override
	{
#if __cpp_rtti
	  if (*static_cast<const type_info*>(__ti) == typeid(_Ex))
	    return std::__addressof(_M_ex);
#endif
	  return nullptr;
	}

	bool
	_M_equals(_Tgt* __tgt) const noexcept override
	{
#if __cpp_rtti
	  if (const void* __p = __tgt->target(&typeid(_Ex)))
	    return *static_cast<const _Ex*>(__p) == _M_ex;
#endif
	  return false;
	}

	_Ex _M_ex [[__no_unique_address__]];

	static void*
	_S_func(_Tgt* __p, const _Tgt* __q) noexcept
	{
	  auto& __ex = static_cast<_Tgt1*>(__p)->_M_ex;
	  if (__q)
	    {
	      if (__ex == static_cast<const _Tgt1*>(__q)->_M_ex)
		return __p;
	      else
		return nullptr;
	    }
	  else
	    return std::__addressof(__ex);
	}
      };

    template<typename _Ex, typename _Alloc>
      struct _Tgt2 : _Tgt1<_Ex>
      {
	explicit
	_Tgt2(_Ex&& __ex, const _Alloc& __a)
	: _Tgt1<_Ex>(std::move(__ex)), _M_alloc(__a) { }

	void
	dispatch(std::function<void()> __f) const override
	{ this->_M_ex.dispatch(std::move(__f), _M_alloc); }

	void
	post(std::function<void()> __f) const override
	{ this->_M_ex.post(std::move(__f), _M_alloc); }

	void
	defer(std::function<void()> __f) const override
	{ this->_M_ex.defer(std::move(__f), _M_alloc); }

	_Alloc _M_alloc [[__no_unique_address__]];
      };

    // Partial specialization for std::allocator<T>.
    // Don't store the allocator.
    template<typename _Ex, typename _Tp>
      struct _Tgt2<_Ex, std::allocator<_Tp>> : _Tgt1<_Ex>
      { };

    friend bool
    operator==(const executor& __a, const executor& __b) noexcept
    {
      _Tgt* __ta = __a._M_target.get();
      _Tgt* __tb = __b._M_target.get();
      if (__ta == __tb)
	return true;
      if (!__ta || !__tb)
	return false;
      if (__ta->_M_func == __tb->_M_func)
	return __ta->_M_func(__ta, __tb);
      return __ta->_M_equals(__tb);
    }

    shared_ptr<_Tgt> _M_target;
  };

  template<> struct is_executor<executor> : true_type { };

  /// executor comparisons
  inline bool
  operator==(const executor& __e, nullptr_t) noexcept
  { return !__e; }

  inline bool
  operator==(nullptr_t, const executor& __e) noexcept
  { return !__e; }

  inline bool
  operator!=(const executor& __a, const executor& __b) noexcept
  { return !(__a == __b); }

  inline bool
  operator!=(const executor& __e, nullptr_t) noexcept
  { return (bool)__e; }

  inline bool
  operator!=(nullptr_t, const executor& __e) noexcept
  { return (bool)__e; }

  /// Swap two executor objects.
  inline void swap(executor& __a, executor& __b) noexcept { __a.swap(__b); }


  template<typename _CompletionHandler>
    struct __dispatcher
    {
      explicit
      __dispatcher(_CompletionHandler& __h)
      : _M_h(std::move(__h)), _M_w(net::make_work_guard(_M_h))
      { }

      void operator()()
      {
	auto __alloc = net::get_associated_allocator(_M_h);
	_M_w.get_executor().dispatch(std::move(_M_h), __alloc);
	_M_w.reset();
      }

      _CompletionHandler _M_h;
      decltype(net::make_work_guard(_M_h)) _M_w;
    };

  template<typename _CompletionHandler>
    inline __dispatcher<_CompletionHandler>
    __make_dispatcher(_CompletionHandler& __h)
    { return __dispatcher<_CompletionHandler>{__h}; }



  // dispatch:

  template<typename _CompletionToken>
    inline __deduced_t<_CompletionToken, void()>
    dispatch(_CompletionToken&& __token)
    {
      async_completion<_CompletionToken, void()> __cmpl{__token};
      auto __ex = net::get_associated_executor(__cmpl.completion_handler);
      auto __alloc = net::get_associated_allocator(__cmpl.completion_handler);
      __ex.dispatch(std::move(__cmpl.completion_handler), __alloc);
      return __cmpl.result.get();
    }

  template<typename _Executor, typename _CompletionToken>
    inline
    enable_if_t<is_executor<_Executor>::value,
		__deduced_t<_CompletionToken, void()>>
    dispatch(const _Executor& __ex, _CompletionToken&& __token)
    {
      async_completion<_CompletionToken, void()> __cmpl{__token};
      auto __alloc = net::get_associated_allocator(__cmpl.completion_handler);
      __ex.dispatch(net::__make_dispatcher(__cmpl.completion_handler),
		    __alloc);
      return __cmpl.result.get();
    }

  template<typename _ExecutionContext, typename _CompletionToken>
    inline
    enable_if_t<__is_exec_context<_ExecutionContext>::value,
		__deduced_t<_CompletionToken, void()>>
    dispatch(_ExecutionContext& __ctx, _CompletionToken&& __token)
    {
      return net::dispatch(__ctx.get_executor(),
			   forward<_CompletionToken>(__token));
    }

  // post:

  template<typename _CompletionToken>
    inline __deduced_t<_CompletionToken, void()>
    post(_CompletionToken&& __token)
    {
      async_completion<_CompletionToken, void()> __cmpl{__token};
      auto __ex = net::get_associated_executor(__cmpl.completion_handler);
      auto __alloc = net::get_associated_allocator(__cmpl.completion_handler);
      __ex.post(std::move(__cmpl.completion_handler), __alloc);
      return __cmpl.result.get();
    }

  template<typename _Executor, typename _CompletionToken>
    inline
    enable_if_t<is_executor<_Executor>::value,
		__deduced_t<_CompletionToken, void()>>
    post(const _Executor& __ex, _CompletionToken&& __token)
    {
      async_completion<_CompletionToken, void()> __cmpl{__token};
      auto __alloc = net::get_associated_allocator(__cmpl.completion_handler);
      __ex.post(net::__make_dispatcher(__cmpl.completion_handler), __alloc);
      return __cmpl.result.get();
    }

  template<typename _ExecutionContext, typename _CompletionToken>
    inline
    enable_if_t<__is_exec_context<_ExecutionContext>::value,
		__deduced_t<_CompletionToken, void()>>
    post(_ExecutionContext& __ctx, _CompletionToken&& __token)
    {
      return net::post(__ctx.get_executor(),
		       forward<_CompletionToken>(__token));
    }

  // defer:

  template<typename _CompletionToken>
    inline __deduced_t<_CompletionToken, void()>
    defer(_CompletionToken&& __token)
    {
      async_completion<_CompletionToken, void()> __cmpl{__token};
      auto __ex = net::get_associated_executor(__cmpl.completion_handler);
      auto __alloc = net::get_associated_allocator(__cmpl.completion_handler);
      __ex.defer(std::move(__cmpl.completion_handler), __alloc);
      return __cmpl.result.get();
    }

  template<typename _Executor, typename _CompletionToken>
    inline
    enable_if_t<is_executor<_Executor>::value,
		__deduced_t<_CompletionToken, void()>>
    defer(const _Executor& __ex, _CompletionToken&& __token)
    {
      async_completion<_CompletionToken, void()> __cmpl{__token};
      auto __alloc = net::get_associated_allocator(__cmpl.completion_handler);
      __ex.defer(net::__make_dispatcher(__cmpl.completion_handler), __alloc);
      return __cmpl.result.get();
    }

  template<typename _ExecutionContext, typename _CompletionToken>
    inline
    enable_if_t<__is_exec_context<_ExecutionContext>::value,
		__deduced_t<_CompletionToken, void()>>
    defer(_ExecutionContext& __ctx, _CompletionToken&& __token)
    {
      return net::defer(__ctx.get_executor(),
			forward<_CompletionToken>(__token));
    }


  template<typename _Executor>
    class strand
    {
    public:
      // types:

      using inner_executor_type = _Executor;

      // construct / copy / destroy:

      strand(); // TODO make state

      explicit strand(_Executor __ex) : _M_inner_ex(__ex) { } // TODO make state

      template<typename _Alloc>
	strand(allocator_arg_t, const _Alloc& __a, _Executor __ex)
	: _M_inner_ex(__ex) { } // TODO make state

      strand(const strand& __other) noexcept
      : _M_state(__other._M_state), _M_inner_ex(__other._M_inner_ex) { }

      strand(strand&& __other) noexcept
      : _M_state(std::move(__other._M_state)),
	_M_inner_ex(std::move(__other._M_inner_ex)) { }

      template<typename _OtherExecutor>
	strand(const strand<_OtherExecutor>& __other) noexcept
	: _M_state(__other._M_state), _M_inner_ex(__other._M_inner_ex) { }

      template<typename _OtherExecutor>
	strand(strand<_OtherExecutor>&& __other) noexcept
	: _M_state(std::move(__other._M_state)),
	  _M_inner_ex(std::move(__other._M_inner_ex)) { }

      strand&
      operator=(const strand& __other) noexcept
      {
	static_assert(is_copy_assignable<_Executor>::value,
		      "inner executor type must be CopyAssignable");

	// TODO lock __other
	// TODO copy state
	_M_inner_ex = __other._M_inner_ex;
	return *this;
      }

      strand&
      operator=(strand&& __other) noexcept
      {
	static_assert(is_move_assignable<_Executor>::value,
		      "inner executor type must be MoveAssignable");

	// TODO move state
	_M_inner_ex = std::move(__other._M_inner_ex);
	return *this;
      }

      template<typename _OtherExecutor>
	strand&
	operator=(const strand<_OtherExecutor>& __other) noexcept
	{
	  static_assert(is_convertible<_OtherExecutor, _Executor>::value,
			"inner executor type must be compatible");

	  // TODO lock __other
	  // TODO copy state
	  _M_inner_ex = __other._M_inner_ex;
	  return *this;
	}

      template<typename _OtherExecutor>
	strand&
	operator=(strand<_OtherExecutor>&& __other) noexcept
	{
	  static_assert(is_convertible<_OtherExecutor, _Executor>::value,
			"inner executor type must be compatible");

	  // TODO move state
	  _M_inner_ex = std::move(__other._M_inner_ex);
	  return *this;
	}

      ~strand()
      {
	// the task queue outlives this object if non-empty
	// TODO create circular ref in queue?
      }

      // strand operations:

      inner_executor_type
      get_inner_executor() const noexcept
      { return _M_inner_ex; }

      bool
      running_in_this_thread() const noexcept
      { return _M_state->running_in_this_thread(); }

      execution_context&
      context() const noexcept
      { return _M_inner_ex.context(); }

      void on_work_started() const noexcept { _M_inner_ex.on_work_started(); }
      void on_work_finished() const noexcept { _M_inner_ex.on_work_finished(); }

      template<typename _Func, typename _Alloc>
	void
	dispatch(_Func&& __f, const _Alloc& __a) const
	{
	  if (running_in_this_thread())
	    decay_t<_Func>{std::forward<_Func>(__f)}();
	  else
	    post(std::forward<_Func>(__f), __a);
	}

      template<typename _Func, typename _Alloc>
	void
	post(_Func&& __f, const _Alloc& __a) const; // TODO

      template<typename _Func, typename _Alloc>
	void
	defer(_Func&& __f, const _Alloc& __a) const
	{ post(std::forward<_Func>(__f), __a); }

    private:
      friend bool
      operator==(const strand& __a, const strand& __b)
      { return __a._M_state == __b._M_state; }

      // TODO add synchronised queue
      struct _State
      {
#if defined(_GLIBCXX_HAS_GTHREADS)
	bool
	running_in_this_thread() const noexcept
	{ return std::this_thread::get_id() == _M_running_on; }

	std::thread::id _M_running_on;
#else
	bool running_in_this_thread() const { return true; }
#endif
      };
      shared_ptr<_State> _M_state;
      _Executor _M_inner_ex;
    };

#if defined(_GLIBCXX_HAS_GTHREADS)

  // Completion token for asynchronous operations initiated with use_future.
  template<typename _Func, typename _Alloc>
    struct __use_future_ct
    {
      std::tuple<_Func, _Alloc> _M_t;
    };

  template<typename _Func, typename _Tp>
    struct __use_future_ct<_Func, std::allocator<_Tp>>
    {
      _Func _M_f;
    };

  template<typename _ProtoAllocator = allocator<void>>
    class use_future_t
    {
    public:
      // use_future_t types:
      using allocator_type = _ProtoAllocator;

      // use_future_t members:
      constexpr
      use_future_t()
      noexcept(is_nothrow_default_constructible<_ProtoAllocator>::value)
      : _M_alloc() { }

      explicit
      use_future_t(const _ProtoAllocator& __a) noexcept : _M_alloc(__a) { }

      template<typename _OtherAllocator>
	use_future_t<_OtherAllocator>
	rebind(const _OtherAllocator& __a) const noexcept
	{ return use_future_t<_OtherAllocator>(__a); }

      allocator_type get_allocator() const noexcept { return _M_alloc; }

      template<typename _Func>
	auto
	operator()(_Func&& __f) const
	{
	  using _Token = __use_future_ct<decay_t<_Func>, _ProtoAllocator>;
	  return _Token{ {std::forward<_Func>(__f), _M_alloc} };
	}

    private:
      _ProtoAllocator _M_alloc;
    };

  template<typename _Tp>
    class use_future_t<std::allocator<_Tp>>
    {
    public:
      // use_future_t types:
      using allocator_type = std::allocator<_Tp>;

      // use_future_t members:
      constexpr use_future_t() noexcept = default;

      explicit
      use_future_t(const allocator_type& __a) noexcept { }

      template<class _Up>
	use_future_t<std::allocator<_Up>>
	rebind(const std::allocator<_Up>& __a) const noexcept
	{ return use_future_t<std::allocator<_Up>>(__a); }

      allocator_type get_allocator() const noexcept { return {}; }

      template<typename _Func>
	auto
	operator()(_Func&& __f) const
	{
	  using _Token = __use_future_ct<decay_t<_Func>, allocator_type>;
	  return _Token{std::forward<_Func>(__f)};
	}
    };

  constexpr use_future_t<> use_future = use_future_t<>();

  template<typename _Func, typename _Alloc, typename _Res, typename... _Args>
    class async_result<__use_future_ct<_Func, _Alloc>, _Res(_Args...)>;

  template<typename _Result, typename _Executor>
    struct __use_future_ex;

  // Completion handler for asynchronous operations initiated with use_future.
  template<typename _Func, typename... _Args>
    struct __use_future_ch
    {
      template<typename _Alloc>
	explicit
	__use_future_ch(__use_future_ct<_Func, _Alloc>&& __token)
	: _M_f{ std::move(std::get<0>(__token._M_t)) },
	  _M_promise{ std::get<1>(__token._M_t) }
	{ }

      template<typename _Tp>
	explicit
	__use_future_ch(__use_future_ct<_Func, std::allocator<_Tp>>&& __token)
	: _M_f{ std::move(__token._M_f) }
	{ }

      void
      operator()(_Args&&... __args)
      {
	__try
	  {
	    _M_promise.set_value(_M_f(std::forward<_Args>(__args)...));
	  }
	__catch(__cxxabiv1::__forced_unwind&)
	  {
	    __throw_exception_again;
	  }
	__catch(...)
	  {
	    _M_promise.set_exception(std::current_exception());
	  }
      }

      using __result = result_of_t<_Func(decay_t<_Args>...)>;

      future<__result> get_future() { return _M_promise.get_future(); }

    private:
      template<typename _Result, typename _Executor>
	friend struct __use_future_ex;

      _Func _M_f;
      mutable promise<__result> _M_promise;
    };

  // Specialization of async_result for operations initiated with use_future.
  template<typename _Func, typename _Alloc, typename _Res, typename... _Args>
    class async_result<__use_future_ct<_Func, _Alloc>, _Res(_Args...)>
    {
    public:
      using completion_handler_type = __use_future_ch<_Func, _Args...>;
      using return_type = future<typename completion_handler_type::__result>;

      explicit
      async_result(completion_handler_type& __h)
      : _M_future(__h.get_future())
      { }

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

      return_type get() { return std::move(_M_future); }

    private:
      return_type _M_future;
    };

  template<typename _Result, typename _Executor>
    struct __use_future_ex
    {
      template<typename _Handler>
      __use_future_ex(const _Handler& __h, _Executor __ex)
      : _M_t(__h._M_promise, __ex)
      { }

      template<typename _Fn, typename _Alloc>
	void
	dispatch(_Fn&& __fn)
	{
	  __try
	    {
	      std::get<1>(_M_t).dispatch(std::forward<_Fn>(__fn));
	    }
	  __catch(__cxxabiv1::__forced_unwind&)
	    {
	      __throw_exception_again;
	    }
	  __catch(...)
	    {
	      std::get<0>(_M_t).set_exception(std::current_exception());
	    }
	}

      template<typename _Fn, typename _Alloc>
	void
	post(_Fn&& __fn)
	{
	  __try
	    {
	      std::get<1>(_M_t).post(std::forward<_Fn>(__fn));
	    }
	  __catch(__cxxabiv1::__forced_unwind&)
	    {
	      __throw_exception_again;
	    }
	  __catch(...)
	    {
	      std::get<0>(_M_t).set_exception(std::current_exception());
	    }
	}

      template<typename _Fn, typename _Alloc>
	void
	defer(_Fn&& __fn)
	{
	  __try
	    {
	      std::get<1>(_M_t).defer(std::forward<_Fn>(__fn));
	    }
	  __catch(__cxxabiv1::__forced_unwind&)
	    {
	      __throw_exception_again;
	    }
	  __catch(...)
	    {
	      std::get<0>(_M_t).set_exception(std::current_exception());
	    }
	}

    private:
      tuple<promise<_Result>&, _Executor> _M_t;
    };

  template<typename _Func, typename... _Args, typename _Executor>
    struct associated_executor<__use_future_ch<_Func, _Args...>, _Executor>
    {
    private:
      using __handler = __use_future_ch<_Func, _Args...>;

      using type = __use_future_ex<typename __handler::__result, _Executor>;

      static type
      get(const __handler& __h, const _Executor& __ex)
      { return { __h, __ex }; }
    };

#if 0

  // [async.use.future.traits]
  template<typename _Allocator, typename _Ret, typename... _Args>
    class handler_type<use_future_t<_Allocator>, _Ret(_Args...)> // TODO uglify name
    {
      template<typename... _Args>
	struct __is_error_result : false_type { };

      template<typename... _Args>
	struct __is_error_result<error_code, _Args...> : true_type { };

      template<typename... _Args>
	struct __is_error_result<exception_ptr, _Args...> : true_type { };

      static exception_ptr
      _S_exptr(exception_ptr& __ex)
      { return std::move(__ex); }

      static exception_ptr
      _S_exptr(const error_code& __ec)
      { return make_exception_ptr(system_error(__ec)); }

      template<bool _IsError, typename... _UArgs>
	struct _Type;

      // N == 0
      template<bool _IsError>
	struct _Type<_IsError>
	{
	  std::promise<void> _M_promise;

	  void
	  operator()()
	  {
	    _M_promise.set_value();
	  }
	};

      // N == 1, U0 is error_code or exception_ptr
      template<typename _UArg0>
	struct _Type<true, _UArg0>
	{
	  std::promise<void> _M_promise;

	  template<typename _Arg0>
	    void
	    operator()(_Arg0&& __a0)
	    {
	      if (__a0)
		_M_promise.set_exception(_S_exptr(__a0));
	      else
		_M_promise.set_value();
	    }
	};

      // N == 1, U0 is not error_code or exception_ptr
      template<typename _UArg0>
	struct _Type<false, _UArg0>
	{
	  std::promise<_UArg0> _M_promise;

	  template<typename _Arg0>
	    void
	    operator()(_Arg0&& __a0)
	    {
	      _M_promise.set_value(std::forward<_Arg0>(__a0));
	    }
	};

      // N == 2, U0 is error_code or exception_ptr
      template<typename _UArg0, typename _UArg1>
	struct _Type<true, _UArg0, _UArg1>
	{
	  std::promise<_UArg1> _M_promise;

	  template<typename _Arg0, typename _Arg1>
	    void
	    operator()(_Arg0&& __a0, _Arg1&& __a1)
	    {
	      if (__a0)
		_M_promise.set_exception(_S_exptr(__a0));
	      else
		_M_promise.set_value(std::forward<_Arg1>(__a1));
	    }
	};

      // N >= 2, U0 is not error_code or exception_ptr
      template<typename... _UArgs>
	struct _Type<false, _UArgs...>
	{
	  static_assert(sizeof...(_UArgs) > 1, "wrong partial specialization");

	  std::promise<tuple<_UArgs...>> _M_promise;

	  template<typename... _Args>
	    void
	    operator()(_Args&&... __args)
	    {
	      _M_promise.set_value(
		  std::forward_as_tuple(std::forward<_Args>(__args)...));
	    }
	};

      // N > 2, U0 is error_code or exception_ptr
      template<typename _UArg0, typename... _UArgs>
	struct _Type<true, _UArg0, _UArgs...>
	{
	  static_assert(sizeof...(_UArgs) > 1, "wrong partial specialization");

	  std::promise<tuple<_UArgs...>> _M_promise;

	  template<typename _Arg0, typename... _Args>
	    void
	    operator()(_Arg0&& __a0, _Args&&... __args)
	    {
	      if (__a0)
		_M_promise.set_exception(_S_exptr(__a0));
	      else
		_M_promise.set_value(
		    std::forward_as_tuple(std::forward<_Args>(__args)...));
	    }
	};

    public:
      using type =
	_Type<__is_error_result<_Args...>::value, decay_t<_Args>...>;
    };


  template<typename _Alloc, typename _Ret, typename... _Args>
    struct async_result<use_future_t<_Alloc>, _Ret(_Args...)>
    {
      using completion_handler_type
	= typename handler_type<use_future_t<_Alloc>, _Ret(_Args...)>::type;

      using return_type = void; // XXX TODO ???;

      explicit
      async_result(completion_handler_type& __h) : _M_handler(__h) { }

      auto get() { return _M_handler._M_provider.get_future(); }

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

      return_type get() { return _M_handler._M_promise.get_future(); }

    private:
      completion_handler_type& _M_handler;
    };

  // TODO specialize associated_executor for
  // async_result<use_future_t<A>, Sig>::completion_handler_type
  // to use a __use_future_ex
  // (probably need to move _Type outside of handler_type so we don't have
  // a non-deduced context)

#endif

  // [async.packaged.task.specializations]
  template<typename _Ret, typename... _Args, typename _Signature>
    class async_result<packaged_task<_Ret(_Args...)>, _Signature>
    {
    public:
      using completion_handler_type = packaged_task<_Ret(_Args...)>;
      using return_type = future<_Ret>;

      explicit
      async_result(completion_handler_type& __h)
      : _M_future(__h.get_future()) { }

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

      return_type get() { return std::move(_M_future); }

    private:
      return_type _M_future;
    };

#endif // _GLIBCXX_HAS_GTHREADS

  /// @}

} // namespace v1
} // namespace net
} // namespace experimental

  template<typename _Alloc>
    struct uses_allocator<experimental::net::executor, _Alloc>
    : true_type {};

_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std

#endif // C++14

#endif // _GLIBCXX_EXPERIMENTAL_EXECUTOR
