/*
 * $Id$
 *
    Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:
    1. Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.

    THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef _QSE_TYPES_HPP_
#define _QSE_TYPES_HPP_

/// \file
/// Defines aliases to various QSE types in a class and holds various feature
/// configuration options.

#include <qse/types.h>
#include <qse/macros.h>

#if (__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1900) // C++11 or later
	#define QSE_LANG_CPP11 1

	#define QSE_CPP_NOEXCEPT noexcept(true)
	#define QSE_CPP_THREXCEPT1(e1) throw(e1)
	#define QSE_CPP_THREXCEPT2(e1,e2) throw(e1,e2)
	#define QSE_CPP_THREXCEPT3(e1,e2,e3) throw(e1,e2,e3)
	#define QSE_CPP_THREXCEPT4(e1,e2,e3,e4) throw(e1,e2,e3,e4)
	#define QSE_CPP_THREXCEPT5(e1,e2,e3,e4,e5) throw(e1,e2,e3,e4,e5)
	#define QSE_CPP_EXPLICIT explicit
	#define QSE_CPP_OVERRIDE override

	/// The QSE_CPP_ENABLE_CPP11_MOVE macro enables C++11 move semantics
	/// in various classes.
	#define QSE_CPP_ENABLE_CPP11_MOVE 1

	// The QSE_CPP_CALL_DESTRUCTOR() macro calls a destructor explicitly.
	#define QSE_CPP_CALL_DESTRUCTOR(ptr, class_name) ((ptr)->~class_name())

	// The QSE_CPP_CALL_PLACEMENT_DELETE1() macro calls the global operator delete
	// with 1 extra argument given.
	#define QSE_CPP_CALL_PLACEMENT_DELETE1(ptr, arg1) (::operator delete((ptr), (arg1)))

	#define QSE_CPP_TEMPLATE_QUALIFIER template


#elif (__cplusplus >= 199711L) // C++98
	#undef QSE_LANG_CPP11 

	#define QSE_CPP_NOEXCEPT throw()
	#define QSE_CPP_THREXCEPT1(e1) throw(e1)
	#define QSE_CPP_THREXCEPT2(e1,e2) throw(e1,e2)
	#define QSE_CPP_THREXCEPT3(e1,e2,e3) throw(e1,e2,e3)
	#define QSE_CPP_THREXCEPT4(e1,e2,e3,e4) throw(e1,e2,e3,e4)
	#define QSE_CPP_THREXCEPT5(e1,e2,e3,e4,e5) throw(e1,e2,e3,e4,e5)
	#define QSE_CPP_EXPLICIT 
	#define QSE_CPP_OVERRIDE

	#define QSE_CPP_CALL_DESTRUCTOR(ptr, class_name) ((ptr)->~class_name())
	#define QSE_CPP_CALL_PLACEMENT_DELETE1(ptr, arg1) (::operator delete((ptr), (arg1)))
	#define QSE_CPP_TEMPLATE_QUALIFIER template
#else
	#define QSE_CPP_NOEXCEPT 
	#define QSE_CPP_THREXCEPT1(e1)
	#define QSE_CPP_THREXCEPT2(e1,e2)
	#define QSE_CPP_THREXCEPT3(e1,e2,e3)
	#define QSE_CPP_THREXCEPT4(e1,e2,e3,e4)
	#define QSE_CPP_THREXCEPT5(e1,e2,e3,e4,e5)
	#define QSE_CPP_EXPLICIT 
	#define QSE_CPP_OVERRIDE 

	#if defined(__BORLANDC__)

		// Explicit destructor call requires a class name depending on the
		// C++ standard/compiler.  
		// 
		//   Node* x;
		//   x->~Node (); 
		//
		// While x->~Node() is ok with modern compilers, some old compilers
		// like BCC55 required the class name in the call as shown below.
		//
		//   x->Node::~Node ();

		#define QSE_CPP_CALL_DESTRUCTOR(ptr, class_name) ((ptr)->class_name::~class_name())
		#define QSE_CPP_CALL_PLACEMENT_DELETE1(ptr, arg1) (::operator delete((ptr), (arg1)))
		#define QSE_CPP_TEMPLATE_QUALIFIER template

	#elif defined(__WATCOMC__)
		// WATCOM has a problem with this syntax.
		//    Node* x; x->Node::~Node(). 
		// But it doesn't support operator delete overloading.

		#define QSE_CPP_CALL_DESTRUCTOR(ptr, class_name) ((ptr)->~class_name())
		#define QSE_CPP_CALL_PLACEMENT_DELETE1(ptr, arg1) (::qse_operator_delete((ptr), (arg1)))

		// When  the name of a member template specialization appears after .  or
		// -> in a postfix-expression, or after :: in a qualified-id that explic-
		// itly  depends on a template-argument (_temp.dep_), the member template
		// name must be prefixed by the keyword template.  Otherwise the name  is
		// assumed to name a non-template.  [Example:
		// 		class X {
		// 		public:
		// 			   template<size_t> X* alloc();
		// 		};
		// 		void f(X* p)
		// 		{
		// 			   X* p1 = p->alloc<200>();
		// 					 // ill-formed: < means less than
		// 			   X* p2 = p->template alloc<200>();
		// 					 // fine: < starts explicit qualification
		// 		}
		// --end example]
		//
		// WATCOM doesn't support this qualifier.

		#define QSE_CPP_TEMPLATE_QUALIFIER
		#define QSE_CPP_NO_OPERATOR_DELETE_OVERLOADING 1
	#else

		#define QSE_CPP_CALL_DESTRUCTOR(ptr, class_name) ((ptr)->~class_name())
		#define QSE_CPP_CALL_PLACEMENT_DELETE1(ptr, arg1) (::operator delete((ptr), (arg1)))
		#define QSE_CPP_TEMPLATE_QUALIFIER template

	#endif

#endif

#if defined(QSE_CPP_ENABLE_CPP11_MOVE)

	template<typename T> struct QSE_CPP_RMREF      { typedef T Type; };
	template<typename T> struct QSE_CPP_RMREF<T&>  { typedef T Type; };
	template<typename T> struct QSE_CPP_RMREF<T&&> { typedef T Type; };

	template<typename T> inline
	typename QSE_CPP_RMREF<T>::Type&& QSE_CPP_RVREF(T&& v) 
	{
		return (typename QSE_CPP_RMREF<T>::Type&&)v; 
	}
#else

	/*
	template<typename T> inline
	T& QSE_CPP_RVREF(T& v) { return (T&)v; }

	template<typename T> inline
	const T& QSE_CPP_RVREF(const T& v) { return (const T&)v; }
	*/
	#define QSE_CPP_RVREF(x) x
