// =====================================================================================================================
//  fennec, a free and open source game engine
//  Copyright © 2025  Medusa Slockbower
//
//  This program 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.
//
//  This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================

///
/// \file limits.h
/// \brief \ref fennec_lang_limits
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///


#ifndef FENNEC_LANG_LIMITS_H
#define FENNEC_LANG_LIMITS_H

///
/// \page fennec_lang_limits Limits
///
/// \brief This header defines fennec::numeric_limits which contains info regarding the limits of numeric types including
///        floats and integers. There are overloads for all builtin types, and overloads for other types are included in
///        their own header.
///
/// \code{.cpp}#include <fennec/lang/limits.h>\endcode
///
/// \section fennec_lang_limits_numeric_limits Numeric Limits
/// <table width="100%" class="fieldtable" id="table_fennec_lang_limits">
/// <tr><th style="vertical-align: top">Member
///     <th style="vertical-align: top">Description
/// <tr><th colspan=2 style="text-align: center;">Traits
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::is_specialized "is_specialized"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::is_specialized
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::is_signed "is_signed"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::is_signed
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::is_integer "is_integer"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::is_integer
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::is_exact "is_exact"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::is_exact
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::has_infinity "has_infinity"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::has_infinity
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::has_quiet_nan "has_quiet_nan"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::has_quiet_nan
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::has_signaling_nan "has_signaling_nan"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::has_signaling_nan
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::is_iec559 "is_iec559"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::is_iec559
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::is_bounded "is_bounded"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::is_bounded
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::is_modulo "is_modulo"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::is_modulo
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::tinyness_before "tinyness_before"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::tinyness_before
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::traps "traps"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::traps
///
/// <tr><th colspan=2 style="text-align: center;">Binary
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::radix "radix"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::radix
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::digits "digits"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::digits
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::digits10 "digits10"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::digits10
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::max_digits10 "max_digits10"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::max_digits10
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::min_exponent "min_exponent"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::min_exponent
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::min_exponent10 "min_exponent10"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::min_exponent10
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::max_exponent "max_exponent"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::max_exponent
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::max_exponent10 "max_exponent10"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::max_exponent10
///
/// <tr><th colspan=2 style="text-align: center;">Limits
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::min "min()"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::min
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::max "max()"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::max
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::lowest "lowest()"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::lowest
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::epsilon "epsilon()"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::epsilon
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::round_error "round_error()"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::round_error
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::infinity "infinity()"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::infinity
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::quiet_NaN "quiet_NaN()"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::quiet_NaN
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::signaling_NaN "signaling_NaN()"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::signaling_NaN
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///		<tt>\ref fennec::numeric_limits::denorm_min "denorm_min()"</tt>
///     <td width="50%" style="vertical-align: top">
///     \copybrief fennec::numeric_limits::denorm_min
///
/// </table>
///
///

#include <fennec/lang/types.h>
#include <fennec/lang/type_traits.h>

#include <fennec/lang/integer.h>
#include <fennec/lang/float.h>

