libguf/tools/ckdint-gen.py
jun 57f0e47efc Refactor to use portable minimum-width integers.
The signed and unsigned fixed-width integers (int32_t, uint32_t etc.) are optional
in C99 (and above). Use the non-optional minimum-width integers (int_fast32_t, uint_fast32_t and int_least32_t, uint_least32_t etc.) instead.

To simulate unsigned wrap-around, use the GUF_UWRAP macros in guf_common.h

cf. https://en.cppreference.com/w/c/types/integer (last-retrieved: 2025-05-18)
2025-05-18 22:03:03 +02:00

643 lines
29 KiB
Python

"""
Generate typesafe checked arithmetic functions for libguf/src/guf_math_ckdint.h
"""
from dataclasses import dataclass
from typing import Tuple
import textwrap
@dataclass
class IntType:
INT_TYPE: str
INT_TYPE_ABBR: str
INT_MIN: str
INT_MAX: str
UINT_TYPE: str
UINT_MAX: str
is_optional: bool = False
@dataclass
class UintType:
INT_TYPE: str
INT_TYPE_ABBR: str
INT_MIN: str
INT_MAX: str
is_optional: bool = False
def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, str]:
ckd_add_sub_uint_header = textwrap.dedent("""\
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_{type_abbr}({type} a, {type} b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_{type_abbr}({type} a, {type} b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_{type_abbr}({type} a, {type} b);
""")
ckd_add_sub_uint = textwrap.dedent("""\
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_{type_abbr}({type} a, {type} b)
{{
if (b > 0 && a > {int_max} - b) {{
return GUF_MATH_CKD_OVERFLOW_POS;
}} else {{
return GUF_MATH_CKD_SUCCESS;
}}
}}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_{type_abbr}({type} a, {type} b)
{{
if (b > a) {{
return GUF_MATH_CKD_OVERFLOW_NEG;
}} else {{
return GUF_MATH_CKD_SUCCESS;
}}
}}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_{type_abbr}({type} a, {type} b)
{{
const {type} c = 1u * a * b;
return a != 0 && ((1u * c / a) != b) ? GUF_MATH_CKD_OVERFLOW_POS : GUF_MATH_CKD_SUCCESS;
}}
""")
ckd_add_sub_uint_FAST = textwrap.dedent("""\
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_{type_abbr}({type} a, {type} b)
{{
a = GUF_UWRAP_{bits}(a);
b = GUF_UWRAP_{bits}(b);
if (b > 0 && a > {int_max} - b) {{
return GUF_MATH_CKD_OVERFLOW_POS;
}} else {{
return GUF_MATH_CKD_SUCCESS;
}}
}}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_{type_abbr}({type} a, {type} b)
{{
a = GUF_UWRAP_{bits}(a);
b = GUF_UWRAP_{bits}(b);
if (b > a) {{
return GUF_MATH_CKD_OVERFLOW_NEG;
}} else {{
return GUF_MATH_CKD_SUCCESS;
}}
}}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_{type_abbr}({type} a, {type} b)
{{
a = GUF_UWRAP_{bits}(a);
b = GUF_UWRAP_{bits}(b);
const {type} c = GUF_UWRAP_{bits}( 1u * a * b );
return a != 0 && ((1u * c / a) != b) ? GUF_MATH_CKD_OVERFLOW_POS : GUF_MATH_CKD_SUCCESS;
}}
""")
ckd_add_sub_int_header = textwrap.dedent("""\
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_{type_abbr}({type} a, {type} b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_{type_abbr}({type} a, {type} b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_{type_abbr}({type} a, {type} b);
""")
ckd_add_sub_int = textwrap.dedent("""\
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_{type_abbr}({type} a, {type} b)
{{
if (b > 0 && a > {int_max} - b) {{
return GUF_MATH_CKD_OVERFLOW_POS;
}} else if (b < 0 && a < {int_min} - b) {{
return GUF_MATH_CKD_OVERFLOW_NEG;
}} else {{
return GUF_MATH_CKD_SUCCESS;
}}
}}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_{type_abbr}({type} a, {type} b)
{{
if (b < 0 && a > {int_max} + b) {{
return GUF_MATH_CKD_OVERFLOW_POS;
}} else if (b > 0 && a < {int_min} + b) {{
return GUF_MATH_CKD_OVERFLOW_NEG;
}} else {{
return GUF_MATH_CKD_SUCCESS;
}}
}}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_{type_abbr}({type} a, {type} b)
{{
if (b > 0) {{
if (a > {int_max} / b) {{
return GUF_MATH_CKD_OVERFLOW_POS;
}} else if (a < {int_min} / b) {{
return GUF_MATH_CKD_OVERFLOW_NEG;
}} else {{
return GUF_MATH_CKD_SUCCESS;
}}
}} else if (b < 0) {{
if ({int_min} != -{int_max} && b == -1) {{ // Prevent potential ({int_min} / b) overflow for b == -1
return a == {int_min} ? GUF_MATH_CKD_OVERFLOW_POS : GUF_MATH_CKD_SUCCESS;
}} else if (a < {int_max} / b) {{
return GUF_MATH_CKD_OVERFLOW_POS;
}} else if (a > {int_min} / b) {{
return GUF_MATH_CKD_OVERFLOW_NEG;
}} else {{
return GUF_MATH_CKD_SUCCESS;
}}
}} else {{
return GUF_MATH_CKD_SUCCESS;
}}
}}
""")
saturating_wrapping_int_header = textwrap.dedent("""\
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_{type_abbr}({type} a, {type} b, {type} *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_{type_abbr}({type} a, {type} b, {type} *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_{type_abbr}({type} a, {type} b, {type} *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_{type_abbr}({type} a, {type} b, {type} *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_{type_abbr}({type} a, {type} b, {type} *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_{type_abbr}({type} a, {type} b, {type} *result);
""")
saturating_wrapping_int = textwrap.dedent("""\
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_{type_abbr}({type} a, {type} b, {type} *result)
{{
const guf_math_ckd_result check = guf_ckd_add_{type_abbr}(a, b);
if (result) {{
switch (check) {{
case GUF_MATH_CKD_SUCCESS:
*result = a + b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
*result = {int_max};
break;
case GUF_MATH_CKD_OVERFLOW_NEG:
*result = {int_min};
break;
default:
GUF_ASSERT(false);
}}
}}
return check;
}}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_{type_abbr}({type} a, {type} b, {type} *result)
{{
const guf_math_ckd_result check = guf_ckd_sub_{type_abbr}(a, b);
if (result) {{
switch (check) {{
case GUF_MATH_CKD_SUCCESS:
*result = a - b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
*result = {int_max};
break;
case GUF_MATH_CKD_OVERFLOW_NEG:
*result = {int_min};
break;
default:
GUF_ASSERT(false);
}}
}}
return check;
}}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_{type_abbr}({type} a, {type} b, {type} *result)
{{
const guf_math_ckd_result check = guf_ckd_mul_{type_abbr}(a, b);
if (result) {{
switch (check) {{
case GUF_MATH_CKD_SUCCESS:
*result = a * b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
*result = {int_max};
break;
case GUF_MATH_CKD_OVERFLOW_NEG:
*result = {int_min};
break;
default:
GUF_ASSERT(false);
}}
}}
return check;
}}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_{type_abbr}({type} a, {type} b, {type} *result)
{{
const guf_math_ckd_result check = guf_ckd_add_{type_abbr}(a, b);
if (result) {{
switch (check) {{
case GUF_MATH_CKD_SUCCESS:
*result = a + b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
*result = (a + {int_min}) + (b + {int_min});
break;
case GUF_MATH_CKD_OVERFLOW_NEG:
*result = (a - {int_min}) + (b - {int_min});
break;
default:
GUF_ASSERT(false);
}}
}}
return check;
}}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_{type_abbr}({type} a, {type} b, {type} *result)
{{
const guf_math_ckd_result check = guf_ckd_sub_{type_abbr}(a, b);
if (result) {{
switch (check) {{
case GUF_MATH_CKD_SUCCESS:
*result = a - b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
GUF_ASSERT(b < 0);
*result = (a + {int_min}) - (b - {int_min}); // TODO: not sure
break;
case GUF_MATH_CKD_OVERFLOW_NEG:
GUF_ASSERT(b > 0);
*result = (a - {int_min}) - (b + {int_min}); // TODO: not sure
break;
default:
GUF_ASSERT(false);
}}
}}
return check;
}}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_{type_abbr}({type} a, {type} b, {type} *result)
{{
const guf_math_ckd_result check = guf_ckd_mul_{type_abbr}(a, b);
if (result) {{
switch (check) {{
case GUF_MATH_CKD_SUCCESS:
*result = a * b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
case GUF_MATH_CKD_OVERFLOW_NEG: {{
{uint_type} res = 1u * ({uint_type})a * ({uint_type})b;
if (res > {int_max}) {{ // This is the fix for implementation defined conversion from unsigned to signed.
const {uint_type} mod = ({uint_type}){int_max} + 1u;
GUF_ASSERT(mod > 0);
res = 1u * res % mod;
*result = {int_min} + ({type})res;
}} else {{
*result = ({type})res;
}}
break;
}}
default:
GUF_ASSERT(false);
}}
}}
return check;
}}
""")
saturating_wrapping_uint_header = textwrap.dedent("""\
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_{type_abbr}({type} a, {type} b, {type} *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_{type_abbr}({type} a, {type} b, {type} *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_{type_abbr}({type} a, {type} b, {type} *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_{type_abbr}({type} a, {type} b, {type} *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_{type_abbr}({type} a, {type} b, {type} *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_{type_abbr}({type} a, {type} b, {type} *result);
""")
saturating_wrapping_uint = textwrap.dedent("""\
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_{type_abbr}({type} a, {type} b, {type} *result)
{{
const guf_math_ckd_result check = guf_ckd_add_{type_abbr}(a, b);
GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW_POS);
if (result) {{
switch (check) {{
case GUF_MATH_CKD_SUCCESS:
*result = a + b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
*result = {int_max};
break;
default:
GUF_ASSERT(false);
}}
}}
return check;
}}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_{type_abbr}({type} a, {type} b, {type} *result)
{{
const guf_math_ckd_result check = guf_ckd_sub_{type_abbr}(a, b);
GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW_NEG);
if (result) {{
switch (check) {{
case GUF_MATH_CKD_SUCCESS:
*result = a - b;
break;
case GUF_MATH_CKD_OVERFLOW_NEG:
*result = 0;
break;
default:
GUF_ASSERT(false);
}}
}}
return check;
}}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_{type_abbr}({type} a, {type} b, {type} *result)
{{
const guf_math_ckd_result check = guf_ckd_mul_{type_abbr}(a, b);
GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW_POS);
if (result) {{
switch (check) {{
case GUF_MATH_CKD_SUCCESS:
*result = a * b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
*result = {int_max};
break;
default:
GUF_ASSERT(false);
}}
}}
return check;
}}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_{type_abbr}({type} a, {type} b, {type} *result)
{{
const guf_math_ckd_result check = guf_ckd_add_{type_abbr}(a, b);
if (result) {{
*result = 1u * a + b;
}}
return check;
}}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_{type_abbr}({type} a, {type} b, {type} *result)
{{
const guf_math_ckd_result check = guf_ckd_sub_{type_abbr}(a, b);
if (result) {{
*result = 1u * a - b;
}}
return check;
}}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_{type_abbr}({type} a, {type} b, {type} *result)
{{
const guf_math_ckd_result check = guf_ckd_mul_{type_abbr}(a, b);
if (result) {{
*result = 1u * a * b;
}}
return check;
}}
""")
saturating_wrapping_uint_FAST = textwrap.dedent("""\
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_{type_abbr}({type} a, {type} b, {type} *result)
{{
const guf_math_ckd_result check = guf_ckd_add_{type_abbr}(a, b);
GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW_POS);
if (result) {{
switch (check) {{
case GUF_MATH_CKD_SUCCESS:
*result = a + b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
*result = {int_max};
break;
default:
GUF_ASSERT(false);
}}
}}
return check;
}}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_{type_abbr}({type} a, {type} b, {type} *result)
{{
const guf_math_ckd_result check = guf_ckd_sub_{type_abbr}(a, b);
GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW_NEG);
if (result) {{
switch (check) {{
case GUF_MATH_CKD_SUCCESS:
*result = a - b;
break;
case GUF_MATH_CKD_OVERFLOW_NEG:
*result = 0;
break;
default:
GUF_ASSERT(false);
}}
}}
return check;
}}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_{type_abbr}({type} a, {type} b, {type} *result)
{{
const guf_math_ckd_result check = guf_ckd_mul_{type_abbr}(a, b);
GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW_POS);
if (result) {{
switch (check) {{
case GUF_MATH_CKD_SUCCESS:
*result = a * b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
*result = {int_max};
break;
default:
GUF_ASSERT(false);
}}
}}
return check;
}}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_{type_abbr}({type} a, {type} b, {type} *result)
{{
a = GUF_UWRAP_{bits}(a);
b = GUF_UWRAP_{bits}(b);
const guf_math_ckd_result check = guf_ckd_add_{type_abbr}(a, b);
if (result) {{
*result = GUF_UWRAP_{bits}( 1u * a + b );
}}
return check;
}}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_{type_abbr}({type} a, {type} b, {type} *result)
{{
a = GUF_UWRAP_{bits}(a);
b = GUF_UWRAP_{bits}(b);
const guf_math_ckd_result check = guf_ckd_sub_{type_abbr}(a, b);
if (result) {{
*result = GUF_UWRAP_{bits}( 1u * a - b );
}}
return check;
}}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_{type_abbr}({type} a, {type} b, {type} *result)
{{
a = GUF_UWRAP_{bits}(a);
b = GUF_UWRAP_{bits}(b);
const guf_math_ckd_result check = guf_ckd_mul_{type_abbr}(a, b);
if (result) {{
*result = GUF_UWRAP_{bits}( 1u * a * b );
}}
return check;
}}
""")
text_result = "// Signed integer arithmetic checks (generated with libguf/tools/ckdint-gen.py)\n"
text_result_header = text_result
for type in int_types:
end = "\n"
if type.is_optional:
text_result += f"#ifdef {type.INT_MAX}\n"
text_result_header += f"#ifdef {type.INT_MAX}\n"
end = ""
text_result += ckd_add_sub_int.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX, uint_max = type.UINT_MAX) + end
text_result_header += ckd_add_sub_int_header.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX, uint_max = type.UINT_MAX) + end
if type.is_optional:
text_result += "#endif\n\n"
text_result_header += "#endif\n\n"
text_result += "\n// Unsigned integer arithmetic checks (generated with libguf/tools/ckdint-gen.py) \n"
text_result_header += "\n// Unsigned integer arithmetic checks (generated with libguf/tools/ckdint-gen.py) \n"
for type in uint_types:
end = "\n"
if type.is_optional:
text_result += f"#ifdef {type.INT_MAX}\n"
text_result_header += f"#ifdef {type.INT_MAX}\n"
end = ""
if "uint_fast" in type.INT_TYPE:
bits = 0
if "fast8" in type.INT_TYPE:
bits = 8
elif "fast16" in type.INT_TYPE:
bits = 16
elif "fast32" in type.INT_TYPE:
bits = 32
elif "fast64" in type.INT_TYPE:
bits = 64
else:
assert(False)
text_result += ckd_add_sub_uint_FAST.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX, bits = str(bits))
else:
text_result += ckd_add_sub_uint.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX) + end
text_result_header += ckd_add_sub_uint_header.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX) + end
if type.is_optional:
text_result += "#endif\n\n"
text_result_header += "#endif\n\n"
text_result += "\n\n// Signed saturating/wrapping arithmetic (generated with libguf/tools/ckdint-gen.py)\n"
text_result_header += "\n\n// Signed saturating/wrapping arithmetic (generated with libguf/tools/ckdint-gen.py)\n"
for type in int_types:
end = "\n"
if type.is_optional:
text_result += f"#ifdef {type.INT_MAX}\n"
text_result_header += f"#ifdef {type.INT_MAX}\n"
end = ""
text_result += saturating_wrapping_int.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX, uint_type = type.UINT_TYPE, uint_max = type.UINT_MAX) + end
text_result_header += saturating_wrapping_int_header.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX, uint_type = type.UINT_TYPE, uint_max = type.UINT_MAX) + end
if type.is_optional:
text_result += "#endif\n\n"
text_result_header += "#endif\n\n"
text_result += "\n// Unsigned saturating/wrapping arithmetic (generated with libguf/tools/ckdint-gen.py)\n"
text_result_header += "\n// Unsigned saturating/wrapping arithmetic (generated with libguf/tools/ckdint-gen.py)\n"
for type in uint_types:
end = "\n"
if type.is_optional:
text_result += f"#ifdef {type.INT_MAX}\n"
text_result_header += f"#ifdef {type.INT_MAX}\n"
end = ""
if "uint_fast" in type.INT_TYPE:
bits = 0
if "fast8" in type.INT_TYPE:
bits = 8
elif "fast16" in type.INT_TYPE:
bits = 16
elif "fast32" in type.INT_TYPE:
bits = 32
elif "fast64" in type.INT_TYPE:
bits = 64
else:
assert(False)
text_result += saturating_wrapping_uint_FAST.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX, bits = str(bits)) + end
else:
text_result += saturating_wrapping_uint.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX) + end
text_result_header += saturating_wrapping_uint_header.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX) + end
if type.is_optional:
text_result += "#endif\n\n"
text_result_header += "#endif\n\n"
return (text_result_header, text_result)
if __name__ == "__main__":
int_types = [
IntType(INT_TYPE = "int", INT_TYPE_ABBR = "int", INT_MIN = "INT_MIN", INT_MAX = "INT_MAX", UINT_TYPE = "unsigned", UINT_MAX = "UINT_MAX"),
IntType(INT_TYPE = "long", INT_TYPE_ABBR = "long", INT_MIN = "LONG_MIN", INT_MAX = "LONG_MAX", UINT_TYPE = "unsigned long", UINT_MAX = "ULONG_MAX"),
IntType(INT_TYPE = "long long", INT_TYPE_ABBR = "long_long", INT_MIN = "LLONG_MIN", INT_MAX = "LLONG_MAX", UINT_TYPE = "unsigned long long", UINT_MAX = "ULLONG_MAX"),
# TODO: size_t is not necessarily the unsigned ptrdiff_t equivalent
IntType(INT_TYPE = "ptrdiff_t", INT_TYPE_ABBR = "ptrdiff_t", INT_MIN = "PTRDIFF_MIN", INT_MAX = "PTRDIFF_MAX", UINT_TYPE = "size_t", UINT_MAX = "SIZE_MAX"),
IntType(INT_TYPE = "int_fast8_t", INT_TYPE_ABBR = "int_fast8_t", INT_MIN = "GUF_INT8_MIN", INT_MAX = "GUF_INT8_MAX", UINT_TYPE = "uint_fast8_t", UINT_MAX = "GUF_UINT8_MAX"),
IntType(INT_TYPE = "int_fast16_t", INT_TYPE_ABBR = "int_fast16_t", INT_MIN = "GUF_INT16_MIN", INT_MAX = "GUF_INT16_MAX", UINT_TYPE = "uint_fast16_t", UINT_MAX = "GUF_UINT16_MAX"),
IntType(INT_TYPE = "int_fast32_t", INT_TYPE_ABBR = "int_fast32_t", INT_MIN = "GUF_INT32_MIN", INT_MAX = "GUF_INT32_MAX", UINT_TYPE = "uint_fast32_t", UINT_MAX = "GUF_UINT32_MAX"),
IntType(INT_TYPE = "int_fast64_t", INT_TYPE_ABBR = "int_fast64_t", INT_MIN = "GUF_INT64_MIN", INT_MAX = "GUF_INT64_MAX", UINT_TYPE = "uint_fast64_t", UINT_MAX = "GUF_UINT64_MAX"),
IntType(INT_TYPE = "int8_t", INT_TYPE_ABBR = "i8", INT_MIN = "INT8_MIN", INT_MAX = "INT8_MAX", UINT_TYPE = "uint8_t", UINT_MAX = "GUF_UINT8_MAX", is_optional = True),
IntType(INT_TYPE = "int16_t", INT_TYPE_ABBR = "i16", INT_MIN = "INT16_MIN", INT_MAX = "INT16_MAX", UINT_TYPE = "uint16_t", UINT_MAX = "GUF_UINT16_MAX", is_optional = True),
IntType(INT_TYPE = "int32_t", INT_TYPE_ABBR = "i32", INT_MIN = "INT32_MIN", INT_MAX = "INT32_MAX", UINT_TYPE = "uint32_t", UINT_MAX = "GUF_UINT32_MAX", is_optional = True),
IntType(INT_TYPE = "int64_t", INT_TYPE_ABBR = "i64", INT_MIN = "INT64_MIN", INT_MAX = "INT64_MAX", UINT_TYPE = "uint64_t", UINT_MAX = "GUF_UINT64_MAX", is_optional = True),
]
uint_types = [
UintType(INT_TYPE = "unsigned char", INT_TYPE_ABBR = "uchar", INT_MIN = "0", INT_MAX = "UCHAR_MAX"),
UintType(INT_TYPE = "unsigned", INT_TYPE_ABBR = "unsigned", INT_MIN = "0", INT_MAX = "UINT_MAX"),
UintType(INT_TYPE = "unsigned long", INT_TYPE_ABBR = "ulong", INT_MIN = "0", INT_MAX = "ULONG_MAX"),
UintType(INT_TYPE = "unsigned long long", INT_TYPE_ABBR = "ulong_long", INT_MIN = "0", INT_MAX = "ULLONG_MAX"),
UintType(INT_TYPE = "size_t", INT_TYPE_ABBR = "size_t", INT_MIN = "0", INT_MAX = "SIZE_MAX"),
UintType(INT_TYPE = "uint_fast8_t", INT_TYPE_ABBR = "uint_fast8_t", INT_MIN = "0", INT_MAX = "GUF_UINT8_MAX"),
UintType(INT_TYPE = "uint_fast16_t", INT_TYPE_ABBR = "uint_fast16_t", INT_MIN = "0", INT_MAX = "GUF_UINT16_MAX"),
UintType(INT_TYPE = "uint_fast32_t", INT_TYPE_ABBR = "uint_fast32_t", INT_MIN = "0", INT_MAX = "GUF_UINT32_MAX"),
UintType(INT_TYPE = "uint_fast64_t", INT_TYPE_ABBR = "uint_fast64_t", INT_MIN = "0", INT_MAX = "GUF_UINT64_MAX"),
UintType(INT_TYPE = "uint8_t", INT_TYPE_ABBR = "u8", INT_MIN = "0", INT_MAX = "UINT8_MAX", is_optional = True),
UintType(INT_TYPE = "uint16_t", INT_TYPE_ABBR = "u16", INT_MIN = "0", INT_MAX = "UINT16_MAX", is_optional = True),
UintType(INT_TYPE = "uint32_t", INT_TYPE_ABBR = "u32", INT_MIN = "0", INT_MAX = "UINT32_MAX", is_optional = True),
UintType(INT_TYPE = "uint64_t", INT_TYPE_ABBR = "u64", INT_MIN = "0", INT_MAX = "UINT64_MAX", is_optional = True),
]
code_header, code_impl = generate_ckdint_functions(int_types = int_types, uint_types= uint_types)
print(textwrap.dedent(
"""
#if defined(GUF_MATH_CKDINT_IMPL_STATIC)
#define GUF_MATH_CKDINT_KWRDS static inline
#else
#define GUF_MATH_CKDINT_KWRDS
#endif
#ifndef GUF_MATH_CKDINT_H
#define GUF_MATH_CKDINT_H
#include "guf_common.h"
typedef enum guf_math_ckd_result {GUF_MATH_CKD_SUCCESS = 0, GUF_MATH_CKD_OVERFLOW_POS, GUF_MATH_CKD_OVERFLOW_NEG} guf_math_ckd_result;
"""))
print("#if !defined(GUF_MATH_CKDINT_IMPL_STATIC) && !defined(GUF_MATH_CKDINT_IMPL)")
print(code_header)
print("#endif")
print("#if defined(GUF_MATH_CKDINT_IMPL) || defined(GUF_MATH_CKDINT_IMPL_STATIC)")
print('#include "guf_assert.h"')
print(code_impl)
print("#endif /* End impl */\n")
print("#endif /* End header-guard */\n")
print("#undef GUF_MATH_CKDINT_KWRDS")
print("#undef GUF_MATH_CKDINT_IMPL")
print("#undef GUF_MATH_CKDINT_IMPL_STATIC\n")