// =====================================================================================================================
//  fennec, a free and open source game engine
//  Copyright © 2025 - 2026  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 fennec/lang/limits.h
/// \brief \ref fennec_lang_limits
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 - 2026 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 TypeT represents an 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
};


// Overloads ===========================================================================================================

///
/// \brief Definition for type \emph{float}.
template<> struct numeric_limits<float>
{
	static constexpr bool is_specialized    = true;                  //!< Check if the template is specialized for float
	static constexpr bool is_signed         = true;                  //!< Check if float is signed
	static constexpr bool is_integer        = false;                 //!< Check if float is of an integral type
	static constexpr bool is_exact          = false;                 //!< Check if float is exact in its precision
	static constexpr bool has_infinity      = FLT_HAS_INFINITY;      //!< Check if float can hold a value representing infinity
	static constexpr bool has_quiet_nan     = FLT_HAS_QUIET_NAN;     //!< Check if float can hold a non-signaling nan
	static constexpr bool has_signaling_nan = FLT_HAS_SIGNALING_NAN; //!< Check if float can hold a signaling nan
	static constexpr bool has_denorm        = FLT_HAS_DENORM;        //!< Check if float denormalizes
	static constexpr bool has_denorm_loss   = FLT_HAS_DENORM_LOSS;   //!< Check if float has precision loss when denormalized
	static constexpr bool is_iec559         = FLT_IS_IEC559;         //!< Check if float represents an IEC 559 or IEEE 754
	static constexpr bool is_bounded        = true;                  //!< Check if float represents a finite set of values
	static constexpr bool is_modulo         = false;                 //!< Check if float can handle modulo arithmetic
	static constexpr bool tinyness_before   = FLT_TINYNESS_BEFORE;   //!< Check if float checks for tinyness before rounding
	static constexpr bool traps             = FLT_TRAPS;             //!< Check if float can cause operations to trap

	static constexpr int  digits            = FLT_MANT_DIG;    //!< Get the base representation of the type
	static constexpr int  digits10          = FLT_DIG;         //!< Get the number of radix digits float represents
	static constexpr int  max_digits10      = FLT_DECIMAL_DIG; //!< Get the number of decimal digits float represents
	static constexpr int  radix             = FLT_RADIX;       //!< Get the maximum number of decimal digits float represents
	static constexpr int  min_exponent      = FLT_MIN_EXP;     //!< Get the minimum number of radix digits that represent the exponent of float
	static constexpr int  min_exponent10    = FLT_MIN_10_EXP;  //!< Get the minimum number of decimal digits that represent the exponent of float
	static constexpr int  max_exponent      = FLT_MAX_EXP;     //!< Get the maximum number of radix digits that represent the exponent of float
	static constexpr int  max_exponent10    = FLT_MAX_10_EXP;  //!< Get the maximum number of decimal digits that represent the exponent of float

	static constexpr float min()           { return -FLT_MAX;           } //!< \returns the minimum finite value of float
	static constexpr float max()           { return  FLT_MAX;           } //!< \returns the maximum finite value of float
	static constexpr float lowest()        { return  FLT_MIN;           } //!< \returns the smallest positive value of float
	static constexpr float epsilon()       { return  FLT_EPSILON;       } //!< \returns the difference between 1.0 and the next representable value
	static constexpr float round_error()   { return  FLT_ROUND_ERR;     } //!< \returns the max rounding error of float
	static constexpr float infinity()      { return  FLT_INF;           } //!< \returns a value of float holding a positive infinity
	static constexpr float quiet_NaN()     { return  FLT_QUIET_NAN;     } //!< \returns a value of float holding a quiet NaN
	static constexpr float signaling_NaN() { return  FLT_SIGNALING_NAN; } //!< \returns a value of float holding a signaling NaN
	static constexpr float denorm_min()    { return  FLT_DENORM_MIN;    } //!< \returns a value of float holding the smallest positive subnormal
};


