diff --git a/doc/src/index.dox b/doc/src/index.dox index db95975..d5fba09 100644 --- a/doc/src/index.dox +++ b/doc/src/index.dox @@ -43,6 +43,12 @@ \li \subpage num__parser + \li \subpage num__op + + \li \subpage num__safe_cast + + \li \subpage num__safe_op + \li \subpage patch Text Encoding diff --git a/doc/src/num/op.dox b/doc/src/num/op.dox new file mode 100644 index 0000000..5e22e57 --- /dev/null +++ b/doc/src/num/op.dox @@ -0,0 +1,30 @@ +namespace yycc::num::op { +/** + +\page num__op Numeric Operations + +Namespace yycc::num::op provides functions for robust numeric operations inspired by Rust's approach to primitive type operations. + +Currently, this namespace only supports unsigned integer ceiling division, though more operations may be added in the future based on demand. + +\section num__op__div_ceil Ceiling Division + +The \c div_ceil function performs division between two unsigned integers and rounds up the result. +It uses a safe algorithm that avoids potential overflow issues that could occur with the traditional formula (lhs + rhs - 1) / rhs. + +The function computes: (lhs % rhs == 0) ? (lhs / rhs) : (lhs / rhs) + 1u +The function prevents division by zero by checking the divisor before performing the operation and throwing a std::logic_error if the divisor is zero. + +Here are some examples showing how to use this function: + +\code +#include + +// Ceiling division examples +uint32_t result1 = op::div_ceil(uint32_t(10), uint32_t(3)); // Results in 4 +uint32_t result2 = op::div_ceil(uint32_t(9), uint32_t(3)); // Results in 3 +uint32_t result3 = op::div_ceil(uint32_t(1), uint32_t(10)); // Results in 1 +\endcode + +*/ +} \ No newline at end of file diff --git a/doc/src/num/safe_cast.dox b/doc/src/num/safe_cast.dox new file mode 100644 index 0000000..5de93b8 --- /dev/null +++ b/doc/src/num/safe_cast.dox @@ -0,0 +1,63 @@ +namespace yycc::num::safe_cast { +/** + +\page num__safe_cast Numeric Safe Casting + +Namespace yycc::num::safe_cast provides functions which safely cast numeric value from one type to another. + +\section num__safe_cast__overview Overview + +When writing C++ code, casting between types with different ranges is very important +but greatly easy to make mistakes which finally cause fatal errors. +Inspired by Rust's approach to type conversion, +this namespace provides safe casting functions that handle potential overflow and underflow issues. + +\section num__safe_cast__functions Functions + +The namespace provides two main functions: +\li \c to() - Direct conversion for cases where the destination type can definitely hold the source value +which means definitely safe conversions (widening conversions). +\li \c try_to() - Attempt conversion and return a Result type that includes error information if the conversion fails +which means potentially risky conversions (narrowing conversions). + +The \c try_to function returns a \c std::expected. +If the conversion succeeds, the result contains the converted value. +If it fails, it contains a error info. + +\section num__safe_cast__examples Examples + +Here are some examples showing how to use the safe casting functions: + +\code +#include + +// Safe conversion using 'to' function +uint32_t val1 = safe_cast::to(static_cast(123)); + +// Potentially risky conversion using 'try_to' function +auto result = safe_cast::try_to(static_cast(12345)); +if (result.has_value()) { + auto converted = result.value(); + // Use converted value +} else { + // Handle error +} +\endcode + +\section num__safe_cast__notes Notes + +The safety of conversions is determined at compile time using the \c CAN_SAFE_TO meta-programming concept. +However, for variable-length data types (like \c size_t ), the safety determination may vary across platforms, +which could affect code portability. For this reason, it would be better to use \c try_to for these types +for better robust application on different platforms. + +\section num__safe_cast__limitations Limitations + +This namespace supports safe casting between integral types only. +Currently unsupported conversions include: + +\li Floating-point to floating-point conversions +\li Floating-point to integer conversions + +*/ +} \ No newline at end of file diff --git a/doc/src/num/safe_op.dox b/doc/src/num/safe_op.dox new file mode 100644 index 0000000..ecd6cc1 --- /dev/null +++ b/doc/src/num/safe_op.dox @@ -0,0 +1,86 @@ +namespace yycc::num::safe_op { +/** + +\page num__safe_op Numeric Safe Arithmetic Operations + +Namespace yycc::num::safe_op provides Rust-like safe arithmetic operations +for handling overflow, underflow, and other undefined behaviors in C++. + +\section num__safe_op__overview Overview + +Inspired by Rust's rich set of arithmetic operators, +this namespace provides safe arithmetic operations that handle potential overflow, underflow, and other undefined behaviors that commonly occur in C++. +It offers multiple strategies for handling arithmetic operations including wrapping, checked, overflowing, saturating, and strict operations. + +\section num__safe_op__operation_types Operation Types + +The namespace provides several families of arithmetic operations: + +\li \c wrapping_* operations: Perform arithmetic with wrapping on overflow/underflow (similar to unsigned integer behavior) +\li \c checked_* operations: Return std::optional containing the result, or std::nullopt if overflow/underflow occurs +\li \c overflowing_* operations: Return a pair with the result and a boolean indicating whether overflow occurred +\li \c saturating_* operations: Clamp the result to the min/max value when overflow/underflow occurs +\li \c strict_* operations: Throw exceptions when overflow/underflow occurs +\li \c ordinary operations (add, sub, mul, div): Alias to wrapping operations for safe default behavior + +\section num__safe_op__arithmetic_functions Arithmetic Functions + +For each operation type, the namespace provides functions for the four basic arithmetic operations: +\li \c _add : Addition +\li \c _sub : Subtraction +\li \c _mul : Multiplication +\li \c _div : Division + +For example, for wrapping operations: \c wrapping_add, \c wrapping_sub, \c wrapping_mul, \c wrapping_div. + +\section num__safe_op__examples Examples + +Here are some examples showing how to use the safe arithmetic functions: + +\code +#include +#include + +// Wrapping addition - wraps around on overflow +uint8_t result1 = safe_op::wrapping_add(uint8_t(200), uint8_t(100)); // Results in 44 + +// Checked multiplication - returns std::optional +auto result2 = safe_op::checked_mul(int32_t(1000000), int32_t(1000000)); +if (!result2.has_value()) { + std::cout << "Multiplication overflowed!" << std::endl; +} else { + std::cout << "Result: " << result2.value() << std::endl; +} + +// Overflowing subtraction - returns pair of result and overflow flag +auto [result3, overflowed] = safe_op::overflowing_sub(int32_t(-10), int32_t(INT32_MIN)); +if (overflowed) { + std::cout << "Subtraction overflowed!" << std::endl; +} + +// Saturating multiplication - clamps to min/max on overflow +int32_t result4 = safe_op::saturating_mul(int32_t(1000000), int32_t(1000000)); // Clamps to INT32_MAX + +// Ordinary operations - safe defaults without undefined behavior +int32_t result5 = safe_op::add(int32_t(10), int32_t(20)); // 30 +\endcode + +\section num__safe_op__undefined_behaviors Handling of Undefined Behaviors + +This namespace handles several undefined behaviors in C++ arithmetic: +\li Signed integer overflow and underflow (e.g. INT_MAX + 1) +\li Division by zero +\li Performing INT_MIN / -1 division (which would result in a value that doesn't fit in the type) + +For division operations, special care is taken to handle these undefined behaviors appropriately depending on the operation type. + +\section num__safe_op__platform_support Platform Support + +The implementation uses hardware-specific overflow detection functions: +\li GCC/Clang: Uses built-in functions like __builtin_add_overflow +\li Windows: Uses Windows API functions from \c intsafe.h + +This ensures optimal performance across different platforms. + +*/ +} \ No newline at end of file