--- kcore/type.h.m → <k/type.h>
--- ~ lexi hale <lexi@hale.su>
--- this file gathers information on the environment it's
--- being compiled in, defining types that our code
--- needs. it will be emitted as <k/type.h>.
--- vim: ft=c
#ifndef KItype
#define KItype

typedef unsigned char      kc_uint_min;
typedef   signed char      kc_sint_min;
typedef unsigned long long kc_uint_max;
typedef   signed long long kc_sint_max;

[ifdef type_bit8]
	typedef unsigned [type_bit8] u8;
	typedef   signed [type_bit8] s8;
[else]
	typedef kc_uint_min u8;
	typedef	kc_sint_min s8;
[endif]

[ifdef type_bit16]
	typedef unsigned [type_bit16] u16;
	typedef   signed [type_bit16] s16;
[else]
	typedef kc_uint_max u16;
	typedef	kc_sint_max s16;
[endif]

[ifdef type_bit32]
	typedef unsigned [type_bit32] u32;
	typedef   signed [type_bit32] s32;
[else]
	typedef kc_uint_max u32;
	typedef	kc_sint_max s32;
[endif]

[ifdef type_bit64]
	typedef unsigned [type_bit64] u64;
	typedef   signed [type_bit64] s64;
	[ifndef type_bit128]
#		if defined(__GNUC__) || defined(__clang__)
			typedef unsigned __int128_t u128;
			typedef   signed __int128_t s128;
#		else
			typedef kc_uint_max u128;
			typedef kc_sint_max s128;
#		endif
	[endif]
[else]
	typedef kc_uint_max u64;
	typedef	kc_sint_max s64;

	typedef kc_uint_max u128;
	typedef	kc_sint_max s128;
[endif]

[ifdef type_bit128]
	typedef unsigned [type_bit128] u128;
	typedef   signed [type_bit128] s128;
[endif]

enum /* max-min values of each type */ {
	/* assuming two's complement. TODO: check math */
	/* TODO: figure out how to calc min */
	kc_byte_bits = [byte_bits],
	  u8_min = 0,   u8_max = ((u8)-1),
	 u16_min = 0,  u16_max = ((u16)-1),
	 u32_min = 0,  u32_max = ((u32)-1),
	 u64_min = 0,  u32_max = ((u64)-1),
	u128_min = 0, u128_max = ((u128)-1),

	[define merge: $1$2]
	[define [sspec type]:
		[merge [type],_min] = 0 - ((1 << sizeof([type]) * kc_byte_bits) / 2),
		[merge [type],_max] =      (1 << sizeof([type]) * kc_byte_bits) / 2 - 1]

	[sspec s8], [sspec s16], [sspec s32],
	[sspec s64], [sspec s128],

	kc_min_uchar  = 0, kc_max_uchar  = [type_max_u_char],
	kc_min_ushort = 0, kc_max_ushort = [type_max_u_short],
	kc_min_uint   = 0, kc_max_uint   = [type_max_u_int],
	kc_min_ulong  = 0, kc_max_ulong  = [type_max_u_long],
	kc_min_ullong = 0, kc_max_ullong = [type_max_u_llong],

	kc_min_schar  = [type_min_s_char],  kc_max_schar  = [type_max_s_char],
	kc_min_sshort = [type_min_s_short], kc_max_sshort = [type_max_s_short],
	kc_min_sint   = [type_min_s_int],   kc_max_sint   = [type_max_s_int],
	kc_min_slong  = [type_min_s_long],  kc_max_slong  = [type_max_s_long],
	kc_min_sllong = [type_min_s_llong], kc_max_sllong = [type_max_s_llong],
};

[ifdef type_sz]
	typedef [type_sz] sz;
[else]
#	ifdef __cplusplus
 	   /* C++ gives us a clean, standardized way to do this */
 	   typedef decltype (sizeof(char)) sz;
#	else
#		if defined(__GNUC__) || defined(__clang__)
			typedef __typeof__ (sizeof(char)) sz;
#		else
			/* we're stumped - set sz to the safest possible value under
			 * the circumstances, and warn the user. */
#			warning no authoritative sz (size_t) type definition \
			        available; defaulting to largest unsigned integer type
			typedef kc_uint_max sz;
#		endif
#	endif
[endif]

[ifdef type_offset]
	typedef [type_offset] offset;
[else]
#	ifdef __cplusplus
 	   /* C++ gives us a clean, standardized way to do this */
		typedef decltype (((void*)-1) - 1) offset;
#	else
#		if defined(__GNUC__) || defined(__clang__)
			typedef __typeof__ (((void*)10) - ((void*)5)) offset;
#		else
			/* no dice - set offset to the safest possible value under
			 * the circumstances, and warn the user. */
#			warning no authoritative offset (ptrdiff_t) type definition \
			        available; defaulting to largest unsigned integer type
			typedef kc_sint_max offset;
#		endif
#	endif
[endif]

// exit status integer types - pls use kbad in <k/magic.h> instead
[if [target_posix] == yes]
	/* by convention, posix return values are 8-bit,
	 * but note that many modern UNIXes do technically
	 * support higher-bit values. for this reason,
	 * longstat is defined differently under posix. */
	typedef u8 stat;
	typedef u32 stat_long;
[else]
	[if ([atom_target_os] == win) ||
		([atom_target_os] == vms)]
		typedef u32 stat;
	[else]
		typedef u8 stat;
		/* we don't know a specific exit status type
		 * for your arch so we're going with a sane
		 * default. if this is wrong, help us fix it! */
	[endif]
	typedef stat stat_long;
[endif]

#endif