///
/// \brief Definition for type \emph{double}.
template<> struct numeric_limits<double>
{
	static constexpr bool is_specialized    = true;                  //!< Check if the template is specialized for double
	static constexpr bool is_signed         = true;                  //!< Check if double is signed
	static constexpr bool is_integer        = false;                 //!< Check if double is of an integral type
	static constexpr bool is_exact          = false;                 //!< Check if double is exact in its precision
	static constexpr bool has_infinity      = DBL_HAS_INFINITY;      //!< Check if double can hold a value representing infinity
	static constexpr bool has_quiet_nan     = DBL_HAS_QUIET_NAN;     //!< Check if double can hold a non-signaling nan
	static constexpr bool has_signaling_nan = DBL_HAS_SIGNALING_NAN; //!< Check if double can hold a signaling nan
	static constexpr bool has_denorm        = DBL_HAS_DENORM;        //!< Check if double denormalizes
	static constexpr bool has_denorm_loss   = DBL_HAS_DENORM_LOSS;   //!< Check if double has precision loss when denormalized
	static constexpr bool is_iec559         = DBL_IS_IEC559;         //!< Check if double represents an IEC 559 or IEEE 754
	static constexpr bool is_bounded        = true;                  //!< Check if double represents a finite set of values
	static constexpr bool is_modulo         = false;                 //!< Check if double can handle modulo arithmetic
	static constexpr bool tinyness_before   = DBL_TINYNESS_BEFORE;   //!< Check if double checks for tinyness before rounding
	static constexpr bool traps             = DBL_TRAPS;             //!< Check if double can cause operations to trap

	static constexpr int  digits            = DBL_MANT_DIG;    //!< Get the base representation of the type
	static constexpr int  digits10          = DBL_DIG;         //!< Get the number of radix digits double represents
	static constexpr int  max_digits10      = DBL_DECIMAL_DIG; //!< Get the number of decimal digits double represents
	static constexpr int  radix             = DBL_RADIX;       //!< Get the maximum number of decimal digits double represents
	static constexpr int  min_exponent      = DBL_MIN_EXP;     //!< Get the minimum number of radix digits that represent the exponent of double
	static constexpr int  min_exponent10    = DBL_MIN_10_EXP;  //!< Get the minimum number of decimal digits that represent the exponent of double
	static constexpr int  max_exponent      = DBL_MAX_EXP;     //!< Get the maximum number of radix digits that represent the exponent of double
	static constexpr int  max_exponent10    = DBL_MAX_10_EXP;  //!< Get the maximum number of decimal digits that represent the exponent of double

	static constexpr double min()           { return -DBL_MAX;           } //!< \returns the minimum finite value of double
	static constexpr double max()           { return  DBL_MAX;           } //!< \returns the maximum finite value of double
	static constexpr double lowest()        { return  DBL_MIN;           } //!< \returns the smallest positive value of double
	static constexpr double epsilon()       { return  DBL_EPSILON;       } //!< \returns the difference between 1.0 and the next representable value
	static constexpr double round_error()   { return  DBL_ROUND_ERR;     } //!< \returns the max rounding error of double
	static constexpr double infinity()      { return  DBL_INF;           } //!< \returns a value of double holding a positive infinity
	static constexpr double quiet_NaN()     { return  DBL_QUIET_NAN;     } //!< \returns a value of double holding a quiet NaN
	static constexpr double signaling_NaN() { return  DBL_SIGNALING_NAN; } //!< \returns a value of double holding a signaling NaN
	static constexpr double denorm_min()    { return  DBL_DENORM_MIN;    } //!< \returns a value of double holding the smallest positive subnormal
};

///
/// \brief Definition for type \emph{char}.
template<> struct numeric_limits<char>
{
	static constexpr bool is_specialized    = true;           //!< Check if the template is specialized for char
	static constexpr bool is_signed         = CHAR_IS_SIGNED; //!< Check if char is signed
	static constexpr bool is_integer        = true;           //!< Check if char is of an integral type
	static constexpr bool is_exact          = true;           //!< Check if char is exact in its precision
	static constexpr bool has_infinity      = false;          //!< Check if char can hold a value representing infinity
	static constexpr bool has_quiet_nan     = false;          //!< Check if char can hold a non-signaling nan
	static constexpr bool has_signaling_nan = false;          //!< Check if char can hold a signaling nan
	static constexpr bool has_denorm        = false;          //!< Check if char denormalizes
	static constexpr bool has_denorm_loss   = false;          //!< Check if char has precision loss when denormalized
	static constexpr bool is_iec559         = false;          //!< Check if char represents an IEC 559 or IEEE 754
	static constexpr bool is_bounded        = true;           //!< Check if char represents a finite set of values
	static constexpr bool is_modulo         = true;           //!< Check if char can handle modulo arithmetic
	static constexpr bool tinyness_before   = false;          //!< Check if char checks for tinyness before rounding
	static constexpr bool traps             = true;           //!< Check if char can cause operations to trap

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

	static constexpr char min()           { return  CHAR_MIN; } //!< \returns the minimum finite value of char
	static constexpr char max()           { return  CHAR_MAX; } //!< \returns the maximum finite value of char
	static constexpr char lowest()        { return  1;        } //!< \returns the smallest positive value of char
	static constexpr char epsilon()       { return  1;        } //!< \returns the difference between 1.0 and the next representable value
	static constexpr char round_error()   { return  0;        } //!< \returns the max rounding error of char
	static constexpr char infinity()      { return  0;        } //!< \returns a value of char holding a positive infinity
	static constexpr char quiet_NaN()     { return  0;        } //!< \returns a value of char holding a quiet NaN
	static constexpr char signaling_NaN() { return  0;        } //!< \returns a value of char holding a signaling NaN
	static constexpr char denorm_min()    { return  0;        } //!< \returns a value of char holding the smallest positive subnormal
};

