/*
								+---------------------------------+
								|                                 |
								| ***   Parallel primitives   *** |
								|                                 |
								|  Copyright  © -tHE SWINe- 2013  |
								|                                 |
								|          Parallel.inl           |
								|                                 |
								+---------------------------------+
*/

#pragma once
#ifndef __PARALLEL_PRIMITIVES_INLINES_INCLUDED
#define __PARALLEL_PRIMITIVES_INLINES_INCLUDED

/**
 *	@file Parallel.inl
 *	@brief simple parallel primitives
 *	@date 2013
 *	@author -tHE SWINe-
 */

#if defined(_WIN32) || defined(_WIN64)

namespace __winatom {

/**
 *	@brief chooses an integer type that is supported by windows atomics
 *	@tparam n_size is required size, in bytes
 */
template <const int n_size>
class CChooseSupportedIntType;

/**
 *	@brief chooses an integer type that is supported by windows atomics
 *		(specialization for 1 byte)
 */
template <>
class CChooseSupportedIntType<1> {
public:
	typedef int32_t _TyResult; // don't have 8-bit atomics
};

/**
 *	@brief chooses an integer type that is supported by windows atomics
 *		(specialization for 2 bytes)
 */
template <>
class CChooseSupportedIntType<2> {
public:
	typedef int32_t _TyResult; // don't have 16-bit atomics
};

/**
 *	@brief chooses an integer type that is supported by windows atomics
 *		(specialization for 4 bytes)
 */
template <>
class CChooseSupportedIntType<4> {
public:
	typedef int32_t _TyResult;
};

/**
 *	@brief chooses an integer type that is supported by windows atomics
 *		(specialization for 8 bytes)
 */
template <>
class CChooseSupportedIntType<8> {
public:
	typedef int64_t _TyResult; // note: 64-bit atomics not supported in msvc 6.0
};

/**
 *	@brief base class for atomic operations
 *	@tparam _Ty is data type to perform atomic operations on
 */
template <class _Ty>
class CAtomicBase_Inner;

#if 0

/**
 *	@brief base class for atomic operations (specialization for 8-bit integers)
 */
template <>
class CAtomicBase_Inner<int8_t> {
public:
	typedef int8_t _Ty;

	/**
	 *	@brief exchanges value of the counter with n_value
	 *	@note On some platforms, n_value must be 1.
	 */
	static inline _Ty n_Atomic_Exchange(_Ty *p_target, _Ty n_value)
	{
		_ASSERTE(sizeof(char) == sizeof(_Ty));
		return InterlockedExchange16((char*)p_target, n_value);
	}

	/**
	 *	@brief exchanges value of the counter with n_value
	 *	@note On some platforms, n_value must be 1.
	 */
	static inline void Atomic_Exchange_0(_Ty *p_target)
	{
		_ASSERTE(sizeof(char) == sizeof(_Ty));
		InterlockedExchange16((char*)p_target, 0);
	}

	/**
	 *	@brief atomically (pre) increments the counter and returns the value
	 */
	static inline _Ty n_Atomic_Increment(_Ty *p_target)
	{
		_ASSERTE(sizeof(char) == sizeof(_Ty));
		return InterlockedIncrement16((char*)p_target);
	}

	/**
	 *	@brief atomically (pre) decrements the counter and returns the value
	 */
	static inline _Ty n_Atomic_Decrement(_Ty *p_target)
	{
		_ASSERTE(sizeof(char) == sizeof(_Ty));
		return InterlockedDecrement16((char*)p_target);
	}

	/**
	 *	@brief atomically adds a value to the counter and returns the original value
	 */
	static inline _Ty n_Atomic_FetchAdd(_Ty *p_target, _Ty n_value)
	{
		_ASSERTE(sizeof(char) == sizeof(_Ty));
		return InterlockedExchangeAdd16((char*)p_target, n_value);
	}

	/**
	 *	@brief atomically subtracts a value from the counter and returns the original value
	 */
	static inline _Ty n_Atomic_FetchSubtract(_Ty *p_target, _Ty n_value)
	{
		_ASSERTE(sizeof(char) == sizeof(_Ty));
		return InterlockedExchangeAdd16((char*)p_target, -n_value);
	}
};

/**
 *	@brief base class for atomic operations (specialization for 16-bit integers)
 */
template <>
class CAtomicBase_Inner<int16_t> {
public:
	typedef int16_t _Ty;

	/**
	 *	@brief exchanges value of the counter with n_value
	 *	@note On some platforms, n_value must be 1.
	 */
	static inline _Ty n_Atomic_Exchange(_Ty *p_target, _Ty n_value)
	{
		_ASSERTE(sizeof(SHORT) == sizeof(_Ty));
		return InterlockedExchange16((SHORT*)p_target, n_value);
	}

	/**
	 *	@brief exchanges value of the counter with n_value
	 *	@note On some platforms, n_value must be 1.
	 */
	static inline void Atomic_Exchange_0(_Ty *p_target)
	{
		_ASSERTE(sizeof(SHORT) == sizeof(_Ty));
		InterlockedExchange16((SHORT*)p_target, 0);
	}

	/**
	 *	@brief atomically (pre) increments the counter and returns the value
	 */
	static inline _Ty n_Atomic_Increment(_Ty *p_target)
	{
		_ASSERTE(sizeof(SHORT) == sizeof(_Ty));
		return InterlockedIncrement16((SHORT*)p_target);
	}

	/**
	 *	@brief atomically (pre) decrements the counter and returns the value
	 */
	static inline _Ty n_Atomic_Decrement(_Ty *p_target)
	{
		_ASSERTE(sizeof(SHORT) == sizeof(_Ty));
		return InterlockedDecrement16((SHORT*)p_target);
	}

