/* Zeta API - Z/inspection/floating-point.h
 ______ ____________  ___
|__   /|  ___|__  __|/   \
  /  /_|  __|  |  | /  *  \
 /_____|_____| |__|/__/ \__\
Copyright (C) 2006-2022 Manuel Sainz de Baranda y Goñi.
Released under the terms of the GNU Lesser General Public License v3. */

#ifndef Z_inspection_floating_point_H
#define Z_inspection_floating_point_H

#include <Z/keys/number.h>
#include <Z/keys/type.h>
#include <Z/inspection/language.h>
#include <Z/macros/token.h>

#if Z_DIALECT_HAS_TYPE(C, DOUBLE)
#	ifndef Z_FLOATING_POINT_FIXED_FUNDAMENTAL_DOUBLE
#		ifdef Z_COMPILER_FIXED_FUNDAMENTAL_DOUBLE
#			define Z_FLOATING_POINT_FIXED_FUNDAMENTAL_DOUBLE Z_COMPILER_FIXED_FUNDAMENTAL_DOUBLE
#		else
#			define Z_FLOATING_POINT_FIXED_FUNDAMENTAL_DOUBLE Z_FUNDAMENTAL_BFP64
#		endif
#	endif

#	if Z_FLOATING_POINT_FIXED_FUNDAMENTAL_DOUBLE == Z_FUNDAMENTAL_BFP64
#		define Z_FLOATING_POINT_TYPE_BFP64	   double
#		define Z_FLOATING_POINT_FUNDAMENTAL_BFP64  Z_FUNDAMENTAL_DOUBLE
#		define Z_FLOATING_POINT_LITERAL_BFP64	   Z_SAME

#	elif Z_FLOATING_POINT_FIXED_FUNDAMENTAL_DOUBLE == Z_FUNDAMENTAL_DFP64
#		define Z_FLOATING_POINT_TYPE_DFP64	   double
#		define Z_FLOATING_POINT_FUNDAMENTAL_DFP64  Z_FUNDAMENTAL_DOUBLE
#		define Z_FLOATING_POINT_LITERAL_DFP64	   Z_SAME

#	else
#		error "Invalid Z_FLOATING_POINT_FIXED_FUNDAMENTAL_DOUBLE key."
#	endif
#endif

#if Z_DIALECT_HAS_TYPE(C, FLOAT)
#	ifndef Z_FLOATING_POINT_FIXED_FUNDAMENTAL_FLOAT
#		ifdef Z_COMPILER_FIXED_FUNDAMENTAL_FLOAT
#			define Z_FLOATING_POINT_FIXED_FUNDAMENTAL_FLOAT Z_COMPILER_FIXED_FUNDAMENTAL_FLOAT
#		else
#			define Z_FLOATING_POINT_FIXED_FUNDAMENTAL_FLOAT Z_FUNDAMENTAL_BFP32
#		endif
#	endif

#	if Z_FLOATING_POINT_FIXED_FUNDAMENTAL_FLOAT == Z_FUNDAMENTAL_BFP32
#		ifndef Z_FLOATING_POINT_TYPE_BFP32
#			define Z_FLOATING_POINT_TYPE_BFP32	  float
#			define Z_FLOATING_POINT_FUNDAMENTAL_BFP32 Z_FUNDAMENTAL_FLOAT
#			define Z_FLOATING_POINT_LITERAL_BFP32	  Z_SUFFIX_F
#		endif

#	elif Z_FLOATING_POINT_FIXED_FUNDAMENTAL_FLOAT == Z_FUNDAMENTAL_DFP32
#		ifndef Z_FLOATING_POINT_TYPE_DFP32
#			define Z_FLOATING_POINT_TYPE_DFP32	  float
#			define Z_FLOATING_POINT_FUNDAMENTAL_DFP32 Z_FUNDAMENTAL_FLOAT
#			define Z_FLOATING_POINT_LITERAL_DFP32	  Z_SUFFIX_F
#		endif

#	else
#		error "Invalid Z_FLOATING_POINT_FIXED_FUNDAMENTAL_FLOAT key."
#	endif
#endif

#if Z_DIALECT_HAS_TYPE(C89, LONG_DOUBLE)
#	ifndef Z_FLOATING_POINT_FIXED_FUNDAMENTAL_LDOUBLE
#		ifdef Z_COMPILER_FIXED_FUNDAMENTAL_LDOUBLE
#			define Z_FLOATING_POINT_FIXED_FUNDAMENTAL_LDOUBLE Z_COMPILER_FIXED_FUNDAMENTAL_LDOUBLE
#		else
#			define Z_FLOATING_POINT_FIXED_FUNDAMENTAL_LDOUBLE Z_FUNDAMENTAL_BFP128
#		endif
#	endif