namespace fennec
{

///
/// \brief enum for determining rounding styles
enum float_round_style
{
	round_indeterminate       = -1
,	round_toward_zero         =  0
,	round_to_nearest          =  1
,	round_toward_infinity     =  2
,	round_toward_neg_infinity =  3
};

///
/// \brief Helper for getting traits of a numeric type
/// \tparam TypeT Numeric types, may be overloaded for custom types
template<typename TypeT> struct numeric_limits
{
	static constexpr bool is_specialized    = false; ///< Check if the template is specialized for TypeT
	static constexpr bool is_signed         = false; ///< Check if TypeT is signed
	static constexpr bool is_integer        = false; ///< Check if TypeT is of an integral type
	static constexpr bool is_exact          = false; ///< Check if TypeT is exact in its precision
	static constexpr bool has_infinity      = false; ///< Check if TypeT can hold a value representing infinity
	static constexpr bool has_quiet_nan     = false; ///< Check if TypeT can hold a non-signaling nan
	static constexpr bool has_signaling_nan = false; ///< Check if TypeT can hold a signaling nan
	static constexpr bool has_denorm        = false; ///< Check if TypeT denormalizes
	static constexpr bool has_denorm_loss   = false; ///< Check if TypeT has precision loss when denormalized
	static constexpr bool is_iec559         = false; ///< Check if a TypeT representing a float is IEC 559 or IEEE 754
	static constexpr bool is_bounded        = false; ///< Check if TypeT represents a finite set of values
	static constexpr bool is_modulo         = false; ///< Check if TypeT can handle modulo arithmetic
	static constexpr bool tinyness_before   = false; ///< Check if TypeT checks for tinyness before rounding
	static constexpr bool traps             = false; ///< Check if TypeT can cause operations to trap

	static constexpr int  radix             = 0; ///< Get the base representation of the type
	static constexpr int  digits            = 0; ///< Get the number of radix digits TypeT represents
	static constexpr int  digits10          = 0; ///< Get the number of decimal digits TypeT represents
	static constexpr int  max_digits10      = 0; ///< Get the maximum number of decimal digits TypeT represents
	static constexpr int  min_exponent      = 0; ///< Get the minimum number of radix digits that represent the exponent of TypeT
	static constexpr int  min_exponent10    = 0; ///< Get the minimum number of decimal digits that represent the exponent of TypeT
	static constexpr int  max_exponent      = 0; ///< Get the maximum number of radix digits that represent the exponent of TypeT
	static constexpr int  max_exponent10    = 0; ///< Get the maximum number of decimal digits that represent the exponent of TypeT

	static constexpr float_round_style rounding_style = round_indeterminate; ///< The rounding style of TypeT

	// This is very poorly named and defined in the C++ Standard so these functions differ
	static constexpr TypeT min()           { return TypeT(); } ///< Returns the minimum finite value of TypeT
	static constexpr TypeT max()           { return TypeT(); } ///< Returns the maximum finite value of TypeT
	static constexpr TypeT lowest()        { return TypeT(); } ///< Returns the smallest positive value of TypeT
	static constexpr TypeT epsilon()       { return TypeT(); } ///< Returns the difference between 1.0 and the next representable value
	static constexpr TypeT round_error()   { return TypeT(); } ///< Returns the max rounding error of TypeT
	static constexpr TypeT infinity()      { return TypeT(); } ///< Returns a value of TypeT holding a positive infinity
	static constexpr TypeT quiet_NaN()     { return TypeT(); } ///< Returns a value of TypeT holding a quiet NaN
	static constexpr TypeT signaling_NaN() { return TypeT(); } ///< Returns a value of TypeT holding a signaling NaN
	static constexpr TypeT denorm_min()    { return TypeT(); } ///< Returns a value of TypeT holding the smallest positive subnormal
};

// Overload definitions for basic types

// Overload for the builtin floating point type
template<> struct numeric_limits<float>
{
	static constexpr bool is_specialized    = true;
	static constexpr bool is_signed         = true;
	static constexpr bool is_integer        = false;
	static constexpr bool is_exact          = false;
	static constexpr bool has_infinity      = FLT_HAS_INFINITY;
	static constexpr bool has_quiet_nan     = FLT_HAS_QUIET_NAN;
	static constexpr bool has_signaling_nan = FLT_HAS_SIGNALING_NAN;
	static constexpr bool has_denorm        = FLT_HAS_DENORM;
	static constexpr bool has_denorm_loss   = FLT_HAS_DENORM_LOSS;
	static constexpr bool is_iec559         = FLT_IS_IEC559;
	static constexpr bool is_bounded        = true;
	static constexpr bool is_modulo         = false;
	static constexpr bool tinyness_before   = FLT_TINYNESS_BEFORE;
	static constexpr bool traps             = FLT_TRAPS;

	static constexpr int  digits            = FLT_MANT_DIG;
	static constexpr int  digits10          = FLT_DIG;
	static constexpr int  max_digits10      = FLT_DECIMAL_DIG;
	static constexpr int  radix             = FLT_RADIX;
	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 float min()           { return -FLT_MAX;           }
	static constexpr float max()           { return  FLT_MAX;           }
	static constexpr float lowest()        { return  FLT_MIN;           }
	static constexpr float epsilon()       { return  FLT_EPSILON;       }
	static constexpr float round_error()   { return  FLT_ROUND_ERR;     }
	static constexpr float infinity()      { return  FLT_INF;           }
	static constexpr float quiet_NaN()     { return  FLT_QUIET_NAN;     }
	static constexpr float signaling_NaN() { return  FLT_SIGNALING_NAN; }
	static constexpr float denorm_min()    { return  FLT_DENORM_MIN;    }
};

// Overload for the bultin double precision floating point type
template<> struct numeric_limits<double>
{
	static constexpr bool is_specialized    = true;
	static constexpr bool is_signed         = true;
	static constexpr bool is_integer        = false;
	static constexpr bool is_exact          = false;
	static constexpr bool has_infinity      = DBL_HAS_INFINITY;
	static constexpr bool has_quiet_nan     = DBL_HAS_QUIET_NAN;
	static constexpr bool has_signaling_nan = DBL_HAS_SIGNALING_NAN;
	static constexpr bool has_denorm        = DBL_HAS_DENORM;
	static constexpr bool has_denorm_loss   = DBL_HAS_DENORM_LOSS;
	static constexpr bool is_iec559         = DBL_IS_IEC559;
	static constexpr bool is_bounded        = true;
	static constexpr bool is_modulo         = false;
	static constexpr bool tinyness_before   = DBL_TINYNESS_BEFORE;
	static constexpr bool traps             = DBL_TRAPS;

	static constexpr int  digits            = DBL_MANT_DIG;
	static constexpr int  digits10          = DBL_DIG;
	static constexpr int  max_digits10      = DBL_DECIMAL_DIG;
	static constexpr int  radix             = DBL_RADIX;
	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 double min()           { return -DBL_MAX;           }
	static constexpr double max()           { return  DBL_MAX;           }
	static constexpr double lowest()        { return  DBL_MIN;           }
	static constexpr double epsilon()       { return  DBL_EPSILON;       }
	static constexpr double round_error()   { return  DBL_ROUND_ERR;     }
	static constexpr double infinity()      { return  DBL_INF;           }
	static constexpr double quiet_NaN()     { return  DBL_QUIET_NAN;     }
	static constexpr double signaling_NaN() { return  DBL_SIGNALING_NAN; }
	static constexpr double denorm_min()    { return  DBL_DENORM_MIN;    }
};

// Overload for the builtin char type
template<> struct numeric_limits<char>
{
	static constexpr bool is_specialized    = true;
	static constexpr bool is_signed         = CHAR_IS_SIGNED;
	static constexpr bool is_integer        = true;
	static constexpr bool is_exact          = true;
	static constexpr bool has_infinity      = false;
	static constexpr bool has_quiet_nan     = false;
	static constexpr bool has_signaling_nan = false;
	static constexpr bool has_denorm        = false;
	static constexpr bool has_denorm_loss   = false;
	static constexpr bool is_iec559         = false;
	static constexpr bool is_bounded        = true;
	static constexpr bool is_modulo         = true;
	static constexpr bool tinyness_before   = false;
	static constexpr bool traps             = true;

	static constexpr int  digits            = CHAR_RADIX_DIG;
	static constexpr int  digits10          = CHAR_DIG;
	static constexpr int  max_digits10      = CHAR_DECIMAL_DIG;
	static constexpr int  radix             = CHAR_RADIX;
	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 char min()           { return  static_cast<char>(CHAR_MIN); }
	static constexpr char max()           { return  CHAR_MAX; }
	static constexpr char lowest()        { return  1;        }
	static constexpr char epsilon()       { return  1;        }
	static constexpr char round_error()   { return  0;        }
	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;        }
};