///
/// \brief Definition for type \emph{signed char}.
template<> struct numeric_limits<signed char>
{
	static constexpr bool is_specialized    = true;  //!< Check if the template is specialized for signed char
	static constexpr bool is_signed         = true;  //!< Check if signed char is signed
	static constexpr bool is_integer        = true;  //!< Check if signed char is of an integral type
	static constexpr bool is_exact          = true;  //!< Check if signed char is exact in its precision
	static constexpr bool has_infinity      = false; //!< Check if signed char can hold a value representing infinity
	static constexpr bool has_quiet_nan     = false; //!< Check if signed char can hold a non-signaling nan
	static constexpr bool has_signaling_nan = false; //!< Check if signed char can hold a signaling nan
	static constexpr bool has_denorm        = false; //!< Check if signed char denormalizes
	static constexpr bool has_denorm_loss   = false; //!< Check if signed char has precision loss when denormalized
	static constexpr bool is_iec559         = false; //!< Check if signed char represents an IEC 559 or IEEE 754
	static constexpr bool is_bounded        = true;  //!< Check if signed char represents a finite set of values
	static constexpr bool is_modulo         = true;  //!< Check if signed char can handle modulo arithmetic
	static constexpr bool tinyness_before   = false; //!< Check if signed char checks for tinyness before rounding
	static constexpr bool traps             = true;  //!< Check if signed char can cause operations to trap

	static constexpr int  digits            = SCHAR_RADIX_DIG;   //!< Get the base representation of the type
	static constexpr int  digits10          = SCHAR_DIG;         //!< Get the number of radix digits signed char represents
	static constexpr int  max_digits10      = SCHAR_DECIMAL_DIG; //!< Get the number of decimal digits signed char represents
	static constexpr int  radix             = SCHAR_RADIX;       //!< Get the maximum number of decimal digits signed char represents
	static constexpr int  min_exponent      = 0;                 //!< Get the minimum number of radix digits that represent the exponent of signed char
	static constexpr int  min_exponent10    = 0;                 //!< Get the minimum number of decimal digits that represent the exponent of signed char
	static constexpr int  max_exponent      = 0;                 //!< Get the maximum number of radix digits that represent the exponent of signed char
	static constexpr int  max_exponent10    = 0;                 //!< Get the maximum number of decimal digits that represent the exponent of signed char

	static constexpr signed char min()           { return SCHAR_MIN; } //!< \returns the minimum finite value of signed char
	static constexpr signed char max()           { return SCHAR_MAX; } //!< \returns the maximum finite value of signed char
	static constexpr signed char lowest()        { return 1;         } //!< \returns the smallest positive value of signed char
	static constexpr signed char epsilon()       { return 1;         } //!< \returns the difference between 1.0 and the next representable value
	static constexpr signed char round_error()   { return 0;         } //!< \returns the max rounding error of signed char
	static constexpr signed char infinity()      { return 0;         } //!< \returns a value of signed char holding a positive infinity
	static constexpr signed char quiet_NaN()     { return 0;         } //!< \returns a value of signed char holding a quiet NaN
	static constexpr signed char signaling_NaN() { return 0;         } //!< \returns a value of signed char holding a signaling NaN
	static constexpr signed char denorm_min()    { return 0;         } //!< \returns a value of signed char holding the smallest positive subnormal
};

