//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
// thread C++0X header
#pragma once
#ifndef _THREAD_
#define _THREAD_
#ifndef RC_INVOKED

 #ifdef _M_CEE
  #error <thread> is not supported when compiling with /clr or /clr:pure.
 #endif /* _M_CEE */

#include <exception>
#include <iosfwd>
#include <functional>
#include <chrono>

 #include <concrt.h>

#include <thr/xthread>
#include <thr/xtimec.h>

 #pragma pack(push,_CRT_PACKING)
 #pragma warning(push,3)
 #pragma push_macro("new")
 #undef new

 #pragma warning(disable: 4521 4522 4800)

#define __STDCPP_THR__	1	/* nonzero if threads supported */

_STD_BEGIN
class thread
	{	// class for observing and managing threads
public:
	class id;
	typedef void * native_handle_type;

	thread() _NOEXCEPT
		{	// construct with no thread
		_Thr_set_null(_Thr);
		}

#define _THREAD_CONS( \
	TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, X1, X2, X3, X4) \
	template<class _Fn COMMA LIST(_CLASS_TYPE)> \
		explicit thread(_Fn _Fx COMMA LIST(_TYPE_REFREF_ARG)) \
		{	/* construct with _Fx(_Ax...) */ \
		_Launch(&_Thr, \
			 _STD bind(_Decay_copy(_STD forward<_Fn>(_Fx)) \
				COMMA LIST(_FORWARD_ARG))); \
		}

_VARIADIC_EXPAND_0X(_THREAD_CONS, , , , )
#undef _THREAD_CONS

	~thread() _NOEXCEPT
		{	// clean up
		if (joinable())
			_XSTD terminate();
		}

	thread(thread&& _Other) _NOEXCEPT
		: _Thr(_Other._Thr)
		{	// move from _Other
		_Thr_set_null(_Other._Thr);
		}

	thread& operator=(thread&& _Other) _NOEXCEPT
		{	// move from _Other
		return (_Move_thread(_Other));
		}

private:
	thread(const thread&);	// not defined
	thread& operator=(const thread&);	// not defined
public:
	void swap(thread& _Other) _NOEXCEPT
		{	// swap with _Other
		_STD swap(_Thr, _Other._Thr);
		}

	bool joinable() const _NOEXCEPT
		{	// return true if this thread can be joined
		return (!_Thr_is_null(_Thr));
		}

	void join();

	void detach()
		{	// detach thread
		if (!joinable())
			_Throw_Cpp_error(_INVALID_ARGUMENT);
		_Thrd_detachX(_Thr);
		_Thr_set_null(_Thr);
		}

	id get_id() const _NOEXCEPT;

	static unsigned int hardware_concurrency() _NOEXCEPT
		{	// return number of hardware thread contexts
		return (::Concurrency::details::_GetConcurrency());
		}

	native_handle_type native_handle()
		{	// return Win32 HANDLE as void *
		return (_Thr._Hnd);
		}

private:
	thread& _Move_thread(thread& _Other)
		{	// move from _Other
		if (joinable())
			_XSTD terminate();
		_Thr = _Other._Thr;
		_Thr_set_null(_Other._Thr);
		return (*this);
		}

	_Thrd_t _Thr;
	};

	namespace this_thread {
thread::id get_id() _NOEXCEPT;

inline void yield() _NOEXCEPT
	{	// give up balance of time slice
	if (::Concurrency::details::_CurrentScheduler::_Id() != -1)
		{	// yield, then quit
		::Concurrency::details::_Context::_Yield();
		return;
		}
	_Thrd_yield();
	}

inline void sleep_until(const stdext::threads::xtime *_Abs_time)
	{	// sleep until _Abs_time
	if (::Concurrency::details::_CurrentScheduler::_Id() != -1)
		{
		stdext::threads::xtime _Now;
		stdext::threads::xtime_get(&_Now, stdext::threads::TIME_UTC);
		::Concurrency::wait(_Xtime_diff_to_millis2(_Abs_time, &_Now));
		return;
		}

	_Thrd_sleep(_Abs_time);
	}

template<class _Clock,
	class _Duration> inline
	void sleep_until(
		const chrono::time_point<_Clock, _Duration>& _Abs_time)
	{	// sleep until time point
	stdext::threads::xtime _Tgt;
	_Tgt.sec = chrono::duration_cast<chrono::seconds>(
		_Abs_time.time_since_epoch()).count();
	_Tgt.nsec = (long)chrono::duration_cast<chrono::nanoseconds>(
		_Abs_time.time_since_epoch() - chrono::seconds(_Tgt.sec)).count();
	sleep_until(&_Tgt);
	}

template<class _Rep,
	class _Period> inline
	void sleep_for(const chrono::duration<_Rep, _Period>& _Rel_time)
	{	// sleep for duration
	stdext::threads::xtime _Tgt = _To_xtime(_Rel_time);
	sleep_until(&_Tgt);
	}
	}	// namespace this_thread