// Overload for the builtin signed char type
template<> struct numeric_limits<signed char>
{
	static constexpr bool is_specialized    = true;
	static constexpr bool is_signed         = true;
	static constexpr bool is_integer        = true;
	static constexpr bool is_exact          = true;
	static constexpr bool has_infinity      = false;
	static constexpr bool has_quiet_nan     = false;
	static constexpr bool has_signaling_nan = false;
	static constexpr bool has_denorm        = false;
	static constexpr bool has_denorm_loss   = false;
	static constexpr bool is_iec559         = false;
	static constexpr bool is_bounded        = true;
	static constexpr bool is_modulo         = true;
	static constexpr bool tinyness_before   = false;
	static constexpr bool traps             = true;

	static constexpr int  digits            = SCHAR_RADIX_DIG;
	static constexpr int  digits10          = SCHAR_DIG;
	static constexpr int  max_digits10      = SCHAR_DECIMAL_DIG;
	static constexpr int  radix             = SCHAR_RADIX;
	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 signed char min()           { return static_cast<signed char>(SCHAR_MIN); }
	static constexpr signed char max()           { return SCHAR_MAX; }
	static constexpr signed char lowest()        { return 1;         }
	static constexpr signed char epsilon()       { return 1;         }
	static constexpr signed char round_error()   { return 0;         }
	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;         }
};

