<commit_before><?php
namespace Granam\Number\Tools;

use Granam\Scalar\Tools\ToString;

class ToNumber
{
    /**
     * @param $value
     * @param bool $paranoid Throws exception if some value is lost on cast due to rounding on cast
     *
     * @return float|int
     */
    public static function toNumber($value, $paranoid = false)
    {
        if (is_float($value)) {
            return $value;
        }
        if (is_int($value)) {
            return $value;
        }
        if (is_bool($value) || is_null($value)) {
            // true = 1; false = 0; null = 0
            return intval($value);
        }

        try {
            $stringValue = ToString::toString($value);
        } catch (\Granam\Scalar\Tools\Exceptions\WrongParameterType $exception) {
            throw new Exceptions\WrongParameterType($exception->getMessage(), $exception->getCode(), $exception);
        }

        $floatValue = floatval($stringValue); // note: '' = 0.0
        if ($paranoid) {
            self::checkIfNoValueHasBeenLostByCast($floatValue, $stringValue);
        }

        $intValue = intval($floatValue);
        if (floatval($intValue) === $floatValue) {
            return $intValue;
        }

        return $floatValue;
    }

    private static function checkIfNoValueHasBeenLostByCast($floatValue, $stringValue)
    {
        preg_match('~^(?:\s*0*)(?<numericPart>\d+(\.([1-9]+|0+(?=[1-9]+))+)*)~', $stringValue, $numericParts);
        $numericPart = '0';
        if (isset($numericParts['numericPart'])) {
            $numericPart = $numericParts['numericPart'];
        }

        if ("$floatValue" !== $numericPart) { // some value has been lost
            throw new Exceptions\ValueLostOnCast(
                'Some value has been lost on cast. Given string-number ' . var_export($numericPart, true) . ' results into float ' . var_export($floatValue, true)
            );
        }
    }
}<commit_msg>Casting to number optimized a bit<commit_after><?php
namespace Granam\Number\Tools;

use Granam\Scalar\Tools\ToString;

class ToNumber
{
    /**
     * @param $value
     * @param bool $paranoid Throws exception if some value is lost on cast due to rounding on cast
     *
     * @return float|int
     */
    public static function toNumber($value, $paranoid = false)
    {
        if (is_float($value)) {
            return $value;
        }
        if (is_int($value)) {
            return $value;
        }
        if (is_bool($value) || $value === null) {
            // true = 1; false = 0; null = 0
            return (int)$value;
        }

        try {
            $stringValue = ToString::toString($value);
        } catch (\Granam\Scalar\Tools\Exceptions\WrongParameterType $exception) {
            throw new Exceptions\WrongParameterType($exception->getMessage(), $exception->getCode(), $exception);
        }

        $floatValue = (float)$stringValue; // note: '' = 0.0
        if ($paranoid) {
            self::checkIfNoValueHasBeenLostByCast($floatValue, $stringValue);
        }

        $intValue = (int)$floatValue;
        if ((float)$intValue === $floatValue) {
            return $intValue;
        }

        return $floatValue;
    }

    private static function checkIfNoValueHasBeenLostByCast($floatValue, $stringValue)
    {
        $numericPart = '0';
        if (preg_match('~^(?:\s*0*)(?<numericPart>\d+(\.([1-9]+|0+(?=[1-9]+))+)*)~', $stringValue, $numericParts) > 0) {
            $numericPart = $numericParts['numericPart'];
        }

        if ("$floatValue" !== $numericPart) { // some value has been lost
            throw new Exceptions\ValueLostOnCast(
                'Some value has been lost on cast. Given string-number ' . var_export($numericPart, true) . ' results into float ' . var_export($floatValue, true)
            );
        }
    }
}
{'fraction_non_alphanumeric': 0.14259501965923985, 'fraction_numerical': 0.00655307994757536, 'mean_word_length': 2.2094196804037005, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 10, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '645772', 'n_tokens_mistral': 1148, 'n_tokens_neox': 1117, 'n_words': 250}