//======================================================================
//-----------------------------------------------------------------------
/**
 * @file		iutest_stdlib.hpp
 * @brief		iris unit test stdlib
 *
 * @author		t.shirayanagi
 * @par			copyright
 * Copyright (C) 2012-2015, Takazumi Shirayanagi\n
 * This software is released under the new BSD License,
 * see LICENSE
*/
//-----------------------------------------------------------------------
//======================================================================
#ifndef INCG_IRIS_IUTEST_STDLIB_HPP_54D4BEEE_7B6B_4AF4_B1F6_138560480D55_
#define INCG_IRIS_IUTEST_STDLIB_HPP_54D4BEEE_7B6B_4AF4_B1F6_138560480D55_

//======================================================================
// include
#if defined(IUTEST_USE_GTEST) && defined(__STRICT_ANSI__)
#  undef __STRICT_ANSI__
#  include <string.h>
#  include <stdlib.h>
#  include <cstdio>
#  define __STRICT_ANSI__
#endif
#include <cstdlib>

//======================================================================
// define

// iterator

//! has std::begin,std::end
#if !defined(IUTEST_HAS_STD_BEGIN_END)
#  if   IUTEST_HAS_CXX11
#    if   defined(__clang__)
#      define IUTEST_HAS_STD_BEGIN_END	1
#    elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
#      define IUTEST_HAS_STD_BEGIN_END	1
#    endif
#  elif defined(_LIBCPP_STD_VER) && _LIBCPP_STD_VER >= 11
#    define IUTEST_HAS_STD_BEGIN_END	1
#  elif defined(_LIBCPP_VERSION) && _LIBCPP_VERSION >= 1001
#    define IUTEST_HAS_STD_BEGIN_END	1
#  elif defined(_MSC_VER) && (_MSC_VER >= 1700)
#    define IUTEST_HAS_STD_BEGIN_END	1
#  endif
#endif

#if !defined(IUTEST_HAS_STD_BEGIN_END)
#  define IUTEST_HAS_STD_BEGIN_END	0
#endif

//! using begin,end
#if IUTEST_HAS_STD_BEGIN_END
#  define IUTEST_USING_BEGIN_END()	\
	using ::std::begin; using ::std::end
#else
#  define IUTEST_USING_BEGIN_END()	\
	using ::iutest::detail::cxx::begin; using ::iutest::detail::cxx::end
#endif

namespace iutest {
namespace detail {
namespace cxx
{

#if IUTEST_HAS_STD_BEGIN_END

using namespace std; // NOLINT

#else

template<typename T> typename T::iterator begin(T& x) { return x.begin(); }
template<typename T> typename T::iterator end  (T& x) { return x.end(); }

template<typename T> typename T::const_iterator begin(const T& x) { return x.begin(); }
template<typename T> typename T::const_iterator end  (const T& x) { return x.end(); }

#if !defined(IUTEST_NO_FUNCTION_TEMPLATE_ORDERING)
template<typename T, size_t SIZE> T* begin(T (&x)[SIZE]) { return &x[0]; }
template<typename T, size_t SIZE> T* end  (T (&x)[SIZE]) { return begin(x) + SIZE; }

template<typename T, size_t SIZE> const T* begin(const T (&x)[SIZE]) { return &x[0]; }
template<typename T, size_t SIZE> const T* end  (const T (&x)[SIZE]) { return begin(x) + SIZE; }
#endif

#endif

}	// end of namespace cxx
}	// end of namespace detail
}	// end of namespace iutest

// declval

//! has std::declval
#if !defined(IUTEST_HAS_STD_DECLVAL)
#  if   IUTEST_HAS_CXX11
#    if   defined(__clang__)
#      define IUTEST_HAS_STD_DECLVAL		1
#    elif defined(__GLIBCXX__) && __GLIBCXX__ > 20120313
#      define IUTEST_HAS_STD_DECLVAL		1
#    endif
#  elif defined(_LIBCPP_VERSION)
#    define IUTEST_HAS_STD_DECLVAL		1
#  elif defined(_MSC_VER) && (_MSC_VER >= 1700)
#    define IUTEST_HAS_STD_DECLVAL		IUTEST_HAS_DECLTYPE
#  endif
#endif

#if !defined(IUTEST_HAS_STD_DECLVAL)
#  define IUTEST_HAS_STD_DECLVAL		0
#endif

// tuple

#if  defined(IUTEST_USE_EXTERNAL_TR1_TUPLE) && IUTEST_USE_EXTERNAL_TR1_TUPLE
# define IUTEST_HAS_STD_TUPLE	0
#endif