#	if Z_FLOATING_POINT_FIXED_FUNDAMENTAL_LDOUBLE == Z_FUNDAMENTAL_BFP64
#		ifndef Z_FLOATING_POINT_TYPE_BFP64
#			define Z_FLOATING_POINT_TYPE_BFP64	  long double
#			define Z_FLOATING_POINT_FUNDAMENTAL_BFP64 Z_FUNDAMENTAL_LDOUBLE
#			define Z_FLOATING_POINT_LITERAL_BFP64	  Z_SUFFIX_L
#		endif

#	elif Z_FLOATING_POINT_FIXED_FUNDAMENTAL_LDOUBLE == Z_FUNDAMENTAL_DFP64
#		ifndef Z_FLOATING_POINT_TYPE_DFP64
#			define Z_FLOATING_POINT_TYPE_DFP64	  long double
#			define Z_FLOATING_POINT_FUNDAMENTAL_DFP64 Z_FUNDAMENTAL_LDOUBLE
#			define Z_FLOATING_POINT_LITERAL_DFP64	  Z_SUFFIX_L
#		endif

#	elif Z_FLOATING_POINT_FIXED_FUNDAMENTAL_LDOUBLE == Z_FUNDAMENTAL_BFP128
#		define Z_FLOATING_POINT_TYPE_BFP128	      long double
#		define Z_FLOATING_POINT_FUNDAMENTAL_BFP128    Z_FUNDAMENTAL_LDOUBLE
#		define Z_FLOATING_POINT_LITERAL_BFP128	      Z_SUFFIX_L

#	elif Z_FLOATING_POINT_FIXED_FUNDAMENTAL_LDOUBLE == Z_FUNDAMENTAL_DFP128
#		define Z_FLOATING_POINT_TYPE_DFP128	      long double
#		define Z_FLOATING_POINT_FUNDAMENTAL_DFP128    Z_FUNDAMENTAL_LDOUBLE
#		define Z_FLOATING_POINT_LITERAL_DFP128	      Z_SUFFIX_L

#	elif Z_FLOATING_POINT_FIXED_FUNDAMENTAL_LDOUBLE == Z_FUNDAMENTAL_X87_DE80
#		define Z_FLOATING_POINT_TYPE_X87_DE80	      long double
#		define Z_FLOATING_POINT_FUNDAMENTAL_X87_DE80  Z_FUNDAMENTAL_LDOUBLE
#		define Z_FLOATING_POINT_LITERAL_X87_DE80      Z_SUFFIX_L

#	elif Z_FLOATING_POINT_FIXED_FUNDAMENTAL_LDOUBLE == Z_FUNDAMENTAL_X87_DE96
#		define Z_FLOATING_POINT_TYPE_X87_DE96	      long double
#		define Z_FLOATING_POINT_FUNDAMENTAL_X87_DE96  Z_FUNDAMENTAL_LDOUBLE
#		define Z_FLOATING_POINT_LITERAL_X87_DE96      Z_SUFFIX_L

#	elif Z_FLOATING_POINT_FIXED_FUNDAMENTAL_LDOUBLE == Z_FUNDAMENTAL_X87_DE128
#		define Z_FLOATING_POINT_TYPE_X87_DE128	      long double
#		define Z_FLOATING_POINT_FUNDAMENTAL_X87_DE128 Z_FUNDAMENTAL_LDOUBLE
#		define Z_FLOATING_POINT_LITERAL_X87_DE128     Z_SUFFIX_L

#	elif Z_FLOATING_POINT_FIXED_FUNDAMENTAL_LDOUBLE == Z_FUNDAMENTAL_IBM_ED
#		define Z_FLOATING_POINT_TYPE_IBM_ED	      long double
#		define Z_FLOATING_POINT_FUNDAMENTAL_IBM_ED    Z_FUNDAMENTAL_LDOUBLE
#		define Z_FLOATING_POINT_LITERAL_IBM_ED	      Z_SUFFIX_L

#	else
#		error "Invalid Z_FLOATING_POINT_FIXED_FUNDAMENTAL_LDOUBLE key."
#	endif
#endif

#ifndef Z_FLOATING_POINT_TYPE_BFP16
#	if Z_DIALECT_HAS_TYPE(C, FLOAT16)
#		define Z_FLOATING_POINT_TYPE_BFP16	  _Float16
#		define Z_FLOATING_POINT_FUNDAMENTAL_BFP16 Z_FUNDAMENTAL_FLOAT16
#		define Z_FLOATING_POINT_LITERAL_BFP16	  Z_SUFFIX_F16

