/*
	This file is part of Fennix Kernel.

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

	Fennix Kernel 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 General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/

#pragma once

#include <climits>
#include <cfloat>

namespace std
{
	enum float_round_style
	{
		round_indeterminate = -1,
		round_toward_zero = 0,
		round_to_nearest = 1,
		round_toward_infinity = 2,
		round_toward_neg_infinity = 3,
	};

	enum float_denorm_style
	{
		denorm_indeterminate = -1,
		denorm_absent = 0,
		denorm_present = 1
	};

	template <class T>
	class numeric_limits
	{
	public:
		static constexpr bool is_specialized = false;

		static constexpr T min() { return T(); }
		static constexpr T max() { return T(); }
		static constexpr T lowest() { return T(); }

		static constexpr int digits = 0;
		static constexpr int digits10 = 0;
		static constexpr int max_digits10 = 0;

		static constexpr bool is_signed = false;
		static constexpr bool is_integer = false;
		static constexpr bool is_exact = false;
		static constexpr int radix = 0;
		static constexpr T epsilon() { return T(); }
		static constexpr T round_error() { return T(); }

		static constexpr int min_exponent = 0;
		static constexpr int min_exponent10 = 0;
		static constexpr int max_exponent = 0;
		static constexpr int max_exponent10 = 0;

		static constexpr bool has_infinity = false;
		static constexpr bool has_quiet_NaN = false;
		static constexpr bool has_signaling_NaN = false;
		static constexpr float_denorm_style has_denorm = denorm_absent;
		static constexpr bool has_denorm_loss = false;
		static constexpr T infinity() { return T(); }
		static constexpr T quiet_NaN() { return T(); }
		static constexpr T signaling_NaN() { return T(); }
		static constexpr T denorm_min() { return T(); }

		static constexpr bool is_iec559 = false;
		static constexpr bool is_bounded = false;
		static constexpr bool is_modulo = false;

		static constexpr bool traps = false;
		static constexpr bool tinyness_before = false;
		static constexpr float_round_style round_style = round_toward_zero;
	};

	template <>
	class numeric_limits<bool>
	{
	public:
		static constexpr bool is_specialized = true;

		static constexpr bool min() { return false; }
		static constexpr bool max() { return true; }
		static constexpr bool lowest() { return false; }

		static constexpr int digits = 1;
		static constexpr int digits10 = 0;
		static constexpr int max_digits10 = 0;

		static constexpr bool is_signed = false;
		static constexpr bool is_integer = true;
		static constexpr bool is_exact = true;
		static constexpr int radix = 2;
		static constexpr bool epsilon() { return 0; }
		static constexpr bool round_error() { return 0; }

		static constexpr int min_exponent = 0;
		static constexpr int min_exponent10 = 0;
		static constexpr int max_exponent = 0;
		static constexpr int max_exponent10 = 0;

		static constexpr bool has_infinity = false;
		static constexpr bool has_quiet_NaN = false;
		static constexpr bool has_signaling_NaN = false;
		static constexpr float_denorm_style has_denorm = denorm_absent;
		static constexpr bool has_denorm_loss = false;
		static constexpr bool infinity() { return 0; }
		static constexpr bool quiet_NaN() { return 0; }
		static constexpr bool signaling_NaN() { return 0; }
		static constexpr bool denorm_min() { return 0; }

		static constexpr bool is_iec559 = false;
		static constexpr bool is_bounded = true;
		static constexpr bool is_modulo = false;

		static constexpr bool traps = false;
		static constexpr bool tinyness_before = false;
		static constexpr float_round_style round_style = round_toward_zero;
	};

	template <>
	class numeric_limits<char>
	{
	public:
		static constexpr bool is_specialized = true;

		static constexpr char min() { return CHAR_MIN; }
		static constexpr char max() { return CHAR_MAX; }
		static constexpr char lowest() { return CHAR_MIN; }

		static constexpr int digits = CHAR_BIT;
		static constexpr int digits10 = 0;
		static constexpr int max_digits10 = 0;

		static constexpr bool is_signed = CHAR_MIN < 0;
		static constexpr bool is_integer = true;
		static constexpr bool is_exact = true;
		static constexpr int radix = 2;
		static constexpr char epsilon() { return 0; }
		static constexpr char round_error() { return 0; }

		static constexpr int min_exponent = 0;
		static constexpr int min_exponent10 = 0;
		static constexpr int max_exponent = 0;
		static constexpr int max_exponent10 = 0;

		static constexpr bool has_infinity = false;
		static constexpr bool has_quiet_NaN = false;
		static constexpr bool has_signaling_NaN = false;
		static constexpr float_denorm_style has_denorm = denorm_absent;
		static constexpr bool has_denorm_loss = false;
		static constexpr char infinity() { return 0; }
		static constexpr char quiet_NaN() { return 0; }
		static constexpr char signaling_NaN() { return 0; }
		static constexpr char denorm_min() { return 0; }

		static constexpr bool is_iec559 = false;
		static constexpr bool is_bounded = true;
		static constexpr bool is_modulo = true;

		static constexpr bool traps = false;
		static constexpr bool tinyness_before = false;
		static constexpr float_round_style round_style = round_toward_zero;
	};

	template <>
	class numeric_limits<signed char>
	{
	public:
		static constexpr bool is_specialized = true;

		static constexpr signed char min() { return SCHAR_MIN; }
		static constexpr signed char max() { return SCHAR_MAX; }
		static constexpr signed char lowest() { return SCHAR_MIN; }

		static constexpr int digits = CHAR_BIT - 1;
		static constexpr int digits10 = 0;
		static constexpr int max_digits10 = 0;

		static constexpr bool is_signed = true;
		static constexpr bool is_integer = true;
		static constexpr bool is_exact = true;
		static constexpr int radix = 2;
		static constexpr signed char epsilon() { return 0; }
		static constexpr signed char round_error() { return 0; }

		static constexpr int min_exponent = 0;
		static constexpr int min_exponent10 = 0;
		static constexpr int max_exponent = 0;
		static constexpr int max_exponent10 = 0;

		static constexpr bool has_infinity = false;
		static constexpr bool has_quiet_NaN = false;
		static constexpr bool has_signaling_NaN = false;
		static constexpr float_denorm_style has_denorm = denorm_absent;
		static constexpr bool has_denorm_loss = false;
		static constexpr signed char infinity() { return 0; }
		static constexpr signed char quiet_NaN() { return 0; }
		static constexpr signed char signaling_NaN() { return 0; }
		static constexpr signed char denorm_min() { return 0; }

		static constexpr bool is_iec559 = false;
		static constexpr bool is_bounded = true;
		static constexpr bool is_modulo = true;

		static constexpr bool traps = false;
		static constexpr bool tinyness_before = false;
		static constexpr float_round_style round_style = round_toward_zero;
	};

	template <>
	class numeric_limits<unsigned char>
	{
	public:
		static constexpr bool is_specialized = true;

		static constexpr unsigned char min() { return 0; }
		static constexpr unsigned char max() { return UCHAR_MAX; }
		static constexpr unsigned char lowest() { return 0; }

		static constexpr int digits = CHAR_BIT;
		static constexpr int digits10 = 0;
		static constexpr int max_digits10 = 0;

		static constexpr bool is_signed = false;
		static constexpr bool is_integer = true;
		static constexpr bool is_exact = true;
		static constexpr int radix = 2;
		static constexpr unsigned char epsilon() { return 0; }
		static constexpr unsigned char round_error() { return 0; }

		static constexpr int min_exponent = 0;
		static constexpr int min_exponent10 = 0;
		static constexpr int max_exponent = 0;
		static constexpr int max_exponent10 = 0;

		static constexpr bool has_infinity = false;
		static constexpr bool has_quiet_NaN = false;
		static constexpr bool has_signaling_NaN = false;
		static constexpr float_denorm_style has_denorm = denorm_absent;
		static constexpr bool has_denorm_loss = false;
		static constexpr unsigned char infinity() { return 0; }
		static constexpr unsigned char quiet_NaN() { return 0; }
		static constexpr unsigned char signaling_NaN() { return 0; }
		static constexpr unsigned char denorm_min() { return 0; }

		static constexpr bool is_iec559 = false;
		static constexpr bool is_bounded = true;
		static constexpr bool is_modulo = true;

		static constexpr bool traps = false;
		static constexpr bool tinyness_before = false;
		static constexpr float_round_style round_style = round_toward_zero;
	};

	template <>
	class numeric_limits<wchar_t>
	{
	public:
		static constexpr bool is_specialized = true;

		static constexpr wchar_t min() { return __WCHAR_MIN__; }
		static constexpr wchar_t max() { return __WCHAR_MAX__; }
		static constexpr wchar_t lowest() { return __WCHAR_MIN__; }

		static constexpr int digits = CHAR_BIT * sizeof(wchar_t) - 1;
		static constexpr int digits10 = 0;
		static constexpr int max_digits10 = 0;

		static constexpr bool is_signed = __WCHAR_MIN__ < 0;
		static constexpr bool is_integer = true;
		static constexpr bool is_exact = true;
		static constexpr int radix = 2;
		static constexpr wchar_t epsilon() { return 0; }
		static constexpr wchar_t round_error() { return 0; }

		static constexpr int min_exponent = 0;
		static constexpr int min_exponent10 = 0;
		static constexpr int max_exponent = 0;
		static constexpr int max_exponent10 = 0;

		static constexpr bool has_infinity = false;
		static constexpr bool has_quiet_NaN = false;
		static constexpr bool has_signaling_NaN = false;
		static constexpr float_denorm_style has_denorm = denorm_absent;
		static constexpr bool has_denorm_loss = false;
		static constexpr wchar_t infinity() { return 0; }
		static constexpr wchar_t quiet_NaN() { return 0; }
		static constexpr wchar_t signaling_NaN() { return 0; }
		static constexpr wchar_t denorm_min() { return 0; }

		static constexpr bool is_iec559 = false;
		static constexpr bool is_bounded = true;
		static constexpr bool is_modulo = true;

		static constexpr bool traps = false;
		static constexpr bool tinyness_before = false;
		static constexpr float_round_style round_style = round_toward_zero;
	};

	template <>
	class numeric_limits<char8_t>
	{
	public:
		static constexpr bool is_specialized = true;

		static constexpr char8_t min() { return 0; }
		static constexpr char8_t max() { return UCHAR_MAX; }
		static constexpr char8_t lowest() { return 0; }

		static constexpr int digits = CHAR_BIT;
		static constexpr int digits10 = 0;
		static constexpr int max_digits10 = 0;

		static constexpr bool is_signed = false;
		static constexpr bool is_integer = true;
		static constexpr bool is_exact = true;
		static constexpr int radix = 2;
		static constexpr char8_t epsilon() { return 0; }
		static constexpr char8_t round_error() { return 0; }

		static constexpr int min_exponent = 0;
		static constexpr int min_exponent10 = 0;
		static constexpr int max_exponent = 0;
		static constexpr int max_exponent10 = 0;

		static constexpr bool has_infinity = false;
		static constexpr bool has_quiet_NaN = false;
		static constexpr bool has_signaling_NaN = false;
		static constexpr float_denorm_style has_denorm = denorm_absent;
		static constexpr bool has_denorm_loss = false;
		static constexpr char8_t infinity() { return 0; }
		static constexpr char8_t quiet_NaN() { return 0; }
		static constexpr char8_t signaling_NaN() { return 0; }
		static constexpr char8_t denorm_min() { return 0; }

		static constexpr bool is_iec559 = false;
		static constexpr bool is_bounded = true;
		static constexpr bool is_modulo = true;

		static constexpr bool traps = false;
		static constexpr bool tinyness_before = false;
		static constexpr float_round_style round_style = round_toward_zero;
	};

	template <>
	class numeric_limits<char16_t>
	{
	public:
		static constexpr bool is_specialized = true;

		static constexpr char16_t min() { return 0; }
		static constexpr char16_t max() { return USHRT_MAX; }
		static constexpr char16_t lowest() { return 0; }

		static constexpr int digits = CHAR_BIT * sizeof(char16_t) - 1;
		static constexpr int digits10 = 0;
		static constexpr int max_digits10 = 0;

		static constexpr bool is_signed = false;
		static constexpr bool is_integer = true;
		static constexpr bool is_exact = true;
		static constexpr int radix = 2;
		static constexpr char16_t epsilon() { return 0; }
		static constexpr char16_t round_error() { return 0; }

		static constexpr int min_exponent = 0;
		static constexpr int min_exponent10 = 0;
		static constexpr int max_exponent = 0;
		static constexpr int max_exponent10 = 0;

		static constexpr bool has_infinity = false;
		static constexpr bool has_quiet_NaN = false;
		static constexpr bool has_signaling_NaN = false;
		static constexpr float_denorm_style has_denorm = denorm_absent;
		static constexpr bool has_denorm_loss = false;
		static constexpr char16_t infinity() { return 0; }
		static constexpr char16_t quiet_NaN() { return 0; }
		static constexpr char16_t signaling_NaN() { return 0; }
		static constexpr char16_t denorm_min() { return 0; }

		static constexpr bool is_iec559 = false;
		static constexpr bool is_bounded = true;
		static constexpr bool is_modulo = true;

		static constexpr bool traps = false;
		static constexpr bool tinyness_before = false;
		static constexpr float_round_style round_style = round_toward_zero;
	};

	template <>
	class numeric_limits<char32_t>
	{
	public:
		static constexpr bool is_specialized = true;

		static constexpr char32_t min() { return 0; }
		static constexpr char32_t max() { return UINT_MAX; }
		static constexpr char32_t lowest() { return 0; }

		static constexpr int digits = CHAR_BIT * sizeof(char32_t) - 1;
		static constexpr int digits10 = 0;
		static constexpr int max_digits10 = 0;

		static constexpr bool is_signed = false;
		static constexpr bool is_integer = true;
		static constexpr bool is_exact = true;
		static constexpr int radix = 2;
		static constexpr char32_t epsilon() { return 0; }
		static constexpr char32_t round_error() { return 0; }

		static constexpr int min_exponent = 0;
		static constexpr int min_exponent10 = 0;
		static constexpr int max_exponent = 0;
		static constexpr int max_exponent10 = 0;

		static constexpr bool has_infinity = false;
		static constexpr bool has_quiet_NaN = false;
		static constexpr bool has_signaling_NaN = false;
		static constexpr float_denorm_style has_denorm = denorm_absent;
		static constexpr bool has_denorm_loss = false;
		static constexpr char32_t infinity() { return 0; }
		static constexpr char32_t quiet_NaN() { return 0; }
		static constexpr char32_t signaling_NaN() { return 0; }
		static constexpr char32_t denorm_min() { return 0; }

		static constexpr bool is_iec559 = false;
		static constexpr bool is_bounded = true;
		static constexpr bool is_modulo = true;

		static constexpr bool traps = false;
		static constexpr bool tinyness_before = false;
		static constexpr float_round_style round_style = round_toward_zero;
	};

	template <>
	class numeric_limits<short>
	{
	public:
		static constexpr bool is_specialized = true;

		static constexpr short min() { return SHRT_MIN; }
		static constexpr short max() { return SHRT_MAX; }
		static constexpr short lowest() { return SHRT_MIN; }

		static constexpr int digits = CHAR_BIT * sizeof(short) - 1;
		static constexpr int digits10 = 0;
		static constexpr int max_digits10 = 0;

		static constexpr bool is_signed = true;
		static constexpr bool is_integer = true;
		static constexpr bool is_exact = true;
		static constexpr int radix = 2;
		static constexpr short epsilon() { return 0; }
		static constexpr short round_error() { return 0; }

		static constexpr int min_exponent = 0;
		static constexpr int min_exponent10 = 0;
		static constexpr int max_exponent = 0;
		static constexpr int max_exponent10 = 0;

		static constexpr bool has_infinity = false;
		static constexpr bool has_quiet_NaN = false;
		static constexpr bool has_signaling_NaN = false;
		static constexpr float_denorm_style has_denorm = denorm_absent;
		static constexpr bool has_denorm_loss = false;
		static constexpr short infinity() { return 0; }
		static constexpr short quiet_NaN() { return 0; }
		static constexpr short signaling_NaN() { return 0; }
		static constexpr short denorm_min() { return 0; }

		static constexpr bool is_iec559 = false;
		static constexpr bool is_bounded = true;
		static constexpr bool is_modulo = true;

		static constexpr bool traps = false;
		static constexpr bool tinyness_before = false;
		static constexpr float_round_style round_style = round_toward_zero;
	};

	template <>
	class numeric_limits<unsigned short>
	{
	public:
		static constexpr bool is_specialized = true;

		static constexpr unsigned short min() { return 0; }
		static constexpr unsigned short max() { return USHRT_MAX; }
		static constexpr unsigned short lowest() { return 0; }

		static constexpr int digits = CHAR_BIT * sizeof(unsigned short);
		static constexpr int digits10 = 0;
		static constexpr int max_digits10 = 0;

		static constexpr bool is_signed = false;
		static constexpr bool is_integer = true;
		static constexpr bool is_exact = true;
		static constexpr int radix = 2;
		static constexpr unsigned short epsilon() { return 0; }
		static constexpr unsigned short round_error() { return 0; }

		static constexpr int min_exponent = 0;
		static constexpr int min_exponent10 = 0;
		static constexpr int max_exponent = 0;
		static constexpr int max_exponent10 = 0;

		static constexpr bool has_infinity = false;
		static constexpr bool has_quiet_NaN = false;
		static constexpr bool has_signaling_NaN = false;
		static constexpr float_denorm_style has_denorm = denorm_absent;
		static constexpr bool has_denorm_loss = false;
		static constexpr unsigned short infinity() { return 0; }
		static constexpr unsigned short quiet_NaN() { return 0; }
		static constexpr unsigned short signaling_NaN() { return 0; }
		static constexpr unsigned short denorm_min() { return 0; }

		static constexpr bool is_iec559 = false;
		static constexpr bool is_bounded = true;
		static constexpr bool is_modulo = true;

		static constexpr bool traps = false;
		static constexpr bool tinyness_before = false;
		static constexpr float_round_style round_style = round_toward_zero;
	};

	template <>
	class numeric_limits<int>
	{
	public:
		static constexpr bool is_specialized = true;

		static constexpr int min() { return INT_MIN; }
		static constexpr int max() { return INT_MAX; }
		static constexpr int lowest() { return INT_MIN; }

		static constexpr int digits = CHAR_BIT * sizeof(int) - 1;
		static constexpr int digits10 = 0;
		static constexpr int max_digits10 = 0;

		static constexpr bool is_signed = true;
		static constexpr bool is_integer = true;
		static constexpr bool is_exact = true;
		static constexpr int radix = 2;
		static constexpr int epsilon() { return 0; }
		static constexpr int round_error() { return 0; }

		static constexpr int min_exponent = 0;
		static constexpr int min_exponent10 = 0;
		static constexpr int max_exponent = 0;
		static constexpr int max_exponent10 = 0;

		static constexpr bool has_infinity = false;
		static constexpr bool has_quiet_NaN = false;
		static constexpr bool has_signaling_NaN = false;
		static constexpr float_denorm_style has_denorm = denorm_absent;
		static constexpr bool has_denorm_loss = false;
		static constexpr int infinity() { return 0; }
		static constexpr int quiet_NaN() { return 0; }
		static constexpr int signaling_NaN() { return 0; }
		static constexpr int denorm_min() { return 0; }

		static constexpr bool is_iec559 = false;
		static constexpr bool is_bounded = true;
		static constexpr bool is_modulo = true;

		static constexpr bool traps = false;
		static constexpr bool tinyness_before = false;
		static constexpr float_round_style round_style = round_toward_zero;
	};

	template <>
	class numeric_limits<unsigned int>
	{
	public:
		static constexpr bool is_specialized = true;

		static constexpr unsigned int min() { return 0; }
		static constexpr unsigned int max() { return UINT_MAX; }
		static constexpr unsigned int lowest() { return 0; }

		static constexpr int digits = CHAR_BIT * sizeof(unsigned int);
		static constexpr int digits10 = 0;
		static constexpr int max_digits10 = 0;

		static constexpr bool is_signed = false;
		static constexpr bool is_integer = true;
		static constexpr bool is_exact = true;
		static constexpr int radix = 2;
		static constexpr unsigned int epsilon() { return 0; }
		static constexpr unsigned int round_error() { return 0; }

		static constexpr int min_exponent = 0;
		static constexpr int min_exponent10 = 0;
		static constexpr int max_exponent = 0;
		static constexpr int max_exponent10 = 0;

		static constexpr bool has_infinity = false;
		static constexpr bool has_quiet_NaN = false;
		static constexpr bool has_signaling_NaN = false;
		static constexpr float_denorm_style has_denorm = denorm_absent;
		static constexpr bool has_denorm_loss = false;
		static constexpr unsigned int infinity() { return 0; }
		static constexpr unsigned int quiet_NaN() { return 0; }
		static constexpr unsigned int signaling_NaN() { return 0; }
		static constexpr unsigned int denorm_min() { return 0; }

		static constexpr bool is_iec559 = false;
		static constexpr bool is_bounded = true;
		static constexpr bool is_modulo = true;

		static constexpr bool traps = false;
		static constexpr bool tinyness_before = false;
		static constexpr float_round_style round_style = round_toward_zero;
	};

	template <>
	class numeric_limits<long>
	{
	public:
		static constexpr bool is_specialized = true;

		static constexpr long min() { return LONG_MIN; }
		static constexpr long max() { return LONG_MAX; }
		static constexpr long lowest() { return LONG_MIN; }

		static constexpr int digits = CHAR_BIT * sizeof(long) - 1;
		static constexpr int digits10 = 0;
		static constexpr int max_digits10 = 0;

		static constexpr bool is_signed = true;
		static constexpr bool is_integer = true;
		static constexpr bool is_exact = true;
		static constexpr int radix = 2;
		static constexpr long epsilon() { return 0; }
		static constexpr long round_error() { return 0; }

		static constexpr int min_exponent = 0;
		static constexpr int min_exponent10 = 0;
		static constexpr int max_exponent = 0;
		static constexpr int max_exponent10 = 0;

		static constexpr bool has_infinity = false;
		static constexpr bool has_quiet_NaN = false;
		static constexpr bool has_signaling_NaN = false;
		static constexpr float_denorm_style has_denorm = denorm_absent;
		static constexpr bool has_denorm_loss = false;
		static constexpr long infinity() { return 0; }
		static constexpr long quiet_NaN() { return 0; }
		static constexpr long signaling_NaN() { return 0; }
		static constexpr long denorm_min() { return 0; }

		static constexpr bool is_iec559 = false;
		static constexpr bool is_bounded = true;
		static constexpr bool is_modulo = true;

		static constexpr bool traps = false;
		static constexpr bool tinyness_before = false;
		static constexpr float_round_style round_style = round_toward_zero;
	};

	template <>
	class numeric_limits<unsigned long>
	{
	public:
		static constexpr bool is_specialized = true;

		static constexpr unsigned long min() { return 0; }
		static constexpr unsigned long max() { return ULONG_MAX; }
		static constexpr unsigned long lowest() { return 0; }

		static constexpr int digits = CHAR_BIT * sizeof(unsigned long);
		static constexpr int digits10 = 0;
		static constexpr int max_digits10 = 0;

		static constexpr bool is_signed = false;
		static constexpr bool is_integer = true;
		static constexpr bool is_exact = true;
		static constexpr int radix = 2;
		static constexpr unsigned long epsilon() { return 0; }
		static constexpr unsigned long round_error() { return 0; }

		static constexpr int min_exponent = 0;
		static constexpr int min_exponent10 = 0;
		static constexpr int max_exponent = 0;
		static constexpr int max_exponent10 = 0;

		static constexpr bool has_infinity = false;
		static constexpr bool has_quiet_NaN = false;
		static constexpr bool has_signaling_NaN = false;
		static constexpr float_denorm_style has_denorm = denorm_absent;
		static constexpr bool has_denorm_loss = false;
		static constexpr unsigned long infinity() { return 0; }
		static constexpr unsigned long quiet_NaN() { return 0; }
		static constexpr unsigned long signaling_NaN() { return 0; }
		static constexpr unsigned long denorm_min() { return 0; }

		static constexpr bool is_iec559 = false;
		static constexpr bool is_bounded = true;
		static constexpr bool is_modulo = true;

		static constexpr bool traps = false;
		static constexpr bool tinyness_before = false;
		static constexpr float_round_style round_style = round_toward_zero;
	};

	template <>
	class numeric_limits<long long>
	{
	public:
		static constexpr bool is_specialized = true;

		static constexpr long long min() { return LLONG_MIN; }
		static constexpr long long max() { return LLONG_MAX; }
		static constexpr long long lowest() { return LLONG_MIN; }

		static constexpr int digits = CHAR_BIT * sizeof(long long) - 1;
		static constexpr int digits10 = 0;
		static constexpr int max_digits10 = 0;

		static constexpr bool is_signed = true;
		static constexpr bool is_integer = true;
		static constexpr bool is_exact = true;
		static constexpr int radix = 2;
		static constexpr long long epsilon() { return 0; }
		static constexpr long long round_error() { return 0; }

		static constexpr int min_exponent = 0;
		static constexpr int min_exponent10 = 0;
		static constexpr int max_exponent = 0;
		static constexpr int max_exponent10 = 0;

		static constexpr bool has_infinity = false;
		static constexpr bool has_quiet_NaN = false;
		static constexpr bool has_signaling_NaN = false;
		static constexpr float_denorm_style has_denorm = denorm_absent;
		static constexpr bool has_denorm_loss = false;
		static constexpr long long infinity() { return 0; }
		static constexpr long long quiet_NaN() { return 0; }
		static constexpr long long signaling_NaN() { return 0; }
		static constexpr long long denorm_min() { return 0; }

		static constexpr bool is_iec559 = false;
		static constexpr bool is_bounded = true;
		static constexpr bool is_modulo = true;

		static constexpr bool traps = false;
		static constexpr bool tinyness_before = false;
		static constexpr float_round_style round_style = round_toward_zero;
	};

	template <>
	class numeric_limits<unsigned long long>
	{
	public:
		static constexpr bool is_specialized = true;

		static constexpr unsigned long long min() { return 0; }
		static constexpr unsigned long long max() { return ULLONG_MAX; }
		static constexpr unsigned long long lowest() { return 0; }

		static constexpr int digits = CHAR_BIT * sizeof(unsigned long long);
		static constexpr int digits10 = 0;
		static constexpr int max_digits10 = 0;

		static constexpr bool is_signed = false;
		static constexpr bool is_integer = true;
		static constexpr bool is_exact = true;
		static constexpr int radix = 2;
		static constexpr unsigned long long epsilon() { return 0; }
		static constexpr unsigned long long round_error() { return 0; }

		static constexpr int min_exponent = 0;
		static constexpr int min_exponent10 = 0;
		static constexpr int max_exponent = 0;
		static constexpr int max_exponent10 = 0;

		static constexpr bool has_infinity = false;
		static constexpr bool has_quiet_NaN = false;
		static constexpr bool has_signaling_NaN = false;
		static constexpr float_denorm_style has_denorm = denorm_absent;
		static constexpr bool has_denorm_loss = false;
		static constexpr unsigned long long infinity() { return 0; }
		static constexpr unsigned long long quiet_NaN() { return 0; }
		static constexpr unsigned long long signaling_NaN() { return 0; }
		static constexpr unsigned long long denorm_min() { return 0; }

		static constexpr bool is_iec559 = false;
		static constexpr bool is_bounded = true;
		static constexpr bool is_modulo = true;

		static constexpr bool traps = false;
		static constexpr bool tinyness_before = false;
		static constexpr float_round_style round_style = round_toward_zero;
	};

	template <>
	class numeric_limits<float>
	{
	public:
		static constexpr bool is_specialized = true;

		static constexpr float min() { return FLT_MIN; }
		static constexpr float max() { return FLT_MAX; }
		static constexpr float lowest() { return -FLT_MAX; }

		static constexpr int digits = FLT_MANT_DIG;
		static constexpr int digits10 = FLT_DIG;
		static constexpr int max_digits10 = FLT_DECIMAL_DIG;

		static constexpr bool is_signed = true;
		static constexpr bool is_integer = false;
		static constexpr bool is_exact = false;
		static constexpr int radix = FLT_RADIX;
		static constexpr float epsilon() { return FLT_EPSILON; }
		static constexpr float round_error() { return 0.5f; }

		static constexpr int min_exponent = FLT_MIN_EXP;
		static constexpr int min_exponent10 = FLT_MIN_10_EXP;
		static constexpr int max_exponent = FLT_MAX_EXP;
		static constexpr int max_exponent10 = FLT_MAX_10_EXP;

		static constexpr bool has_infinity = true;
		static constexpr bool has_quiet_NaN = true;
		static constexpr bool has_signaling_NaN = true;
		static constexpr float_denorm_style has_denorm = denorm_present;
		static constexpr bool has_denorm_loss = true;
		static constexpr float infinity() { return INFINITY; }
		static constexpr float quiet_NaN() { return NAN; }
		static constexpr float signaling_NaN() { return NAN; }
		static constexpr float denorm_min() { return FLT_TRUE_MIN; }

		static constexpr bool is_iec559 = true;
		static constexpr bool is_bounded = true;
		static constexpr bool is_modulo = false;

		static constexpr bool traps = true;
		static constexpr bool tinyness_before = false;
		static constexpr float_round_style round_style = round_to_nearest;
	};

	template <>
	class numeric_limits<double>
	{
	public:
		static constexpr bool is_specialized = true;

		static constexpr double min() { return DBL_MIN; }
		static constexpr double max() { return DBL_MAX; }
		static constexpr double lowest() { return -DBL_MAX; }

		static constexpr int digits = DBL_MANT_DIG;
		static constexpr int digits10 = DBL_DIG;
		static constexpr int max_digits10 = DBL_DECIMAL_DIG;

		static constexpr bool is_signed = true;
		static constexpr bool is_integer = false;
		static constexpr bool is_exact = false;
		static constexpr int radix = FLT_RADIX;
		static constexpr double epsilon() { return DBL_EPSILON; }
		static constexpr double round_error() { return 0.5; }

		static constexpr int min_exponent = DBL_MIN_EXP;
		static constexpr int min_exponent10 = DBL_MIN_10_EXP;
		static constexpr int max_exponent = DBL_MAX_EXP;
		static constexpr int max_exponent10 = DBL_MAX_10_EXP;

		static constexpr bool has_infinity = true;
		static constexpr bool has_quiet_NaN = true;
		static constexpr bool has_signaling_NaN = true;
		static constexpr float_denorm_style has_denorm = denorm_present;
		static constexpr bool has_denorm_loss = true;
		static constexpr double infinity() { return INFINITY; }
		static constexpr double quiet_NaN() { return NAN; }
		static constexpr double signaling_NaN() { return NAN; }
		static constexpr double denorm_min() { return DBL_TRUE_MIN; }

		static constexpr bool is_iec559 = true;
		static constexpr bool is_bounded = true;
		static constexpr bool is_modulo = false;

		static constexpr bool traps = true;
		static constexpr bool tinyness_before = false;
		static constexpr float_round_style round_style = round_to_nearest;
	};

	template <>
	class numeric_limits<long double>
	{
	public:
		static constexpr bool is_specialized = true;

		static constexpr long double min() { return LDBL_MIN; }
		static constexpr long double max() { return LDBL_MAX; }
		static constexpr long double lowest() { return -LDBL_MAX; }

		static constexpr int digits = LDBL_MANT_DIG;
		static constexpr int digits10 = LDBL_DIG;
		static constexpr int max_digits10 = LDBL_DECIMAL_DIG;

		static constexpr bool is_signed = true;
		static constexpr bool is_integer = false;
		static constexpr bool is_exact = false;
		static constexpr int radix = FLT_RADIX;
		static constexpr long double epsilon() { return LDBL_EPSILON; }
		static constexpr long double round_error() { return 0.5L; }

		static constexpr int min_exponent = LDBL_MIN_EXP;
		static constexpr int min_exponent10 = LDBL_MIN_10_EXP;
		static constexpr int max_exponent = LDBL_MAX_EXP;
		static constexpr int max_exponent10 = LDBL_MAX_10_EXP;

		static constexpr bool has_infinity = true;
		static constexpr bool has_quiet_NaN = true;
		static constexpr bool has_signaling_NaN = true;
		static constexpr float_denorm_style has_denorm = denorm_present;
		static constexpr bool has_denorm_loss = true;
		static constexpr long double infinity() { return INFINITY; }
		static constexpr long double quiet_NaN() { return NAN; }
		static constexpr long double signaling_NaN() { return NAN; }
		static constexpr long double denorm_min() { return LDBL_TRUE_MIN; }

		static constexpr bool is_iec559 = true;
		static constexpr bool is_bounded = true;
		static constexpr bool is_modulo = false;

		static constexpr bool traps = true;
		static constexpr bool tinyness_before = false;
		static constexpr float_round_style round_style = round_to_nearest;
	};
}