//! use tr1::tuple
#if !defined(IUTEST_USE_EXTERNAL_TR1_TUPLE)
#  define IUTEST_USE_EXTERNAL_TR1_TUPLE	0
#endif

//! has ::std::tuple
#if !defined(IUTEST_HAS_STD_TUPLE)
#  if   defined(IUTEST_USE_EXTERNAL_STD_TUPLE) && IUTEST_USE_EXTERNAL_STD_TUPLE
#    define IUTEST_HAS_STD_TUPLE	1
#  elif defined(_STLPORT_VERSION)
#    define IUTEST_HAS_STD_TUPLE	0
#  elif defined(_MSC_VER)
#    if (_MSC_VER > 1700) || (_MSC_VER == 1700 && _VARIADIC_MAX >= 9)
#      define IUTEST_HAS_STD_TUPLE	1
#    endif
#  elif defined(__clang__)
#    if __has_include( <tuple> ) && IUTEST_HAS_VARIADIC_TEMPLATES
#      define IUTEST_HAS_STD_TUPLE	1
#    endif
#  elif defined(__GNUC__)
#    if IUTEST_HAS_VARIADIC_TEMPLATES
#      define IUTEST_HAS_STD_TUPLE	1
#    endif
#  endif
#endif

#if !defined(IUTEST_HAS_STD_TUPLE)
#  define IUTEST_HAS_STD_TUPLE		0
#endif

#ifndef IUTEST_USE_EXTERNAL_STD_TUPLE
#  define IUTEST_USE_EXTERNAL_STD_TUPLE	0
#endif

#if !IUTEST_HAS_STD_TUPLE

//! has ::std::tr1::tuple
#if !defined(IUTEST_HAS_TR1_TUPLE)
#  if   defined(IUTEST_USE_EXTERNAL_TR1_TUPLE) && IUTEST_USE_EXTERNAL_TR1_TUPLE
#    define IUTEST_HAS_TR1_TUPLE	1
#  elif defined(_STLPORT_VERSION)
#    define IUTEST_HAS_TR1_TUPLE	0
#  elif defined(IUTEST_OS_LINUX_ANDROID) && defined(_STLPORT_MAJOR)
#    define IUTEST_HAS_TR1_TUPLE	0
#  elif defined(_MSC_VER) && defined(_MSC_FULL_VER)
#    if (_MSC_VER >= 1500) && (_MSC_VER < 1700) && (_MSC_FULL_VER > 150021022)
#      define IUTEST_HAS_TR1_TUPLE	1
#    endif
#  elif defined(__clang__)
#    if __has_include( <tr1/tuple> )
#      define IUTEST_HAS_TR1_TUPLE	1
#    endif
#  elif defined(__GNUC__)
#    if (!defined(__CUDACC__) && !defined(__ARMCC_VERSION) && (__GNUC__ >= 4))
#      define IUTEST_HAS_TR1_TUPLE	1
#    endif
#  endif
#endif

#endif

//! has ::std::tr1::tuple
#if !defined(IUTEST_HAS_TR1_TUPLE)
#  define IUTEST_HAS_TR1_TUPLE		0
#endif

#if !defined(IUTEST_USE_OWN_TR1_TUPLE)
#  define IUTEST_USE_OWN_TR1_TUPLE	0
#endif

//! has tuple
#if IUTEST_HAS_STD_TUPLE || IUTEST_HAS_TR1_TUPLE
#  if !defined(IUTEST_HAS_TUPLE)
#    define IUTEST_HAS_TUPLE	1
#  endif
#else
#  if defined(IUTEST_HAS_TUPLE)
#    undef IUTEST_HAS_TUPLE
#  endif
#  define IUTEST_HAS_TUPLE		0
#endif

#if IUTEST_HAS_TUPLE

#if IUTEST_HAS_STD_TUPLE
#  if !IUTEST_USE_EXTERNAL_STD_TUPLE
#    include <tuple>
#  endif
#else
#  if IUTEST_HAS_TR1_TUPLE && !IUTEST_USE_EXTERNAL_TR1_TUPLE
#    if IUTEST_USE_OWN_TR1_TUPLE
#      include "iutest_tuple.hpp"
#    else
#      if (defined(__GNUC__) && (__GNUC__ >= 4))
#        include <tr1/tuple>
#      else
#        include <tuple>
#      endif
#    endif
#  endif
#endif

