/* ************************************************************************** */
/*                                                                            */
/*                                                        :::      ::::::::   */
/*   ft_safe_int_math.c                                 :+:      :+:    :+:   */
/*                                                    +:+ +:+         +:+     */
/*   By: thrieg <thrieg@student.42mulhouse.fr>      +#+  +:+       +#+        */
/*                                                +#+#+#+#+#+   +#+           */
/*   Created: 2024/11/08 11:11:17 by alier             #+#    #+#             */
/*   Updated: 2025/02/16 19:04:25 by thrieg           ###   ########.fr       */
/*                                                                            */
/* ************************************************************************** */

#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>
#include <errno.h>

/* 
 * Does saturate and never overflows/underflows.
 * Sets `errno` to `ERANGE` if the operation would
 * have caused an overflow/underflow.
 */
int	safe_int_add(int a, int b)
{
	if (b >= 0 && a > INT_MAX - b)
	{
		errno = ERANGE;
		return (INT_MAX);
	}
	else if (b < 0 && a < INT_MIN - b)
	{
		errno = ERANGE;
		return (INT_MIN);
	}
	return (a + b);
}

/* 
 * Does saturate and never overflows/underflows.
 * Sets `errno` to `ERANGE` if the operation would
 * have caused an overflow/underflow.
 */
int	safe_int_sub(int a, int b)
{
	if (b >= 0 && a < INT_MIN + b)
	{
		errno = ERANGE;
		return (INT_MIN);
	}
	else if (b < 0 && a > INT_MAX + b)
	{
		errno = ERANGE;
		return (INT_MAX);
	}
	return (a - b);
}

/* 
 * Does saturate and never overflows/underflows.
 * Sets `errno` to `ERANGE` if the operation would
 * have caused an overflow/underflow.
 */
int	safe_int_mul(int a, int b)
{
	if (b > 0)
	{
		if (a > 0 && a > INT_MAX / b)
			return (errno = ERANGE, INT_MAX);
		else if (a < 0 && a < INT_MIN / b)
			return (errno = ERANGE, INT_MIN);
	}
	else if (b < 0)
	{
		if (a < 0 && a < INT_MAX / b)
			return (errno = ERANGE, INT_MAX);
		else if ((-INT_MAX > INT_MIN && b < -1) && a > INT_MIN / b)
			return (errno = ERANGE, INT_MIN);
	}
	return (a * b);
}