///
/// \brief Definition for type \emph{unsigned char}.
template<> struct numeric_limits<unsigned char>
{
	static constexpr bool is_specialized    = true;  //!< Check if the template is specialized for unsigned char
	static constexpr bool is_signed         = false; //!< Check if unsigned char is unsigned
	static constexpr bool is_integer        = true;  //!< Check if unsigned char is of an integral type
	static constexpr bool is_exact          = true;  //!< Check if unsigned char is exact in its precision
	static constexpr bool has_infinity      = false; //!< Check if unsigned char can hold a value representing infinity
	static constexpr bool has_quiet_nan     = false; //!< Check if unsigned char can hold a non-signaling nan
	static constexpr bool has_signaling_nan = false; //!< Check if unsigned char can hold a signaling nan
	static constexpr bool has_denorm        = false; //!< Check if unsigned char denormalizes
	static constexpr bool has_denorm_loss   = false; //!< Check if unsigned char has precision loss when denormalized
	static constexpr bool is_iec559         = false; //!< Check if unsigned char represents an IEC 559 or IEEE 754
	static constexpr bool is_bounded        = true;  //!< Check if unsigned char represents a finite set of values
	static constexpr bool is_modulo         = true;  //!< Check if unsigned char can handle modulo arithmetic
	static constexpr bool tinyness_before   = false; //!< Check if unsigned char checks for tinyness before rounding
	static constexpr bool traps             = true;  //!< Check if unsigned char can cause operations to trap

	static constexpr int  digits            = UCHAR_RADIX_DIG;   //!< Get the base representation of the type
	static constexpr int  digits10          = UCHAR_DIG;         //!< Get the number of radix digits unsigned char represents
	static constexpr int  max_digits10      = UCHAR_DECIMAL_DIG; //!< Get the number of decimal digits unsigned char represents
	static constexpr int  radix             = UCHAR_RADIX;       //!< Get the maximum number of decimal digits unsigned char represents
	static constexpr int  min_exponent      = 0;                 //!< Get the minimum number of radix digits that represent the exponent of unsigned char
	static constexpr int  min_exponent10    = 0;                 //!< Get the minimum number of decimal digits that represent the exponent of unsigned char
	static constexpr int  max_exponent      = 0;                 //!< Get the maximum number of radix digits that represent the exponent of unsigned char
	static constexpr int  max_exponent10    = 0;                 //!< Get the maximum number of decimal digits that represent the exponent of unsigned char

	static constexpr unsigned char min()           { return UCHAR_MIN; } //!< \returns the minimum finite value of unsigned char
	static constexpr unsigned char max()           { return UCHAR_MAX; } //!< \returns the maximum finite value of unsigned char
	static constexpr unsigned char lowest()        { return 1;         } //!< \returns the smallest positive value of unsigned char
	static constexpr unsigned char epsilon()       { return 1;         } //!< \returns the difference between 1.0 and the next representable value
	static constexpr unsigned char round_error()   { return 0;         } //!< \returns the max rounding error of unsigned char
	static constexpr unsigned char infinity()      { return 0;         } //!< \returns a value of unsigned char holding a positive infinity
	static constexpr unsigned char quiet_NaN()     { return 0;         } //!< \returns a value of unsigned char holding a quiet NaN
	static constexpr unsigned char signaling_NaN() { return 0;         } //!< \returns a value of unsigned char holding a signaling NaN
	static constexpr unsigned char denorm_min()    { return 0;         } //!< \returns a value of unsigned char holding the smallest positive subnormal
};

///
/// \brief Definition for type \emph{short}.
template<> struct numeric_limits<short>
{
	static constexpr bool is_specialized    = true;  //!< Check if the template is specialized for short
	static constexpr bool is_signed         = true;  //!< Check if short is signed
	static constexpr bool is_integer        = true;  //!< Check if short is of an integral type
	static constexpr bool is_exact          = true;  //!< Check if short is exact in its precision
	static constexpr bool has_infinity      = false; //!< Check if short can hold a value representing infinity
	static constexpr bool has_quiet_nan     = false; //!< Check if short can hold a non-signaling nan
	static constexpr bool has_signaling_nan = false; //!< Check if short can hold a signaling nan
	static constexpr bool has_denorm        = false; //!< Check if short denormalizes
	static constexpr bool has_denorm_loss   = false; //!< Check if short has precision loss when denormalized
	static constexpr bool is_iec559         = false; //!< Check if short represents an IEC 559 or IEEE 754
	static constexpr bool is_bounded        = true;  //!< Check if short represents a finite set of values
	static constexpr bool is_modulo         = true;  //!< Check if short can handle modulo arithmetic
	static constexpr bool tinyness_before   = false; //!< Check if short checks for tinyness before rounding
	static constexpr bool traps             = true;  //!< Check if short can cause operations to trap

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

	static constexpr short min()           { return static_cast<short>(SHORT_MIN); } //!< \returns the minimum finite value of short
	static constexpr short max()           { return SHORT_MAX;                     } //!< \returns the maximum finite value of short
	static constexpr short lowest()        { return 1;                             } //!< \returns the smallest positive value of short
	static constexpr short epsilon()       { return 1;                             } //!< \returns the difference between 1.0 and the next representable value
	static constexpr short round_error()   { return 0;                             } //!< \returns the max rounding error of short
	static constexpr short infinity()      { return 0;                             } //!< \returns a value of short holding a positive infinity
	static constexpr short quiet_NaN()     { return 0;                             } //!< \returns a value of short holding a quiet NaN
	static constexpr short signaling_NaN() { return 0;                             } //!< \returns a value of short holding a signaling NaN
	static constexpr short denorm_min()    { return 0;                             } //!< \returns a value of short holding the smallest positive subnormal
};