namespace iutest {
namespace tuples
{

#if IUTEST_HAS_STD_TUPLE
namespace alias = ::std;
#elif IUTEST_HAS_TR1_TUPLE
namespace alias = ::std::tr1;
#endif

using alias::tuple;
using alias::tuple_element;
using alias::make_tuple;
using alias::get;

template<typename T>struct tuple_size : public alias::tuple_size<T> {};
template<typename T>struct tuple_size<const T> : public alias::tuple_size<T> {};
template<typename T>struct tuple_size<volatile T> : public alias::tuple_size<T>{};
template<typename T>struct tuple_size<const volatile T> : public alias::tuple_size<T>{};

namespace detail
{

template<typename T, typename F, int Begin>
struct tuple_foreach_impl
{
	template<int N, int I>
	struct impl
	{
		static void do_something(T& t, F fn)
		{
			fn(I, get<I>(t));
			impl<N, I + 1>::do_something(t, fn);
		}
	};
	template<int N>
	struct impl<N, N>
	{
		static void do_something(T&, F) {}
	};

	static void do_something(T& t, F fn)
	{
		impl<tuple_size<T>::value, Begin>::do_something(t, fn);
	}
};

template<typename T, typename U>
struct tuple_cast_copy_impl
{
	template<int N, int I>
	struct impl
	{
		static void copy(T& dst, const U& src)
		{
			get<I>(dst) = static_cast<typename tuple_element<I, T>::type>(get<I>(src));
			impl<N, I + 1>::copy(dst, src);
		}
	};
	template<int N>
	struct impl<N, N>
	{
		static void copy(T&, const U&) {}
	};

	static void copy(T& dst, const U& src)
	{
		impl<tuple_size<T>::value, 0>::copy(dst, src);
	}
};

}	// end of namespace detail

template<int I, typename tuple_t, typename F>
void tuple_foreach(tuple_t& t, F& fn)
{
	detail::tuple_foreach_impl<tuple_t, F&, I>::do_something(t, fn);
}
template<typename tuple_t, typename F>
void tuple_foreach(tuple_t& t, F& fn)
{
	tuple_foreach<0>(t, fn);
}
template<int I, typename tuple_t, typename F>
void tuple_foreach(tuple_t& t, const F& fn)
{
	detail::tuple_foreach_impl<tuple_t, const F&, I>::do_something(t, fn);
}
template<typename tuple_t, typename F>
void tuple_foreach(tuple_t& t, const F& fn)
{
	tuple_foreach<0>(t, fn);
}
template<typename T, typename U>
void tuple_cast_copy(T& dst, const U& src)
{
	detail::tuple_cast_copy_impl<T, U>::copy(dst, src);
}

}	// end of namespace tuples

using tuples::tuple;
using tuples::tuple_size;
using tuples::tuple_element;
using tuples::tuple_foreach;
using tuples::make_tuple;
using tuples::get;

}	// end of namespace iutest

#endif

//! has regex header
#if !defined(IUTEST_HAS_CXX_HDR_REGEX)

#if   defined(__has_include)
#  if __has_include( <regex> ) && IUTEST_HAS_CXX11
#    if !defined(__GLIBCXX__) || (__GLIBCXX__ > 20120301)
#      define IUTEST_HAS_CXX_HDR_REGEX		1
#    endif
#  endif
#elif defined(__GLIBCXX__)
#  if defined(__GNUC__)
#    if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) && defined(__GXX_EXPERIMENTAL_CXX0X__)
#      define IUTEST_HAS_CXX_HDR_REGEX		1
#    endif
#  else
#  endif
#elif defined(_MSC_VER)
#  if _MSC_VER > 1600
#    define IUTEST_HAS_CXX_HDR_REGEX		1
#  endif
#endif

#endif

#if !defined(IUTEST_HAS_CXX_HDR_REGEX)
#  define IUTEST_HAS_CXX_HDR_REGEX			0
#endif

//! has chrono header
#if !defined(IUTEST_HAS_CXX_HDR_CHRONO)

#if   defined(__has_include)
#  if __has_include( <chrono> )
#    if IUTEST_HAS_CXX11
#      define IUTEST_HAS_CXX_HDR_CHRONO		1
#    endif
#  endif
#elif defined(__GLIBCXX__)
#  if defined(__GNUC__)
#    if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) && defined(__GXX_EXPERIMENTAL_CXX0X__)
#      define IUTEST_HAS_CXX_HDR_CHRONO		1
#    endif
#  else
#  endif
#elif defined(_MSC_VER)
#  if _MSC_VER > 1600
#    define IUTEST_HAS_CXX_HDR_CHRONO		1
#  endif
#endif

#endif

#if !defined(IUTEST_HAS_CXX_HDR_CHRONO)
#  define IUTEST_HAS_CXX_HDR_CHRONO			0
#endif