#	elif Z_COMPILER_HAS_TYPE(BFP16)
#		define Z_FLOATING_POINT_TYPE_BFP16	  Z_COMPILER_TYPE(BFP16)
#		define Z_FLOATING_POINT_FUNDAMENTAL_BFP16 Z_FUNDAMENTAL_BFP16

#		if Z_COMPILER_HAS_LITERAL(BFP16)
#			define Z_FLOATING_POINT_LITERAL_BFP16 Z_COMPILER_LITERAL(BFP16)
#		else
#			define Z_FLOATING_POINT_LITERAL_BFP16 Z_SAME
#		endif
#	endif
#endif

#ifndef Z_FLOATING_POINT_TYPE_BFP32
#	if Z_DIALECT_HAS_TYPE(C, FLOAT32)
#		define Z_FLOATING_POINT_TYPE_BFP32	  _Float32
#		define Z_FLOATING_POINT_FUNDAMENTAL_BFP32 Z_FUNDAMENTAL_FLOAT32
#		define Z_FLOATING_POINT_LITERAL_BFP32	  Z_SUFFIX_F32

#	elif Z_COMPILER_HAS_TYPE(BFP32)
#		define Z_FLOATING_POINT_TYPE_BFP32	  Z_COMPILER_TYPE(BFP32)
#		define Z_FLOATING_POINT_FUNDAMENTAL_BFP32 Z_FUNDAMENTAL_BFP32

#		if Z_COMPILER_HAS_LITERAL(BFP32)
#			define Z_FLOATING_POINT_LITERAL_BFP32 Z_COMPILER_LITERAL(BFP32)
#		else
#			define Z_FLOATING_POINT_LITERAL_BFP32 Z_SAME
#		endif
#	endif
#endif

#ifndef Z_FLOATING_POINT_TYPE_BFP64
#	if Z_DIALECT_HAS_TYPE(C, FLOAT64)
#		define Z_FLOATING_POINT_TYPE_BFP64	  _Float64
#		define Z_FLOATING_POINT_FUNDAMENTAL_BFP64 Z_FUNDAMENTAL_FLOAT64
#		define Z_FLOATING_POINT_LITERAL_BFP64	  Z_SUFFIX_F64

#	elif Z_COMPILER_HAS_TYPE(BFP64)
#		define Z_FLOATING_POINT_TYPE_BFP64	  Z_COMPILER_TYPE(BFP64)
#		define Z_FLOATING_POINT_FUNDAMENTAL_BFP64 Z_FUNDAMENTAL_BFP64

#		if Z_COMPILER_HAS_LITERAL(BFP64)
#			define Z_FLOATING_POINT_LITERAL_BFP64 Z_COMPILER_LITERAL(BFP64)
#		else
#			define Z_FLOATING_POINT_LITERAL_BFP64 Z_SAME
#		endif
#	endif
#endif

#ifndef Z_FLOATING_POINT_TYPE_BFP128
#	if Z_DIALECT_HAS_TYPE(C, FLOAT128)
#		define Z_FLOATING_POINT_TYPE_BFP128	   _Float128
#		define Z_FLOATING_POINT_FUNDAMENTAL_BFP128 Z_FUNDAMENTAL_FLOAT128
#		define Z_FLOATING_POINT_LITERAL_BFP128	   Z_SUFFIX_F128

#	elif Z_COMPILER_HAS_TYPE(BFP128)
#		define Z_FLOATING_POINT_TYPE_BFP128	   Z_COMPILER_TYPE(BFP128)
#		define Z_FLOATING_POINT_FUNDAMENTAL_BFP128 Z_FUNDAMENTAL_BFP128

#		if Z_COMPILER_HAS_LITERAL(BFP128)
#			define Z_FLOATING_POINT_LITERAL_BFP128 Z_COMPILER_LITERAL(BFP128)
#		else
#			define Z_FLOATING_POINT_LITERAL_BFP128 Z_SAME
#		endif
#	endif
#endif

#ifndef Z_FLOATING_POINT_TYPE_DFP32
#	if Z_DIALECT_HAS_TYPE(C, DECIMAL32)
#		define Z_FLOATING_POINT_TYPE_DFP32	  _Decimal32
#		define Z_FLOATING_POINT_FUNDAMENTAL_DFP32 Z_FUNDAMENTAL_DECIMAL32
#		define Z_FLOATING_POINT_LITERAL_DFP32	  Z_SUFFIX_DF