///
/// \brief Definition for type \emph{unsigned short}.
template<> struct numeric_limits<unsigned short>
{
	static constexpr bool is_specialized    = true;  //!< Check if the template is specialized for signed short
	static constexpr bool is_signed         = false; //!< Check if unsigned short is signed
	static constexpr bool is_integer        = true;  //!< Check if unsigned short is of an integral type
	static constexpr bool is_exact          = true;  //!< Check if unsigned short is exact in its precision
	static constexpr bool has_infinity      = false; //!< Check if unsigned short can hold a value representing infinity
	static constexpr bool has_quiet_nan     = false; //!< Check if unsigned short can hold a non-signaling nan
	static constexpr bool has_signaling_nan = false; //!< Check if unsigned short can hold a signaling nan
	static constexpr bool has_denorm        = false; //!< Check if unsigned short denormalizes
	static constexpr bool has_denorm_loss   = false; //!< Check if unsigned short has precision loss when denormalized
	static constexpr bool is_iec559         = false; //!< Check if unsigned short represents an IEC 559 or IEEE 754
	static constexpr bool is_bounded        = true;  //!< Check if unsigned short represents a finite set of values
	static constexpr bool is_modulo         = true;  //!< Check if unsigned short can handle modulo arithmetic
	static constexpr bool tinyness_before   = false; //!< Check if unsigned short checks for tinyness before rounding
	static constexpr bool traps             = true;  //!< Check if unsigned short can cause operations to trap

	static constexpr int  digits            = USHORT_RADIX_DIG;   //!< Get the base representation of the type
	static constexpr int  digits10          = USHORT_DIG;         //!< Get the number of radix digits unsigned short represents
	static constexpr int  max_digits10      = USHORT_DECIMAL_DIG; //!< Get the number of decimal digits unsigned short represents
	static constexpr int  radix             = USHORT_RADIX;       //!< Get the maximum number of decimal digits unsigned short represents
	static constexpr int  min_exponent      = 0;                  //!< Get the minimum number of radix digits that represent the exponent of unsigned short
	static constexpr int  min_exponent10    = 0;                  //!< Get the minimum number of decimal digits that represent the exponent of unsigned short
	static constexpr int  max_exponent      = 0;                  //!< Get the maximum number of radix digits that represent the exponent of unsigned short
	static constexpr int  max_exponent10    = 0;                  //!< Get the maximum number of decimal digits that represent the exponent of unsigned short

	static constexpr unsigned short min()           { return USHORT_MIN; } //!< \returns the minimum finite value of unsigned short
	static constexpr unsigned short max()           { return USHORT_MAX; } //!< \returns the maximum finite value of unsigned short
	static constexpr unsigned short lowest()        { return 1;          } //!< \returns the smallest positive value of unsigned short
	static constexpr unsigned short epsilon()       { return 1;          } //!< \returns the difference between 1.0 and the next representable value
	static constexpr unsigned short round_error()   { return 0;          } //!< \returns the max rounding error of unsigned short
	static constexpr unsigned short infinity()      { return 0;          } //!< \returns a value of unsigned short holding a positive infinity
	static constexpr unsigned short quiet_NaN()     { return 0;          } //!< \returns a value of unsigned short holding a quiet NaN
	static constexpr unsigned short signaling_NaN() { return 0;          } //!< \returns a value of unsigned short holding a signaling NaN
	static constexpr unsigned short denorm_min()    { return 0;          } //!< \returns a value of unsigned short holding the smallest positive subnormal
};

///
/// \brief Definition for type \emph{int}.
template<> struct numeric_limits<int>
{
	static constexpr bool is_specialized    = true;  //!< Check if the template is specialized for int
	static constexpr bool is_signed         = true;  //!< Check if int is signed
	static constexpr bool is_integer        = true;  //!< Check if int is of an integral type
	static constexpr bool is_exact          = true;  //!< Check if int is exact in its precision
	static constexpr bool has_infinity      = false; //!< Check if int can hold a value representing infinity
	static constexpr bool has_quiet_nan     = false; //!< Check if int can hold a non-signaling nan
	static constexpr bool has_signaling_nan = false; //!< Check if int can hold a signaling nan
	static constexpr bool has_denorm        = false; //!< Check if int denormalizes
	static constexpr bool has_denorm_loss   = false; //!< Check if int has precision loss when denormalized
	static constexpr bool is_iec559         = false; //!< Check if int represents an IEC 559 or IEEE 754
	static constexpr bool is_bounded        = true;  //!< Check if int represents a finite set of values
	static constexpr bool is_modulo         = true;  //!< Check if int can handle modulo arithmetic
	static constexpr bool tinyness_before   = false; //!< Check if int checks for tinyness before rounding
	static constexpr bool traps             = true;  //!< Check if int can cause operations to trap

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

	static constexpr int min()           { return INT_MIN; } //!< \returns the minimum finite value of int
	static constexpr int max()           { return INT_MAX; } //!< \returns the maximum finite value of int
	static constexpr int lowest()        { return 1;       } //!< \returns the smallest positive value of int
	static constexpr int epsilon()       { return 1;       } //!< \returns the difference between 1.0 and the next representable value
	static constexpr int round_error()   { return 0;       } //!< \returns the max rounding error of int
	static constexpr int infinity()      { return 0;       } //!< \returns a value of int holding a positive infinity
	static constexpr int quiet_NaN()     { return 0;       } //!< \returns a value of int holding a quiet NaN
	static constexpr int signaling_NaN() { return 0;       } //!< \returns a value of int holding a signaling NaN
	static constexpr int denorm_min()    { return 0;       } //!< \returns a value of int holding the smallest positive subnormal
};