//! has random header
#if !defined(IUTEST_HAS_CXX_HDR_RANDOM)

#if   defined(__has_include)
#  if __has_include( <random> )
#    if IUTEST_HAS_CXX11
#      define IUTEST_HAS_CXX_HDR_RANDOM		1
#    endif
#  endif
#elif defined(__GLIBCXX__)
#  if defined(__GNUC__)
#    if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) && defined(__GXX_EXPERIMENTAL_CXX0X__)
#      define IUTEST_HAS_CXX_HDR_RANDOM		1
#    endif
#  else
#  endif
#elif defined(_LIBCPP_VERSION)
#  if IUTEST_HAS_CXX11
#    define IUTEST_HAS_CXX_HDR_RANDOM		1
#  endif
#elif defined(_MSC_VER)
#  if _MSC_VER > 1600
#    define IUTEST_HAS_CXX_HDR_RANDOM		1
#  endif
#endif

#endif

#if !defined(IUTEST_HAS_CXX_HDR_RANDOM)
#  define IUTEST_HAS_CXX_HDR_RANDOM		0
#endif

//! has codecvt header
/*
#if !defined(IUTEST_HAS_CXX_HDR_CODECVT)

#if   defined(__has_include)
#  if __has_include( <codecvt> )
#    if IUTEST_HAS_CXX11
#      define IUTEST_HAS_CXX_HDR_CODECVT	1
#    endif
#  endif
#elif defined(__GLIBCXX__)
#elif defined(_MSC_VER)
#  if _MSC_VER > 1600
#    define IUTEST_HAS_CXX_HDR_CODECVT		1
#  endif
#endif

#endif
*/

#if !defined(IUTEST_HAS_CXX_HDR_CODECVT)
#  define IUTEST_HAS_CXX_HDR_CODECVT		0
#endif

//! has emplace
#if !defined(IUTEST_HAS_STD_EMPLACE)
#  if defined(__GNUC__)
#    if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) && defined(__GXX_EXPERIMENTAL_CXX0X__)
#      define IUTEST_HAS_STD_EMPLACE		1
#    endif
#  elif defined(__clang__) && IUTEST_HAS_CXX11
#    define IUTEST_HAS_STD_EMPLACE			1
#  elif defined(_MSC_VER)
#    if (_MSC_VER > 1700)
#      define IUTEST_HAS_STD_EMPLACE		1
#    endif
#  endif
#endif

#if !defined(IUTEST_HAS_STD_EMPLACE)
#  define IUTEST_HAS_STD_EMPLACE			0
#endif

//! has cxxabi header
#if !defined(IUTEST_HAS_HDR_CXXABI)

#if   defined(__clang__) && defined(__has_include)
#  if __has_include( <cxxabi.h> )
#    define IUTEST_HAS_HDR_CXXABI		1
#  endif
#elif defined(__GLIBCXX__) || defined(__GLIBCPP__)
#  define IUTEST_HAS_HDR_CXXABI			1
#else
#  define IUTEST_HAS_HDR_CXXABI			0
#endif

#endif

#if !defined(IUTEST_HAS_HDR_CXXABI)
#  define IUTEST_HAS_HDR_CXXABI			0
#endif

//! has sys/time.h header
#if !defined(IUTEST_HAS_HDR_SYSTIME)
#  if defined(IUTEST_OS_WINDOWS) && !defined(IUTEST_OS_WINDOWS_MINGW) && !defined(IUTEST_OS_WINDOWS_WINE)
#    define IUTEST_HAS_HDR_SYSTIME		0
#  endif
#endif

#if !defined(IUTEST_HAS_HDR_SYSTIME)
#  define IUTEST_HAS_HDR_SYSTIME		1
#endif

// socklen_t
#if defined(IUTEST_OS_WINDOWS_WINE)
#  define __socklen_t_defined
#endif

namespace iutest {
namespace detail
{

//======================================================================
// function
/**
 * @internal
 * @brief	mbtowc
*/
inline int iu_mbtowc(wchar_t* dst, const char* src, size_t size)
{
#if defined(IUTEST_OS_LINUX_ANDROID) || defined(IUTEST_OS_WINDOWS_MOBILE)
	// unimplimented
	IUTEST_UNUSED_VAR(dst);
	IUTEST_UNUSED_VAR(src);
	IUTEST_UNUSED_VAR(size);
	return 0;
#else
	return mbtowc(dst, src, size);
#endif
}

}	// end of namespace detail
}	// end of namespace iutest

#endif // INCG_IRIS_IUTEST_STDLIB_HPP_54D4BEEE_7B6B_4AF4_B1F6_138560480D55_
