// xxexception internal header for exception_ptr -*-c++-*-
// Copyright 2014-2017 IAR Systems AB.
#ifndef _XXEXCEPTION_
#define _XXEXCEPTION_

#include <type_traits>

#ifndef _SYSTEM_BUILD
  #pragma system_include
#endif

#if _HAS_EXCEPTIONS

namespace std {

class exception_ptr;

exception_ptr current_exception() _NOEXCEPT;
[[noreturn]] void rethrow_exception(exception_ptr);

class exception_ptr
{
  friend bool operator==(const exception_ptr&, const exception_ptr&) _NOEXCEPT;
  friend bool operator!=(const exception_ptr&, const exception_ptr&) _NOEXCEPT;

  friend exception_ptr current_exception() _NOEXCEPT;
  friend void rethrow_exception (exception_ptr);

public:
  exception_ptr() _NOEXCEPT : _Ptr() {}
  exception_ptr(nullptr_t) _NOEXCEPT : _Ptr() {}
  exception_ptr(const exception_ptr&) _NOEXCEPT;

  exception_ptr& operator=(const exception_ptr&) _NOEXCEPT;
  ~exception_ptr() _NOEXCEPT;

  explicit operator bool() const _NOEXCEPT {return _Ptr != nullptr;}
private:
  void* _Ptr;
};

inline bool operator==(const exception_ptr &x, const exception_ptr &y) _NOEXCEPT
{
  return x._Ptr == y._Ptr;
}

inline bool operator!=(const exception_ptr &x, const exception_ptr &y) _NOEXCEPT
{
  return x._Ptr != y._Ptr;
}

template<class _Ep>
exception_ptr make_exception_ptr(_Ep _Ex) _NOEXCEPT
{
#if ! _EXCEPTION_NEUTRAL
  _TRY_BEGIN
    _RAISE(_Ex);
  _CATCH_ALL
    return current_exception();
  _CATCH_END
#else
  return exception_ptr();
#endif
}

// CLASS nested_exception
class nested_exception
{       // wraps an exception_ptr
public:
  nested_exception() _THROW0()
    : _Myptr(current_exception())
  {       // default construct
  }

  nested_exception(const nested_exception& _Right) = default;

  nested_exception& operator=(const nested_exception& _Right) = default;

  virtual ~nested_exception() _NOEXCEPT;

  exception_ptr nested_ptr() const _NOEXCEPT
  {       // get stored pointer
    return _Myptr;
  }

  [[noreturn]] void rethrow_nested() const
  {       // rethrow stored exception
    rethrow_exception(_Myptr);
  }

private:
  exception_ptr _Myptr;
};

// TEMPLATE FUNCTION throw_with_nested
template<class _Ty>
struct _Wrapped_with_nested
  : _Ty, nested_exception
{       // wrap _Ty and current_exception()
  _Wrapped_with_nested(const _Ty & _Val)
    : _Ty(_Val)
  {       // construct with _Val
  }
};

template <class _Ty>
[[noreturn]] inline void _Throw_with_nested(_Ty&& _Val, std::true_type)
{
  _RAISE(_Wrapped_with_nested<typename std::remove_reference<_Ty>::type>(std::forward<_Ty>(_Val)));
}

template <class _Ty>
[[noreturn]] inline void _Throw_with_nested(_Ty&& _Val, std::false_type)
{
  _RAISE(std::forward<_Ty>(_Val));
}

template <class _Ty>
[[noreturn]] inline void throw_with_nested(_Ty&& _Val)
{
  typedef typename std::remove_reference<_Ty>::type _RawTy;

  _Throw_with_nested(std::forward<_Ty>(_Val),
                     std::bool_constant<(    std::is_class<_RawTy>::value
                                         && !std::is_base_of<nested_exception,
                                                             _RawTy>::value
                                         && !std::is_final<_RawTy>::value)>());
}

// TEMPLATE FUNCTION rethrow_if_nested
template <class _Ex>
inline void _Rethrow_if_nested(const _Ex &_Val, true_type)
{       // throw exception captured by _Val's nested_exception base
  if (nested_exception const *_Nex = dynamic_cast<nested_exception const *>(&_Val))
  {
    _Nex->rethrow_nested();
  }
}

template <class _Ex>
inline void _Rethrow_if_nested(const _Ex &, false_type)
{       // do nothing: no nested_exception base
}

template<class _Ex> inline
void rethrow_if_nested(const _Ex& _Val)
{       // throw exception captured by _Val's nested_exception base, if any
  _Rethrow_if_nested(_Val, is_polymorphic<_Ex>::type());
}

} /* namespace std */

#endif // _HAS_EXCEPTIONS

#endif /* _XXEXCEPTION_ */

/*
 * Copyright (c) by P.J. Plauger. All rights reserved.
 * Consult your license regarding permissions and restrictions.
V6.50:0576 */