// Overload for the builtin signed char type
template<> struct numeric_limits<unsigned char>
{
	static constexpr bool is_specialized    = true;
	static constexpr bool is_signed         = false;
	static constexpr bool is_integer        = true;
	static constexpr bool is_exact          = true;
	static constexpr bool has_infinity      = false;
	static constexpr bool has_quiet_nan     = false;
	static constexpr bool has_signaling_nan = false;
	static constexpr bool has_denorm        = false;
	static constexpr bool has_denorm_loss   = false;
	static constexpr bool is_iec559         = false;
	static constexpr bool is_bounded        = true;
	static constexpr bool is_modulo         = true;
	static constexpr bool tinyness_before   = false;
	static constexpr bool traps             = true;

	static constexpr int  digits            = UCHAR_RADIX_DIG;
	static constexpr int  digits10          = UCHAR_DIG;
	static constexpr int  max_digits10      = UCHAR_DECIMAL_DIG;
	static constexpr int  radix             = UCHAR_RADIX;
	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 unsigned char min()           { return UCHAR_MIN;     }
	static constexpr unsigned char max()           { return UCHAR_MAX;     }
	static constexpr unsigned char lowest()        { return 1;             }
	static constexpr unsigned char epsilon()       { return 1;             }
	static constexpr unsigned char round_error()   { return 0;             }
	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;             }
};

// Overload for the builtin signed char type
template<> struct numeric_limits<short>
{
	static constexpr bool is_specialized    = true;
	static constexpr bool is_signed         = true;
	static constexpr bool is_integer        = true;
	static constexpr bool is_exact          = true;
	static constexpr bool has_infinity      = false;
	static constexpr bool has_quiet_nan     = false;
	static constexpr bool has_signaling_nan = false;
	static constexpr bool has_denorm        = false;
	static constexpr bool has_denorm_loss   = false;
	static constexpr bool is_iec559         = false;
	static constexpr bool is_bounded        = true;
	static constexpr bool is_modulo         = true;
	static constexpr bool tinyness_before   = false;
	static constexpr bool traps             = true;

	static constexpr int  digits            = SHORT_RADIX_DIG;
	static constexpr int  digits10          = SHORT_DIG;
	static constexpr int  max_digits10      = SHORT_DECIMAL_DIG;
	static constexpr int  radix             = SHORT_RADIX;
	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 short min()           { return static_cast<short>(SHORT_MIN); }
	static constexpr short max()           { return SHORT_MAX; }
	static constexpr short lowest()        { return 1;         }
	static constexpr short epsilon()       { return 1;         }
	static constexpr short round_error()   { return 0;         }
	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;         }
};

// Overload for the builtin signed char type
template<> struct numeric_limits<unsigned short>
{
	static constexpr bool is_specialized    = true;
	static constexpr bool is_signed         = false;
	static constexpr bool is_integer        = true;
	static constexpr bool is_exact          = true;
	static constexpr bool has_infinity      = false;
	static constexpr bool has_quiet_nan     = false;
	static constexpr bool has_signaling_nan = false;
	static constexpr bool has_denorm        = false;
	static constexpr bool has_denorm_loss   = false;
	static constexpr bool is_iec559         = false;
	static constexpr bool is_bounded        = true;
	static constexpr bool is_modulo         = true;
	static constexpr bool tinyness_before   = false;
	static constexpr bool traps             = true;

	static constexpr int  digits            = USHORT_RADIX_DIG;
	static constexpr int  digits10          = USHORT_DIG;
	static constexpr int  max_digits10      = USHORT_DECIMAL_DIG;
	static constexpr int  radix             = USHORT_RADIX;
	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 unsigned short min()           { return USHORT_MIN; }
	static constexpr unsigned short max()           { return USHORT_MAX; }
	static constexpr unsigned short lowest()        { return 1;          }
	static constexpr unsigned short epsilon()       { return 1;          }
	static constexpr unsigned short round_error()   { return 0;          }
	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;          }
};

