#pragma once
/*	Copyright (C) 2006 Garrett A. Kajmowicz

	This file is part of the uClibc++ Library.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
#ifdef ARDUINO_ARCH_AVR
#include <math.h>
#include "type_traits"
#include "ext/type_traits.h"
#undef abs
#undef acos
#undef asin
#undef atan
#undef atan2
#undef ceil
#undef cos
#undef cosh
#undef exp
#undef fabs
#undef floor
#undef fmod
#undef frexp
#undef ldexp
#undef log
#undef log10
#undef modf
#undef pow
#undef sin
#undef sinh
#undef sqrt
#undef tan
#undef tanh
#else
#include_next <cmath>
#endif
#ifdef ARDUINO_ARCH_SAM
#include <limits>
#endif
namespace std
{
#ifdef ARDUINO_ARCH_AVR
	using ::acos;
	using ::asin;
	using ::atan;
	using ::atan2;
	using ::ceil;
	using ::cos;
	using ::cosh;
	using ::exp;
	using ::fabs;
	using ::floor;
	using ::fmod;
	using ::frexp;
	using ::ldexp;
	using ::log;
	using ::log10;
	using ::modf;
	using ::pow;
	using ::sin;
	using ::sinh;
	using ::sqrt;
	using ::tan;
	using ::tanh;

#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO
	inline float abs(float x)
	{
		return fabsf(x);
	}
	inline float acos(float x)
	{
		return acosf(x);
	}
	inline float asin(float x)
	{
		return asinf(x);
	}
	inline float atan(float x)
	{
		return atanf(x);
	}
	inline float atan2(float y, float x)
	{
		return atan2f(y, x);
	}
	inline float ceil(float x)
	{
		return ceilf(x);
	}
	inline float cos(float x)
	{
		return cosf(x);
	}
	inline float cosh(float x)
	{
		return coshf(x);
	}
	inline float exp(float x)
	{
		return expf(x);
	}
	inline float fabs(float x)
	{
		return fabsf(x);
	}
	inline float floor(float x)
	{
		return floorf(x);
	}
	inline float fmod(float x, float y)
	{
		return fmodf(x, y);
	}
	inline float frexp(float x, int *exp)
	{
		return frexpf(x, exp);
	}
	inline float ldexp(float x, int exp)
	{
		return ldexpf(x, exp);
	}
	inline float log(float x)
	{
		return logf(x);
	}
	inline float log10(float x)
	{
		return log10f(x);
	}
	inline float modf(float x, float *inptr)
	{
		return modff(x, inptr);
	}
	inline float pow(float x, float y)
	{
		return powf(x, y);
	}
#if 1 // DR 550 removed this
	inline float pow(float x, int y)
	{
		return pow((double)x, (double)y);
	}
#endif
	inline float sin(float x)
	{
		return sinf(x);
	}
	inline float sinh(float x)
	{
		return sinhf(x);
	}
	inline float sqrt(float x)
	{
		return sqrtf(x);
	}
	inline float tan(float x)
	{
		return tanf(x);
	}
	inline float tanh(float x)
	{
		return tanhf(x);
	}
	inline double abs(double x)
	{
		return fabs(x);
	}
	inline double pow(double x, int y)
	{
		return pow((double)x, (double)y);
	}

#ifdef __UCLIBCXX_HAS_LONG_DOUBLE__
	inline long double abs(long double x)
	{
		return fabsl(x);
	}
	inline long double acos(long double x)
	{
		return acosl(x);
	}
	inline long double asin(long double x)
	{
		return asinl(x);
	}
	inline long double atan(long double x)
	{
		return atanl(x);
	}
	inline long double atan2(long double y, long double x)
	{
		return atan2l(y, x);
	}
	inline long double ceil(long double x)
	{
		return ceill(x);
	}
	inline long double cos(long double x)
	{
		return cosl(x);
	}
	inline long double cosh(long double x)
	{
		return coshl(x);
	}
	inline long double exp(long double x)
	{
		return expl(x);
	}
	inline long double fabs(long double x)
	{
		return fabsl(x);
	}
	inline long double floor(long double x)
	{
		return floorl(x);
	}
	inline long double frexp(long double x, int *exp)
	{
		return frexpl(x, exp);
	}
	inline long double fmod(long double x, long double y)
	{
		return fmodl(x, y);
	}
	inline long double ldexp(long double x, int y)
	{
		return ldexpl(x, y);
	}
	inline long double log(long double x)
	{
		return logl(x);
	}
	inline long double log10(long double x)
	{
		return log10l(x);
	}
	inline long double modf(long double x, long double *iptr)
	{
		return modfl(x, iptr);
	}
	inline long double pow(long double x, long double y)
	{
		return powl(x, y);
	}
	inline long double pow(long double x, int y)
	{
		return powl(x, (long double)y);
	}
	inline long double sin(long double x)
	{
		return sinl(x);
	}
	inline long double sinh(long double x)
	{
		return sinhl(x);
	}
	inline long double sqrt(long double x)
	{
		return sqrtl(x);
	}
	inline long double tan(long double x)
	{
		return tanl(x);
	}
	inline long double tanh(long double x)
	{
		return tanhl(x);
	}
#endif //	 __UCLIBCXX_HAS_LONG_DOUBLE__
#endif //	 __CORRECT_ISO_CPP_MATH_H_PROTO
#endif
#ifndef ARDUINO_ARCH_ESP32
	// DR 568.
#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP
	constexpr float
	log2(float __x)
	{
		return __builtin_log2f(__x);
	}

	constexpr long double
	log2(long double __x)
	{
		return __builtin_log2l(__x);
	}
#endif

	template <typename _Tp>
	constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value,
											  double>::__type
	log2(_Tp __x)
	{
		return __x ? __builtin_log2(__x) : -std::numeric_limits<double>::infinity(); // AVR-GCC 7.3.0 的__builtin_log2输入0会出错，而不是返回负无穷
	}
#endif
}