	/**
	 *	@brief atomically adds a value to the counter and returns the original value
	 */
	static inline _Ty n_Atomic_FetchAdd(_Ty *p_target, _Ty n_value)
	{
		_ASSERTE(sizeof(SHORT) == sizeof(_Ty));
		return InterlockedExchangeAdd16((SHORT*)p_target, n_value);
	}

	/**
	 *	@brief atomically subtracts a value from the counter and returns the original value
	 */
	static inline _Ty n_Atomic_FetchSubtract(_Ty *p_target, _Ty n_value)
	{
		_ASSERTE(sizeof(SHORT) == sizeof(_Ty));
		return InterlockedExchangeAdd16((SHORT*)p_target, -n_value);
	}
};

#endif // 0

/**
 *	@brief base class for atomic operations (specialization for 32-bit integers)
 */
template <>
class CAtomicBase_Inner<int32_t> {
public:
	typedef int32_t _Ty;

	/**
	 *	@brief exchanges value of the counter with n_value
	 *	@note On some platforms, n_value must be 1.
	 */
	static inline _Ty n_Atomic_Exchange(_Ty *p_target, _Ty n_value)
	{
		_ASSERTE(sizeof(LONG) == sizeof(_Ty));
		return InterlockedExchange((LONG*)p_target, n_value);
	}

	/**
	 *	@brief exchanges value of the counter with n_value
	 *	@note On some platforms, n_value must be 1.
	 */
	static inline void Atomic_Exchange_0(_Ty *p_target)
	{
		_ASSERTE(sizeof(LONG) == sizeof(_Ty));
		InterlockedExchange((LONG*)p_target, 0);
	}

	/**
	 *	@brief atomically (pre) increments the counter and returns the value
	 */
	static inline _Ty n_Atomic_Increment(_Ty *p_target)
	{
		_ASSERTE(sizeof(LONG) == sizeof(_Ty));
		return InterlockedIncrement((LONG*)p_target);
	}

	/**
	 *	@brief atomically (pre) decrements the counter and returns the value
	 */
	static inline _Ty n_Atomic_Decrement(_Ty *p_target)
	{
		_ASSERTE(sizeof(LONG) == sizeof(_Ty));
		return InterlockedDecrement((LONG*)p_target);
	}

	/**
	 *	@brief atomically adds a value to the counter and returns the original value
	 */
	static inline _Ty n_Atomic_FetchAdd(_Ty *p_target, _Ty n_value)
	{
		_ASSERTE(sizeof(LONG) == sizeof(_Ty));
		return InterlockedExchangeAdd((LONG*)p_target, n_value);
	}

	/**
	 *	@brief atomically subtracts a value from the counter and returns the original value
	 */
	static inline _Ty n_Atomic_FetchSubtract(_Ty *p_target, _Ty n_value)
	{
		_ASSERTE(sizeof(LONG) == sizeof(_Ty));
		return InterlockedExchangeAdd((LONG*)p_target, -n_value);
	}
};

#if !defined(_MSC_VER) || defined(__MWERKS__) || _MSC_VER > 1200

/**
 *	@brief base class for atomic operations (specialization for 64-bit integers)
 */
template <>
class CAtomicBase_Inner<int64_t> {
public:
	typedef int64_t _Ty;

	/**
	 *	@brief exchanges value of the counter with n_value
	 *	@note On some platforms, n_value must be 1.
	 */
	static inline _Ty n_Atomic_Exchange(_Ty *p_target, _Ty n_value)
	{
		_ASSERTE(sizeof(LONGLONG) == sizeof(_Ty));
		return InterlockedExchange64((LONGLONG*)p_target, n_value);
	}

	/**
	 *	@brief exchanges value of the counter with n_value
	 *	@note On some platforms, n_value must be 1.
	 */
	static inline void Atomic_Exchange_0(_Ty *p_target)
	{
		_ASSERTE(sizeof(LONGLONG) == sizeof(_Ty));
		InterlockedExchange64((LONGLONG*)p_target, 0);
	}

	/**
	 *	@brief atomically (pre) increments the counter and returns the value
	 */
	static inline _Ty n_Atomic_Increment(_Ty *p_target)
	{
		_ASSERTE(sizeof(LONGLONG) == sizeof(_Ty));
		return InterlockedIncrement64((LONGLONG*)p_target);
	}

	/**
	 *	@brief atomically (pre) decrements the counter and returns the value
	 */
	static inline _Ty n_Atomic_Decrement(_Ty *p_target)
	{
		_ASSERTE(sizeof(LONGLONG) == sizeof(_Ty));
		return InterlockedDecrement64((LONGLONG*)p_target);
	}

	/**
	 *	@brief atomically adds a value to the counter and returns the original value
	 */
	static inline _Ty n_Atomic_FetchAdd(_Ty *p_target, _Ty n_value)
	{
		_ASSERTE(sizeof(LONGLONG) == sizeof(_Ty));
		return InterlockedExchangeAdd64((LONGLONG*)p_target, n_value);
	}

	/**
	 *	@brief atomically subtracts a value from the counter and returns the original value
	 */
	static inline _Ty n_Atomic_FetchSubtract(_Ty *p_target, _Ty n_value)
	{
		_ASSERTE(sizeof(LONGLONG) == sizeof(_Ty));
		return InterlockedExchangeAdd64((LONGLONG*)p_target, -n_value);
	}
};

#endif // !_MSC_VER || __MWERKS__ || _MSC_VER > 1200

} // ~__winatom

#endif // _WIN32 || _WIN64

#endif // !__PARALLEL_PRIMITIVES_INLINES_INCLUDED