// Overload for the builtin signed char type
template<> struct numeric_limits<int>
{
	static constexpr bool is_specialized    = true;
	static constexpr bool is_signed         = true;
	static constexpr bool is_integer        = true;
	static constexpr bool is_exact          = true;
	static constexpr bool has_infinity      = false;
	static constexpr bool has_quiet_nan     = false;
	static constexpr bool has_signaling_nan = false;
	static constexpr bool has_denorm        = false;
	static constexpr bool has_denorm_loss   = false;
	static constexpr bool is_iec559         = false;
	static constexpr bool is_bounded        = true;
	static constexpr bool is_modulo         = true;
	static constexpr bool tinyness_before   = false;
	static constexpr bool traps             = true;

	static constexpr int  digits            = INT_RADIX_DIG;
	static constexpr int  digits10          = INT_DIG;
	static constexpr int  max_digits10      = INT_DECIMAL_DIG;
	static constexpr int  radix             = INT_RADIX;
	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 int min()           { return INT_MIN; }
	static constexpr int max()           { return INT_MAX; }
	static constexpr int lowest()        { return 1;       }
	static constexpr int epsilon()       { return 1;       }
	static constexpr int round_error()   { return 0;       }
	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;       }
};

// Overload for the builtin signed char type
template<> struct numeric_limits<unsigned int>
{
	static constexpr bool is_specialized    = true;
	static constexpr bool is_signed         = false;
	static constexpr bool is_integer        = true;
	static constexpr bool is_exact          = true;
	static constexpr bool has_infinity      = false;
	static constexpr bool has_quiet_nan     = false;
	static constexpr bool has_signaling_nan = false;
	static constexpr bool has_denorm        = false;
	static constexpr bool has_denorm_loss   = false;
	static constexpr bool is_iec559         = false;
	static constexpr bool is_bounded        = true;
	static constexpr bool is_modulo         = true;
	static constexpr bool tinyness_before   = false;
	static constexpr bool traps             = true;

	static constexpr int  digits            = UINT_RADIX_DIG;
	static constexpr int  digits10          = UINT_DIG;
	static constexpr int  max_digits10      = UINT_DECIMAL_DIG;
	static constexpr int  radix             = UINT_RADIX;
	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 unsigned int min()           { return UINT_MIN; }
	static constexpr unsigned int max()           { return UINT_MAX; }
	static constexpr unsigned int lowest()        { return 1;        }
	static constexpr unsigned int epsilon()       { return 1;        }
	static constexpr unsigned int round_error()   { return 0;        }
	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;        }
};

// Overload for the builtin signed char type
template<> struct numeric_limits<long int>
{
	static constexpr bool is_specialized    = true;
	static constexpr bool is_signed         = true;
	static constexpr bool is_integer        = true;
	static constexpr bool is_exact          = true;
	static constexpr bool has_infinity      = false;
	static constexpr bool has_quiet_nan     = false;
	static constexpr bool has_signaling_nan = false;
	static constexpr bool has_denorm        = false;
	static constexpr bool has_denorm_loss   = false;
	static constexpr bool is_iec559         = false;
	static constexpr bool is_bounded        = true;
	static constexpr bool is_modulo         = true;
	static constexpr bool tinyness_before   = false;
	static constexpr bool traps             = true;

	static constexpr int  digits            = LONG_RADIX_DIG;
	static constexpr int  digits10          = LONG_DIG;
	static constexpr int  max_digits10      = LONG_DECIMAL_DIG;
	static constexpr int  radix             = LONG_RADIX;
	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 long int min()           { return LONG_MIN; }
	static constexpr long int max()           { return LONG_MAX; }
	static constexpr long int lowest()        { return 1;        }
	static constexpr long int epsilon()       { return 1;        }
	static constexpr long int round_error()   { return 0;        }
	static constexpr long int infinity()      { return 0;        }
	static constexpr long int quiet_NaN()     { return 0;        }
	static constexpr long int signaling_NaN() { return 0;        }
	static constexpr long int denorm_min()    { return 0;        }
};