#endif


/////////////////////////////////
QSE_BEGIN_NAMESPACE(QSE)
/////////////////////////////////

/**
 * The Types class defines handy aliases for various QSE types.
 */
class QSE_EXPORT Types
{
public:
	/** boolean data type */
	typedef qse_bool_t  bool_t;

	/** data type that can hold any character */
	typedef qse_char_t  char_t;

	/** data type that can hold an unsigned char_t value */
	typedef qse_chau_t  chau_t;

	/** data type that can hold any character or an end-of-file value */
	typedef qse_cint_t  cint_t;

	/** redefines an unsigned integer number of the same size as void* */
	typedef qse_size_t  size_t;

	/** signed version of size_t */
	typedef qse_ssize_t ssize_t;

	/** redefines qse_long_t */
	typedef qse_long_t  long_t;

	/** redefines qse_ulong_t */
	typedef qse_ulong_t  ulong_t;

	/** redefines qse_intptr_t */
	typedef qse_intptr_t intptr_t;

	/** redefines qse_uintptr_t */
	typedef qse_uintptr_t uintptr_t;

	/** redefines qse_intmax_t */
	typedef qse_intmax_t intmax_t;

	/** redefines qse_uintmax_t */
	typedef qse_uintmax_t uintmax_t;

	/** redefines a floating-point number */
	typedef qse_flt_t flt_t;

	/** redefines a structure of a character pointer and length */
	typedef qse_cstr_t cstr_t;

	/** redefines a structure of a character pointer and length */
	typedef qse_wcstr_t wcstr_t;

	/** redefines a structure of a character pointer and length */
	typedef qse_mcstr_t mcstr_t;


	/** defines common error codes */
	enum ErrorNumber
	{
		/* [NOTE] if you change items here, you must change the stock error description in TypesErrorNumberToStr::operator() */

		E_ENOERR,  /**< no error */
		E_EOTHER,  /**< other error */
		E_ENOIMPL, /**< not implemented */
		E_ESYSERR, /**< subsystem error */
		E_EINTERN, /**< internal error */

		E_ENOMEM,
		E_ENARGS,   /**< wrong number of arguments */
		E_EINVAL,
		E_EACCES,
		E_EPERM,

		E_ENOENT,
		E_EEXIST,
		E_ENOTDIR,
		E_EINTR,
		E_EPIPE,

		E_EINPROG, /* in progress */
		E_EAGAIN,  /* resource unavailable unavailable */
		E_EEXCEPT /**< exception */
	};
};

/////////////////////////////////
QSE_END_NAMESPACE(QSE)
/////////////////////////////////

#endif
