//
// strand
// ~~~~~~
// Strand used for preventing non-concurrent invocation of handlers.
//
// Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef EXECUTORS_EXPERIMENTAL_STRAND_HEADER
#define EXECUTORS_EXPERIMENTAL_STRAND_HEADER

#include <experimental/executor>
#include <memory>
#include <type_traits>

namespace std {
namespace experimental {
inline namespace concurrency_v1 {

struct __strand_impl;

template <class _Executor>
class strand
{
public:
  typedef _Executor inner_executor_type;

  // construct / copy / destroy:

  template <class _Dummy = int> strand(_Dummy = 0,
    typename enable_if<is_default_constructible<_Executor>::value, _Dummy>::type* = 0);
  explicit strand(_Executor __e);
  strand(const strand& __s);
  strand(strand&& __s);
  template <class _OtherExecutor> strand(const strand<_OtherExecutor>& __s);
  template <class _OtherExecutor> strand(strand<_OtherExecutor>&& __s);

  strand& operator=(const strand& __s);
  strand& operator=(strand&& __s);
  template <class _OtherExecutor> strand& operator=(const strand<_OtherExecutor>& __s);
  template <class _OtherExecutor> strand& operator=(strand<_OtherExecutor>&& __s);

  ~strand();

  // executor operations:

  inner_executor_type get_inner_executor() const noexcept;

  bool running_in_this_thread() const noexcept;

  execution_context& context() noexcept;

  void on_work_started() noexcept;
  void on_work_finished() noexcept;

  template <class _Func, class _Alloc>
    void dispatch(_Func&& __f, const _Alloc& a);
  template <class _Func, class _Alloc>
    void post(_Func&& __f, const _Alloc& a);
  template <class _Func, class _Alloc>
    void defer(_Func&& __f, const _Alloc& a);

private:
  template <class> friend class strand;
  template <class _E> friend bool operator==(const strand<_E>&, const strand<_E>&) noexcept;
  friend class work;
  strand(const _Executor& __e, const shared_ptr<__strand_impl>& __i);
  _Executor _M_executor;
  shared_ptr<__strand_impl> _M_impl;
};

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

template <class _Executor> struct is_executor<strand<_Executor>> : true_type {};

template <class _T> auto make_strand(_T&& __t);

} // inline namespace concurrency_v1
} // namespace experimental
} // namespace std

#include <experimental/bits/strand.h>

#endif