///
/// \brief Definition for type \emph{unsigned int}.
template<> struct numeric_limits<unsigned int>
{
	static constexpr bool is_specialized    = true; //!< Check if the template is specialized for unsigned int
	static constexpr bool is_signed         = false; //!< Check if unsigned int is signed
	static constexpr bool is_integer        = true; //!< Check if unsigned int is of an integral type
	static constexpr bool is_exact          = true; //!< Check if unsigned int is exact in its precision
	static constexpr bool has_infinity      = false; //!< Check if unsigned int can hold a value representing infinity
	static constexpr bool has_quiet_nan     = false; //!< Check if unsigned int can hold a non-signaling nan
	static constexpr bool has_signaling_nan = false; //!< Check if unsigned int can hold a signaling nan
	static constexpr bool has_denorm        = false; //!< Check if unsigned int denormalizes
	static constexpr bool has_denorm_loss   = false; //!< Check if unsigned int has precision loss when denormalized
	static constexpr bool is_iec559         = false; //!< Check if unsigned int represents an IEC 559 or IEEE 754
	static constexpr bool is_bounded        = true; //!< Check if unsigned int represents a finite set of values
	static constexpr bool is_modulo         = true; //!< Check if unsigned int can handle modulo arithmetic
	static constexpr bool tinyness_before   = false; //!< Check if unsigned int checks for tinyness before rounding
	static constexpr bool traps             = true; //!< Check if unsigned int can cause operations to trap

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

	static constexpr unsigned int min()           { return UINT_MIN; } //!< \returns the minimum finite value of unsigned int
	static constexpr unsigned int max()           { return UINT_MAX; } //!< \returns the maximum finite value of unsigned int
	static constexpr unsigned int lowest()        { return 1;        } //!< \returns the smallest positive value of unsigned int
	static constexpr unsigned int epsilon()       { return 1;        } //!< \returns the difference between 1.0 and the next representable value
	static constexpr unsigned int round_error()   { return 0;        } //!< \returns the max rounding error of unsigned int
	static constexpr unsigned int infinity()      { return 0;        } //!< \returns a value of unsigned int holding a positive infinity
	static constexpr unsigned int quiet_NaN()     { return 0;        } //!< \returns a value of unsigned int holding a quiet NaN
	static constexpr unsigned int signaling_NaN() { return 0;        } //!< \returns a value of unsigned int holding a signaling NaN
	static constexpr unsigned int denorm_min()    { return 0;        } //!< \returns a value of unsigned int holding the smallest positive subnormal
};

///
/// \brief Definition for type \emph{long int}.
template<> struct numeric_limits<long int>
{
	static constexpr bool is_specialized    = true;  //!< Check if the template is specialized for long int
	static constexpr bool is_signed         = true;  //!< Check if long int is signed
	static constexpr bool is_integer        = true;  //!< Check if long int is of an integral type
	static constexpr bool is_exact          = true;  //!< Check if long int is exact in its precision
	static constexpr bool has_infinity      = false; //!< Check if long int can hold a value representing infinity
	static constexpr bool has_quiet_nan     = false; //!< Check if long int can hold a non-signaling nan
	static constexpr bool has_signaling_nan = false; //!< Check if long int can hold a signaling nan
	static constexpr bool has_denorm        = false; //!< Check if long int denormalizes
	static constexpr bool has_denorm_loss   = false; //!< Check if long int has precision loss when denormalized
	static constexpr bool is_iec559         = false; //!< Check if long int represents an IEC 559 or IEEE 754
	static constexpr bool is_bounded        = true;  //!< Check if long int represents a finite set of values
	static constexpr bool is_modulo         = true;  //!< Check if long int can handle modulo arithmetic
	static constexpr bool tinyness_before   = false; //!< Check if long int checks for tinyness before rounding
	static constexpr bool traps             = true;  //!< Check if long int can cause operations to trap

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

	static constexpr long int min()           { return LONG_MIN; } //!< \returns the minimum finite value of long int
	static constexpr long int max()           { return LONG_MAX; } //!< \returns the maximum finite value of long int
	static constexpr long int lowest()        { return 1;        } //!< \returns the smallest positive value of long int
	static constexpr long int epsilon()       { return 1;        } //!< \returns the difference between 1.0 and the next representable value
	static constexpr long int round_error()   { return 0;        } //!< \returns the max rounding error of long int
	static constexpr long int infinity()      { return 0;        } //!< \returns a value of long int holding a positive infinity
	static constexpr long int quiet_NaN()     { return 0;        } //!< \returns a value of long int holding a quiet NaN
	static constexpr long int signaling_NaN() { return 0;        } //!< \returns a value of long int holding a signaling NaN
	static constexpr long int denorm_min()    { return 0;        } //!< \returns a value of long int holding the smallest positive subnormal
};

