// xxexception internal header for exception_ptr
#ifndef _XXEXCEPTION_
#define _XXEXCEPTION_

#if defined(__ghs)
#include <utility>
#include <type_traits>
#endif /* defined(__ghs) */

 #if defined(__ghs)
  #pragma ghs start_cxx_lib_header
  #pragma ghs startdata
  #if defined(__ghs_max_pack_value)
   #pragma pack (push, __ghs_max_pack_value)
  #endif /* defined(__ghs_max_pack_value) */
 #endif /* defined(__ghs) */

#if defined(__ghs) && _HAS_EXCEPTIONS
_X_STD_BEGIN

extern "C" void* __ghs_get_current_exception(void);
extern "C" void  __ghs_decr_ref_count_on_exception_ptr(void *ptr);
extern "C" void  __ghs_incr_ref_count_on_exception_ptr(void *ptr);
extern "C" void  __ghs_rethrow_exception_ptr(void *ptr);

struct exception_ptr
	{
	struct _Construct_tag {};

	exception_ptr() : _Ptr(nullptr) {}
	exception_ptr(nullptr_t) : _Ptr(nullptr) {}
	exception_ptr(_Construct_tag, void *_Exptr) : _Ptr(_Exptr) {};

	~exception_ptr()
		{
		if (_Ptr != NULL)
			{
			__ghs_decr_ref_count_on_exception_ptr(_Ptr);
			}
		}

	exception_ptr(const exception_ptr & _Other)
		{
		if (_Other._Ptr != NULL)
			{
			__ghs_incr_ref_count_on_exception_ptr(_Other._Ptr);
			}
		_Ptr = _Other._Ptr;
		}

	exception_ptr(exception_ptr && _Other)
		{
		_Ptr = _Other._Ptr;
		_Other._Ptr = NULL;
		}
	
	exception_ptr & operator=(const exception_ptr & _Other)
		{
		if (_Ptr != NULL)
			{
			__ghs_decr_ref_count_on_exception_ptr(_Ptr);
			}
		if (_Other._Ptr != NULL)
			{
			__ghs_incr_ref_count_on_exception_ptr(_Other._Ptr);
			}
		_Ptr = _Other._Ptr;
		return *this;
  		}

	exception_ptr & operator=(exception_ptr && _Other)
		{
		if (_Ptr != NULL)
			{
			__ghs_decr_ref_count_on_exception_ptr(_Ptr);
			}
		_Ptr = _Other._Ptr;
		_Other._Ptr = NULL;
		return *this;
  		}
		
	explicit operator bool() const { return (bool)(_Ptr != nullptr); }

	friend bool operator==(const exception_ptr &_Lhs, const exception_ptr &_Rhs)
		{
		return (bool)(_Lhs._Ptr == _Rhs._Ptr);
		}

	friend bool operator!=(const exception_ptr &_Lhs, const exception_ptr &_Rhs)
		{
		return (bool)(_Lhs._Ptr != _Rhs._Ptr);
		}

	void swap(exception_ptr & _Rhs)
		{
		void *_Temp = this->_Ptr;
		this->_Ptr = _Rhs._Ptr;
		_Rhs._Ptr = _Temp;		
		}
		
	void _Rethrow()
		{
		if (_Ptr != NULL)
			{
			__ghs_rethrow_exception_ptr(_Ptr);
			}
		}
private:
	void *_Ptr;
};

#if defined(__ghs)
        // FUNCTIONS FOR exception_ptr
inline exception_ptr current_exception() _NOEXCEPT
	{       // return pointer to current exception
	return (exception_ptr(exception_ptr::_Construct_tag{},
			      __ghs_get_current_exception()));
	}

inline void rethrow_exception(exception_ptr _Eptr)
{       // rethrow exception
	_Eptr._Rethrow();
}

inline void swap(exception_ptr &_Lhs, exception_ptr &_Rhs)
{
	_Lhs.swap(_Rhs);
}

#else

typedef void *exception_ptr;	// DUMMY

	// FUNCTIONS FOR exception_ptr
inline exception_ptr current_exception() _NOEXCEPT	// DUMMY
	{	// return pointer to current exception
	return (exception_ptr());
	}

inline void rethrow_exception(exception_ptr)	// DUMMY
	{	// rethrow exception
	int _Zero = 0;
	if (_Zero)
		_RERAISE;
	}

#endif /* defined(__ghs) */
_X_STD_END

_X_STD_BEGIN
	// FUNCTION make_exception_ptr
template<class _Excep> inline
	exception_ptr make_exception_ptr(_Excep _Ex) _NOEXCEPT
	{	// copy exception pointer
#if defined(__ghs) && !_HAS_EXCEPTIONS
	return exception_ptr();
#else
	_TRY_BEGIN
	_RAISE(_Ex);
	_CATCH_ALL
	int _Zero = 0;
	if (_Zero == 0)	// to quiet diagnostics
		return (current_exception());
	_CATCH_END
	return (exception_ptr());	// to quiet diagnostics
#endif /* defined(__ghs) && !_HAS_EXCEPTIONS */
	}

	// CLASS nested_exception