// Overload for the builtin signed char type
template<> struct numeric_limits<unsigned long int>
{
	static constexpr bool is_specialized    = true;
	static constexpr bool is_signed         = false;
	static constexpr bool is_integer        = true;
	static constexpr bool is_exact          = true;
	static constexpr bool has_infinity      = false;
	static constexpr bool has_quiet_nan     = false;
	static constexpr bool has_signaling_nan = false;
	static constexpr bool has_denorm        = false;
	static constexpr bool has_denorm_loss   = false;
	static constexpr bool is_iec559         = false;
	static constexpr bool is_bounded        = true;
	static constexpr bool is_modulo         = true;
	static constexpr bool tinyness_before   = false;
	static constexpr bool traps             = true;

	static constexpr int  digits            = ULONG_RADIX_DIG;
	static constexpr int  digits10          = ULONG_DIG;
	static constexpr int  max_digits10      = ULONG_DECIMAL_DIG;
	static constexpr int  radix             = ULONG_RADIX;
	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 unsigned long min()           { return ULONG_MIN; }
	static constexpr unsigned long max()           { return ULONG_MAX; }
	static constexpr unsigned long lowest()        { return 1;         }
	static constexpr unsigned long epsilon()       { return 1;         }
	static constexpr unsigned long round_error()   { return 0;         }
	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;         }
};

// Overload for the builtin signed char type
template<> struct numeric_limits<long long>
{
	static constexpr bool is_specialized    = true;
	static constexpr bool is_signed         = true;
	static constexpr bool is_integer        = true;
	static constexpr bool is_exact          = true;
	static constexpr bool has_infinity      = false;
	static constexpr bool has_quiet_nan     = false;
	static constexpr bool has_signaling_nan = false;
	static constexpr bool has_denorm        = false;
	static constexpr bool has_denorm_loss   = false;
	static constexpr bool is_iec559         = false;
	static constexpr bool is_bounded        = true;
	static constexpr bool is_modulo         = true;
	static constexpr bool tinyness_before   = false;
	static constexpr bool traps             = true;

	static constexpr int  digits            = LLONG_RADIX_DIG;
	static constexpr int  digits10          = LLONG_DIG;
	static constexpr int  max_digits10      = LLONG_DECIMAL_DIG;
	static constexpr int  radix             = LLONG_RADIX;
	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 long long min()           { return LLONG_MIN; }
	static constexpr long long max()           { return LLONG_MAX; }
	static constexpr long long lowest()        { return 1;        }
	static constexpr long long epsilon()       { return 1;        }
	static constexpr long long round_error()   { return 0;        }
	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;        }
};

// Overload for the builtin signed char type
template<> struct numeric_limits<unsigned long long>
{
	static constexpr bool is_specialized    = true;
	static constexpr bool is_signed         = false;
	static constexpr bool is_integer        = true;
	static constexpr bool is_exact          = true;
	static constexpr bool has_infinity      = false;
	static constexpr bool has_quiet_nan     = false;
	static constexpr bool has_signaling_nan = false;
	static constexpr bool has_denorm        = false;
	static constexpr bool has_denorm_loss   = false;
	static constexpr bool is_iec559         = false;
	static constexpr bool is_bounded        = true;
	static constexpr bool is_modulo         = true;
	static constexpr bool tinyness_before   = false;
	static constexpr bool traps             = true;

	static constexpr int  digits            = ULLONG_RADIX_DIG;
	static constexpr int  digits10          = ULLONG_DIG;
	static constexpr int  max_digits10      = ULLONG_DECIMAL_DIG;
	static constexpr int  radix             = ULLONG_RADIX;
	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 unsigned long long min()           { return ULLONG_MIN; }
	static constexpr unsigned long long max()           { return ULLONG_MAX; }
	static constexpr unsigned long long lowest()        { return 1;          }
	static constexpr unsigned long long epsilon()       { return 1;          }
	static constexpr unsigned long long round_error()   { return 0;          }
	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;          }
};

}

#endif // FENNEC_LANG_LIMITS_H