///
/// \brief Definition for type \emph{unsigned long int}.
template<> struct numeric_limits<unsigned long int>
{
	static constexpr bool is_specialized    = true;  //!< Check if the template is specialized for unsigned long int
	static constexpr bool is_signed         = false; //!< Check if unsigned long int is signed
	static constexpr bool is_integer        = true;  //!< Check if unsigned long int is of an integral type
	static constexpr bool is_exact          = true;  //!< Check if unsigned long int is exact in its precision
	static constexpr bool has_infinity      = false; //!< Check if unsigned long int can hold a value representing infinity
	static constexpr bool has_quiet_nan     = false; //!< Check if unsigned long int can hold a non-signaling nan
	static constexpr bool has_signaling_nan = false; //!< Check if unsigned long int can hold a signaling nan
	static constexpr bool has_denorm        = false; //!< Check if unsigned long int denormalizes
	static constexpr bool has_denorm_loss   = false; //!< Check if unsigned long int has precision loss when denormalized
	static constexpr bool is_iec559         = false; //!< Check if unsigned long int represents an IEC 559 or IEEE 754
	static constexpr bool is_bounded        = true;  //!< Check if unsigned long int represents a finite set of values
	static constexpr bool is_modulo         = true;  //!< Check if unsigned long int can handle modulo arithmetic
	static constexpr bool tinyness_before   = false; //!< Check if unsigned long int checks for tinyness before rounding
	static constexpr bool traps             = true;  //!< Check if unsigned long int can cause operations to trap

	static constexpr int  digits            = ULONG_RADIX_DIG;   //!< Get the base representation of the type
	static constexpr int  digits10          = ULONG_DIG;         //!< Get the number of radix digits unsigned long int represents
	static constexpr int  max_digits10      = ULONG_DECIMAL_DIG; //!< Get the number of decimal digits unsigned long int represents
	static constexpr int  radix             = ULONG_RADIX;       //!< Get the maximum number of decimal digits unsigned long int represents
	static constexpr int  min_exponent      = 0;                 //!< Get the minimum number of radix digits that represent the exponent of unsigned long int
	static constexpr int  min_exponent10    = 0;                 //!< Get the minimum number of decimal digits that represent the exponent of unsigned long int
	static constexpr int  max_exponent      = 0;                 //!< Get the maximum number of radix digits that represent the exponent of unsigned long int
	static constexpr int  max_exponent10    = 0;                 //!< Get the maximum number of decimal digits that represent the exponent of unsigned long int

	static constexpr unsigned long min()           { return ULONG_MIN; } //!< \returns the minimum finite value of unsigned long int
	static constexpr unsigned long max()           { return ULONG_MAX; } //!< \returns the maximum finite value of unsigned long int
	static constexpr unsigned long lowest()        { return 1;         } //!< \returns the smallest positive value of unsigned long int
	static constexpr unsigned long epsilon()       { return 1;         } //!< \returns the difference between 1.0 and the next representable value
	static constexpr unsigned long round_error()   { return 0;         } //!< \returns the max rounding error of unsigned long int
	static constexpr unsigned long infinity()      { return 0;         } //!< \returns a value of unsigned long int holding a positive infinity
	static constexpr unsigned long quiet_NaN()     { return 0;         } //!< \returns a value of unsigned long int holding a quiet NaN
	static constexpr unsigned long signaling_NaN() { return 0;         } //!< \returns a value of unsigned long int holding a signaling NaN
	static constexpr unsigned long denorm_min()    { return 0;         } //!< \returns a value of unsigned long int holding the smallest positive subnormal
};