class nested_exception
	{	// wraps an exception_ptr
public:
	nested_exception() _THROW0()
		: _Myptr(current_exception())
		{	// default construct
		}

 #if _HAS_FUNCTION_DELETE
	nested_exception(const nested_exception& _Right) = default;

	nested_exception& operator=(
		const nested_exception& _Right) = default;

//	virtual ~nested_exception() _NOEXCEPT = default;
	virtual ~nested_exception() _NOEXCEPT
		{	// delete the object
		}

 #else /* _HAS_FUNCTION_DELETE */
	nested_exception(const nested_exception& _Right) _NOEXCEPT
		: _Myptr(_Right._Myptr)
		{	// copy construct
		}

	nested_exception& operator=(
		const nested_exception& _Right) _NOEXCEPT
		{	// copy _right
		_Myptr = _Right._Myptr;
		return (*this);
		}

	virtual ~nested_exception() _NOEXCEPT
		{	// delete the object
		}
 #endif /* _HAS_FUNCTION_DELETE */

	exception_ptr nested_ptr() const _NOEXCEPT
		{	// get stored pointer
		return (_Myptr);
		}

	void rethrow_nested() const	// _NO_RETURN
		{	// rethrow stored exception
#if defined(__ghs)
		if (!_Myptr)
			{
			_XSTD terminate();
			}
#endif /* defined(__ghs) */
		rethrow_exception(_Myptr);
		}

private:
	exception_ptr _Myptr;
	};

	// TEMPLATE FUNCTION throw_with_nested
template<class _Ty>
	struct _Wrapped_with_nested
#if defined(__ghs)
		: decay<_Ty>::type, nested_exception
#else
		: _Ty, nested_exception
#endif /* defined(__ghs) */
	{	// wrap _Ty and current_exception()
#if defined(__ghs)
	typedef typename decay<_Ty>::type _Mybase1;
	_Wrapped_with_nested(_Ty _VALREF _Val)
		: _Mybase1(forward<_Ty>(_Val))
#else
	_Wrapped_with_nested(_Ty&& _Val)
		: _Ty((_Ty&&)(_Val))
#endif /* defined(__ghs) */
		{	// construct with _Val
		}
	};

template<class _Ty> inline
	void _Throw_with_nested0(_Ty _VALREF _Val, ...)		// _NO_RETURN
	{	// throw _Val
	_THROW1((_Ty _VALREF)(_Val));
	}

#if defined(__ghs)
template<class _Ty,
	 class _Decayed = typename decay<_Ty>::type,
	 class = typename enable_if<is_class<_Decayed>::value &&
				    !is_union<_Decayed>::value &&
				    !is_final<_Decayed>::value>::type> inline
	void _Throw_with_nested0(_Ty _VALREF _Val,
		int)		// _NO_RETURN
#else
template<class _Ty> inline
	void _Throw_with_nested0(_Ty _VALREF _Val,
		const _Wrapped_with_nested<_Ty>*)		// _NO_RETURN
#endif /* defined(__ghs) */
	{	// throw wrapped object holding _Val and current exception
	_THROW1(_Wrapped_with_nested<_Ty>((_Ty _VALREF)(_Val)));
	}

template<class _Ty> inline
	void _Throw_with_nested(_Ty _VALREF _Val,
		const volatile void *)	// _NO_RETURN
	{	// throw wrapped object holding _Val and current exception
	_Throw_with_nested0(_Val, 0);
	}

template<class _Ty> inline
	void _Throw_with_nested(_Ty _VALREF _Val,
		const volatile nested_exception *)	// _NO_RETURN
	{	// throw _Val
	_THROW1((_Ty _VALREF)(_Val));
	}

template<class _Ty> inline
	void throw_with_nested(_Ty _VALREF _Val)	// _NO_RETURN
	{	// throw _Val
#if defined(__ghs)
	_Throw_with_nested(_Val, _STD addressof(_Val));
#else
	_Throw_with_nested(_Val, &_Val);
#endif /* defined(__ghs) */
	}

#if defined(__ghs)
	// TEMPLATE FUNCTION rethrow_if_nested
template <class _Ty,
	class = typename enable_if<is_polymorphic<_Ty>::value>::type>
	void _Rethrow_if_nested(const _Ty* _Val, int)
	{	// throw exception captured by _Val's nested_exception base
	if (auto _P = dynamic_cast<const nested_exception*>(_Val))
		{
		_P->rethrow_nested();
		}
	}

template <class _Ty>
	void _Rethrow_if_nested(const _Ty* _Val, ...)
	{	// do nothing: no nested_exception base
	}
#else
	// TEMPLATE FUNCTION rethrow_if_nested
inline void _Rethrow_if_nested(const nested_exception *_Val)
	{	// throw exception captured by _Val's nested_exception base
	if (_Val->nested_ptr())
		_Val->rethrow_nested();
	}

inline void _Rethrow_if_nested(const void *)
	{	// do nothing: no nested_exception base
	}
#endif /* defined(__ghs) */

template<class _Ex> inline
	void rethrow_if_nested(const _Ex& _Val)
	{	// throw exception captured by _Val's nested_exception base, if any
#if defined(__ghs)
	_Rethrow_if_nested(_STD addressof(_Val), 0);
#else
	_Rethrow_if_nested(&_Val);
#endif /* defined(__ghs) */
	}
_X_STD_END
#endif /* defined(__ghs) && _HAS_EXCEPTIONS */

 #if defined(__ghs)
  #if defined(__ghs_max_pack_value)
   #pragma pack(pop)
  #endif /* defined(__ghs_max_pack_value) */
  #pragma ghs enddata
  #pragma ghs end_cxx_lib_header
 #endif /* defined(__ghs) */

#endif /* _XXEXCEPTION_ */

/*
 * Copyright (c) by P.J. Plauger. All rights reserved.
 * Consult your license regarding permissions and restrictions.
V8.03b/17:0063 */