class thread::id
	{	// thread id
public:
	id() _NOEXCEPT
		{	// id for no thread
		_Thr_set_null(_Thr);
		}

	template<class _Ch,
		class _Tr>
		basic_ostream<_Ch, _Tr>& _To_text(
			basic_ostream<_Ch, _Tr>& _Str)
		{	// insert representation into stream
		return (_Str << _Thr_val(_Thr));
		}

	size_t hash() const
		{	// hash bits to size_t value by pseudorandomizing transform
		return (_STD hash<size_t>()((size_t)_Thr_val(_Thr)));
		}

private:
	id(const thread& _Thrd)
		: _Thr(_Thrd._Thr)
		{	// construct from thread object
		}

	id(_Thrd_t _Thrd)
		: _Thr(_Thrd)
		{	// construct from thread identifier
		}

	_Thrd_t _Thr;

	friend thread::id thread::get_id() const _NOEXCEPT;
	friend thread::id this_thread::get_id() _NOEXCEPT;
	friend bool operator==(thread::id _Left, thread::id _Right) _NOEXCEPT;
	friend bool operator<(thread::id _Left, thread::id _Right) _NOEXCEPT;
	};

inline void thread::join()
	{	// join thread
	if (!joinable())
		_Throw_Cpp_error(_INVALID_ARGUMENT);
	if (_Thr_is_null(_Thr))
		_Throw_Cpp_error(_INVALID_ARGUMENT);
	if (get_id() == _STD this_thread::get_id())
		_Throw_Cpp_error(_RESOURCE_DEADLOCK_WOULD_OCCUR);
	if (_Thrd_join(_Thr, 0) != _Thrd_success)
		_Throw_Cpp_error(_NO_SUCH_PROCESS);
	_Thr_set_null(_Thr);
	}

inline thread::id thread::get_id() const _NOEXCEPT
	{	// return id for this thread
	return (id(*this));
	}

inline thread::id this_thread::get_id() _NOEXCEPT
	{	// return id for current thread
	return (_Thrd_current());
	}

inline void swap(thread& _Left, thread& _Right) _NOEXCEPT
	{	// swap _Left with _Right
	_Left.swap(_Right);
	}

inline bool operator==(thread::id _Left, thread::id _Right) _NOEXCEPT
	{	// return true if _Left and _Right identify the same thread
	return (_Thrd_equal(_Left._Thr, _Right._Thr));
	}

inline bool operator!=(thread::id _Left, thread::id _Right) _NOEXCEPT
	{	// return true if _Left and _Right do not identify the same thread
	return (!(_Left == _Right));
	}

inline bool operator<(thread::id _Left, thread::id _Right) _NOEXCEPT
	{	// return true if _Left precedes _Right
	return (_Thrd_lt(_Left._Thr, _Right._Thr));
	}

inline bool operator<=(thread::id _Left, thread::id _Right) _NOEXCEPT
	{	// return true if _Left precedes or equals _Right
	return (!(_Right < _Left));
	}
inline bool operator>(thread::id _Left, thread::id _Right) _NOEXCEPT
	{	// return true if _Left follows _Right
	return (_Right < _Left);
	}
inline bool operator>=(thread::id _Left, thread::id _Right) _NOEXCEPT
	{	// return true if _Left follows or equals _Right
	return (!(_Left < _Right));
	}

template<class _Ch,
	class _Tr>
	basic_ostream<_Ch, _Tr>& operator<<(
		basic_ostream<_Ch, _Tr>& _Str,
		thread::id _Id)
	{	// insert id into stream
	return (_Id._To_text(_Str));
	}

	// TEMPLATE STRUCT SPECIALIZATION hash
template<>
	struct hash<thread::id>
		: public unary_function<thread::id, size_t>
	{	// hash functor for thread::id
	typedef thread::id _Kty;

	size_t operator()(const _Kty& _Keyval) const
		{	// hash _Keyval to size_t value by pseudorandomizing transform
		return (_Keyval.hash());
		}
	};
_STD_END

 #pragma pop_macro("new")
 #pragma warning(pop)
 #pragma pack(pop)
#endif /* RC_INVOKED */
#endif /* _THREAD_ */

/*
 * Copyright (c) 1992-2012 by P.J. Plauger.  ALL RIGHTS RESERVED.
 * Consult your license regarding permissions and restrictions.
V6.00:0009 */