#	elif Z_COMPILER_HAS_TYPE(DFP32)
#		define Z_FLOATING_POINT_TYPE_DFP32	  Z_COMPILER_TYPE(DFP32)
#		define Z_FLOATING_POINT_FUNDAMENTAL_DFP32 Z_FUNDAMENTAL_DFP32

#		if Z_COMPILER_HAS_LITERAL(DFP32)
#			define Z_FLOATING_POINT_LITERAL_DFP32 Z_COMPILER_LITERAL(DFP32)
#		else
#			define Z_FLOATING_POINT_LITERAL_DFP32 Z_SAME
#		endif
#	endif
#endif

#ifndef Z_FLOATING_POINT_TYPE_DFP64
#	if Z_DIALECT_HAS_TYPE(C, DECIMAL64)
#		define Z_FLOATING_POINT_TYPE_DFP64	  _Decimal64
#		define Z_FLOATING_POINT_FUNDAMENTAL_DFP64 Z_FUNDAMENTAL_DECIMAL64
#		define Z_FLOATING_POINT_LITERAL_DFP64	  Z_SUFFIX_DF

#	elif Z_COMPILER_HAS_TYPE(DFP64)
#		define Z_FLOATING_POINT_TYPE_DFP64	  Z_COMPILER_TYPE(DFP64)
#		define Z_FLOATING_POINT_FUNDAMENTAL_DFP64 Z_FUNDAMENTAL_DFP64

#		if Z_COMPILER_HAS_LITERAL(DFP64)
#			define Z_FLOATING_POINT_LITERAL_DFP64 Z_COMPILER_LITERAL(DFP64)
#		else
#			define Z_FLOATING_POINT_LITERAL_DFP64 Z_SAME
#		endif
#	endif
#endif

#ifndef Z_FLOATING_POINT_TYPE_DFP128
#	if Z_DIALECT_HAS_TYPE(C, DECIMAL128)
#		define Z_FLOATING_POINT_TYPE_DFP128	   _Decimal128
#		define Z_FLOATING_POINT_FUNDAMENTAL_DFP128 Z_FUNDAMENTAL_DECIMAL128
#		define Z_FLOATING_POINT_LITERAL_DFP128	   Z_SUFFIX_DF

#	elif Z_COMPILER_HAS_TYPE(DFP128)
#		define Z_FLOATING_POINT_TYPE_DFP128	   Z_COMPILER_TYPE(DFP128)
#		define Z_FLOATING_POINT_FUNDAMENTAL_DFP128 Z_FUNDAMENTAL_DFP128

#		if Z_COMPILER_HAS_LITERAL(DFP128)
#			define Z_FLOATING_POINT_LITERAL_DFP128 Z_COMPILER_LITERAL(DFP128)
#		else
#			define Z_FLOATING_POINT_LITERAL_DFP128 Z_SAME
#		endif
#	endif
#endif

#if !defined(Z_FLOATING_POINT_TYPE_X87_DE80) && Z_COMPILER_HAS_TYPE(X87_DE80)
#	define Z_FLOATING_POINT_TYPE_X87_DE80	     Z_COMPILER_TYPE(X87_DE80)
#	define Z_FLOATING_POINT_FUNDAMENTAL_X87_DE80 Z_FUNDAMENTAL_X87_DE80

#	if Z_COMPILER_HAS_LITERAL(X87_DE80)
#		define Z_FLOATING_POINT_LITERAL_X87_DE80 Z_COMPILER_LITERAL(X87_DE80)
#	else
#		define Z_FLOATING_POINT_LITERAL_X87_DE80 Z_SAME
#	endif
#endif

#if !defined(Z_FLOATING_POINT_TYPE_X87_DE96) && Z_COMPILER_HAS_TYPE(X87_DE96)
#	define Z_FLOATING_POINT_TYPE_X87_DE96	     Z_COMPILER_TYPE(X87_DE96)
#	define Z_FLOATING_POINT_FUNDAMENTAL_X87_DE96 Z_FUNDAMENTAL_X87_DE96

#	if Z_COMPILER_HAS_LITERAL(X87_DE96)
#		define Z_FLOATING_POINT_LITERAL_X87_DE96 Z_COMPILER_LITERAL(X87_DE96)
#	else
#		define Z_FLOATING_POINT_LITERAL_X87_DE96 Z_SAME
#	endif
#endif

#if !defined(Z_FLOATING_POINT_TYPE_X87_DE128) && Z_COMPILER_HAS_TYPE(X87_DE128)
#	define Z_FLOATING_POINT_TYPE_X87_DE128	      Z_COMPILER_TYPE(X87_DE128)
#	define Z_FLOATING_POINT_FUNDAMENTAL_X87_DE128 Z_FUNDAMENTAL_X87_DE128