///
/// \brief Definition for type \emph{long long}.
template<> struct numeric_limits<long long>
{
	static constexpr bool is_specialized    = true;  //!< Check if the template is specialized for long long
	static constexpr bool is_signed         = true;  //!< Check if long long is signed
	static constexpr bool is_integer        = true;  //!< Check if long long is of an integral type
	static constexpr bool is_exact          = true;  //!< Check if long long is exact in its precision
	static constexpr bool has_infinity      = false; //!< Check if long long can hold a value representing infinity
	static constexpr bool has_quiet_nan     = false; //!< Check if long long can hold a non-signaling nan
	static constexpr bool has_signaling_nan = false; //!< Check if long long can hold a signaling nan
	static constexpr bool has_denorm        = false; //!< Check if long long denormalizes
	static constexpr bool has_denorm_loss   = false; //!< Check if long long has precision loss when denormalized
	static constexpr bool is_iec559         = false; //!< Check if long long represents an IEC 559 or IEEE 754
	static constexpr bool is_bounded        = true;  //!< Check if long long represents a finite set of values
	static constexpr bool is_modulo         = true;  //!< Check if long long can handle modulo arithmetic
	static constexpr bool tinyness_before   = false; //!< Check if long long checks for tinyness before rounding
	static constexpr bool traps             = true;  //!< Check if long long can cause operations to trap

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

	static constexpr long long min()           { return LLONG_MIN; } //!< \returns the minimum finite value of long long
	static constexpr long long max()           { return LLONG_MAX; } //!< \returns the maximum finite value of long long
	static constexpr long long lowest()        { return 1;         } //!< \returns the smallest positive value of long long
	static constexpr long long epsilon()       { return 1;         } //!< \returns the difference between 1.0 and the next representable value
	static constexpr long long round_error()   { return 0;         } //!< \returns the max rounding error of long long
	static constexpr long long infinity()      { return 0;         } //!< \returns a value of long long holding a positive infinity
	static constexpr long long quiet_NaN()     { return 0;         } //!< \returns a value of long long holding a quiet NaN
	static constexpr long long signaling_NaN() { return 0;         } //!< \returns a value of long long holding a signaling NaN
	static constexpr long long denorm_min()    { return 0;         } //!< \returns a value of long long holding the smallest positive subnormal
};

///
/// \brief Definition for type \emph{unsigned long long}.
template<> struct numeric_limits<unsigned long long>
{
	static constexpr bool is_specialized    = true;  //!< Check if the template is specialized for unsigned long long
	static constexpr bool is_signed         = false; //!< Check if unsigned long long is signed
	static constexpr bool is_integer        = true;  //!< Check if unsigned long long is of an integral type
	static constexpr bool is_exact          = true;  //!< Check if unsigned long long is exact in its precision
	static constexpr bool has_infinity      = false; //!< Check if unsigned long long can hold a value representing infinity
	static constexpr bool has_quiet_nan     = false; //!< Check if unsigned long long can hold a non-signaling nan
	static constexpr bool has_signaling_nan = false; //!< Check if unsigned long long can hold a signaling nan
	static constexpr bool has_denorm        = false; //!< Check if unsigned long long denormalizes
	static constexpr bool has_denorm_loss   = false; //!< Check if unsigned long long has precision loss when denormalized
	static constexpr bool is_iec559         = false; //!< Check if unsigned long long represents an IEC 559 or IEEE 754
	static constexpr bool is_bounded        = true;  //!< Check if unsigned long long represents a finite set of values
	static constexpr bool is_modulo         = true;  //!< Check if unsigned long long can handle modulo arithmetic
	static constexpr bool tinyness_before   = false; //!< Check if unsigned long long checks for tinyness before rounding
	static constexpr bool traps             = true;  //!< Check if unsigned long long can cause operations to trap

	static constexpr int  digits            = ULLONG_RADIX_DIG;   //!< Get the base representation of the type
	static constexpr int  digits10          = ULLONG_DIG;         //!< Get the number of radix digits unsigned long long represents
	static constexpr int  max_digits10      = ULLONG_DECIMAL_DIG; //!< Get the number of decimal digits unsigned long long represents
	static constexpr int  radix             = ULLONG_RADIX;       //!< Get the maximum number of decimal digits unsigned long long represents
	static constexpr int  min_exponent      = 0;                  //!< Get the minimum number of radix digits that represent the exponent of unsigned long long
	static constexpr int  min_exponent10    = 0;                  //!< Get the minimum number of decimal digits that represent the exponent of unsigned long long
	static constexpr int  max_exponent      = 0;                  //!< Get the maximum number of radix digits that represent the exponent of unsigned long long
	static constexpr int  max_exponent10    = 0;                  //!< Get the maximum number of decimal digits that represent the exponent of unsigned long long

	static constexpr unsigned long long min()           { return ULLONG_MIN; } //!< \returns the minimum finite value of unsigned long long
	static constexpr unsigned long long max()           { return ULLONG_MAX; } //!< \returns the maximum finite value of unsigned long long
	static constexpr unsigned long long lowest()        { return 1;          } //!< \returns the smallest positive value of unsigned long long
	static constexpr unsigned long long epsilon()       { return 1;          } //!< \returns the difference between 1.0 and the next representable value
	static constexpr unsigned long long round_error()   { return 0;          } //!< \returns the max rounding error of unsigned long long
	static constexpr unsigned long long infinity()      { return 0;          } //!< \returns a value of unsigned long long holding a positive infinity
	static constexpr unsigned long long quiet_NaN()     { return 0;          } //!< \returns a value of unsigned long long holding a quiet NaN
	static constexpr unsigned long long signaling_NaN() { return 0;          } //!< \returns a value of unsigned long long holding a signaling NaN
	static constexpr unsigned long long denorm_min()    { return 0;          } //!< \returns a value of unsigned long long holding the smallest positive subnormal
};

}

#endif // FENNEC_LANG_LIMITS_H