#	if Z_COMPILER_HAS_LITERAL(X87_DE128)
#		define Z_FLOATING_POINT_LITERAL_X87_DE128 Z_COMPILER_LITERAL(X87_DE128)
#	else
#		define Z_FLOATING_POINT_LITERAL_X87_DE128 Z_SAME
#	endif
#endif

#if Z_DIALECT_HAS_TYPE(C, FLOAT32X) && !defined(Z_FLOATING_POINT_FIXED_FUNDAMENTAL_FLOAT32X)
#	ifdef Z_COMPILER_FIXED_FUNDAMENTAL_FLOAT32X
#		define Z_FLOATING_POINT_FIXED_FUNDAMENTAL_FLOAT32X Z_COMPILER_FIXED_FUNDAMENTAL_FLOAT32X
#	else
#		define Z_FLOATING_POINT_FIXED_FUNDAMENTAL_FLOAT32X Z_FUNDAMENTAL_BFP64
#	endif
#endif

#if Z_DIALECT_HAS_TYPE(C, FLOAT64X) && !defined(Z_FLOATING_POINT_FIXED_FUNDAMENTAL_FLOAT64X)
#	ifdef Z_COMPILER_FIXED_FUNDAMENTAL_FLOAT64X
#		define Z_FLOATING_POINT_FIXED_FUNDAMENTAL_FLOAT64X Z_COMPILER_FIXED_FUNDAMENTAL_FLOAT64X
#	else
#		define Z_FLOATING_POINT_FIXED_FUNDAMENTAL_FLOAT64X Z_FUNDAMENTAL_BFP128
#	endif
#endif

#if Z_DIALECT_HAS_TYPE(C, FLOAT128X) && !defined(Z_FLOATING_POINT_FIXED_FUNDAMENTAL_FLOAT128X)
#	ifdef Z_COMPILER_FIXED_FUNDAMENTAL_FLOAT128X
#		define Z_FLOATING_POINT_FIXED_FUNDAMENTAL_FLOAT128X Z_COMPILER_FIXED_FUNDAMENTAL_FLOAT128X
#	else
#		error "Z_FLOATING_POINT_FIXED_FUNDAMENTAL_FLOAT128X not defined."
#	endif
#endif

#if Z_DIALECT_HAS_TYPE(C, DECIMAL64X) && !defined(Z_FLOATING_POINT_FIXED_FUNDAMENTAL_DECIMAL64X)
#	ifdef Z_COMPILER_FIXED_FUNDAMENTAL_DECIMAL64X
#		define Z_FLOATING_POINT_FIXED_FUNDAMENTAL_DECIMAL64X Z_COMPILER_FIXED_FUNDAMENTAL_DECIMAL64X
#	else
#		define Z_FLOATING_POINT_FIXED_FUNDAMENTAL_DECIMAL64X Z_FUNDAMENTAL_DFP128
#	endif
#endif

#if Z_DIALECT_HAS_TYPE(C, DECIMAL128X) && !defined(Z_FLOATING_POINT_FIXED_FUNDAMENTAL_DECIMAL128X)
#	ifdef Z_COMPILER_FIXED_FUNDAMENTAL_DECIMAL128X
#		define Z_FLOATING_POINT_FIXED_FUNDAMENTAL_DECIMAL128X Z_COMPILER_FIXED_FUNDAMENTAL_DECIMAL128X
#	else
#		error "Z_FLOATING_POINT_FIXED_FUNDAMENTAL_DECIMAL128X not defined."
#	endif
#endif

#include <Z/inspection/floating-point/completion.h>

#define Z_FLOATING_POINT_HAS_TYPE(	   TYPE) Z_IS_TRUE(Z_FLOATING_POINT_HAS_TYPE_##TYPE)
#define Z_FLOATING_POINT_TYPE(		   TYPE) Z_FLOATING_POINT_TYPE_##TYPE
#define Z_FLOATING_POINT_LITERAL(	   TYPE) Z_FLOATING_POINT_LITERAL_##TYPE
#define Z_FLOATING_POINT_FUNDAMENTAL(	   TYPE) Z_FLOATING_POINT_FUNDAMENTAL_##TYPE
#define Z_FLOATING_POINT_FIXED_FUNDAMENTAL(TYPE) Z_FLOATING_POINT_FIXED_FUNDAMENTAL_##TYPE

#endif /* Z_inspection_floating_point_H */
