This commit is contained in:
Xes
2025-08-14 22:41:49 +02:00
parent 2de81ccc46
commit 8ce45119b6
39774 changed files with 4309466 additions and 0 deletions

View File

@@ -0,0 +1 @@
vendor

21
vendor/yuloh/bccomp-polyfill/LICENSE.md vendored Normal file
View File

@@ -0,0 +1,21 @@
# The MIT License (MIT)
Copyright (c) 2016 Matthew Allan matthew.james.allan@gmail.com
> Permission is hereby granted, free of charge, to any person obtaining a copy
> of this software and associated documentation files (the "Software"), to deal
> in the Software without restriction, including without limitation the rights
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> copies of the Software, and to permit persons to whom the Software is
> furnished to do so, subject to the following conditions:
>
> The above copyright notice and this permission notice shall be included in
> all copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> THE SOFTWARE.

17
vendor/yuloh/bccomp-polyfill/README.md vendored Normal file
View File

@@ -0,0 +1,17 @@
# BCComp Polyfill
A polyfill for the `bcmath` function, `bccomp`.
## Why?
I maintain a library that only uses `bccomp`, and doesn't use the rest of `bcmath`. I wanted to be able to work on it on machines that weren't compiled with `bcmath` support, so I wrote this polyfill.
## Install
```bash
composer require yuloh/bccomp-polyfill
```
## Usage
If the function `bccomp` does not exist in the global namespace, this library will declare it's own `bccomp` function.

View File

@@ -0,0 +1,19 @@
{
"name": "yuloh/bccomp-polyfill",
"authors": [
{
"name": "Matt Allan",
"email": "matthew.james.allan@gmail.com"
}
],
"license": "MIT",
"require": {},
"autoload": {
"psr-4": {
"Yuloh\\BcCompPolyfill\\": "src"
},
"files": [
"src/functions.php"
]
}
}

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/autoload.php"
backupGlobals="false"
backupStaticAttributes="false"
colors="true"
verbose="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
<testsuites>
<testsuite name="bccomp Polyfill Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">src/</directory>
<file>./functions.php</file>
</whitelist>
</filter>
<!-- <logging>
<log type="tap" target="build/report.tap"/>
<log type="junit" target="build/report.junit.xml"/>
<log type="coverage-html" target="build/coverage" charset="UTF-8" yui="true" highlight="true"/>
<log type="coverage-text" target="build/coverage.txt"/>
<log type="coverage-clover" target="build/logs/clover.xml"/>
</logging> -->
</phpunit>

View File

@@ -0,0 +1,146 @@
<?php
namespace Yuloh\BcCompPolyfill;
class BigNumber
{
/**
* @var string
*/
private $characteristic = '0';
/**
* @var int
*/
private $characteristicLength;
/**
* @var string
*/
private $mantissa = '';
/**
* @var boolean
*/
private $isNegative = false;
/**
* @param string $value
*/
public function __construct($value)
{
if (static::isNumeric($value)) {
$this->setValues($value);
}
}
/**
* @return boolean
*/
public function isNegative()
{
return $this->isNegative;
}
/**
* @return boolean
*/
public function isPositive()
{
return !$this->isNegative();
}
/**
* @return boolean
*/
public function isZero()
{
return $this->getCharacteristic() === '0' && $this->getMantissa() === '';
}
/**
* @return string
*/
public function getCharacteristic()
{
return $this->characteristic;
}
/**
* @return int
*/
public function getCharacteristicLength()
{
if (is_null($this->characteristicLength)) {
$this->characteristicLength = strlen($this->getCharacteristic());
}
return $this->characteristicLength;
}
/**
* @return string
*/
public function getMantissa()
{
return $this->mantissa;
}
/**
* @param string $value
*/
private function setValues($value)
{
if ($value[0] === '-') {
$this->isNegative = true;
$value = substr($value, 1);
}
$this->characteristic = static::parseCharacteristic($value);
$this->mantissa = static::parseMantissa($value);
}
/**
* @param string $value
* @return string
*/
private static function parseCharacteristic($value)
{
if (strpos($value, '.') !== false) {
$value = substr($value, 0, strpos($value, '.'));
}
return strlen($value) === 1 ? $value : ltrim($value, '0');
}
/**
* @param string $value
* @return string
*/
private static function parseMantissa($value)
{
if (($separatorPos = strrpos($value, '.')) === false) {
return '';
}
$value = substr($value, strrpos($value, '.') + 1);
return rtrim($value, '0');
}
/**
* @param string $value
* @return boolean
*/
private static function isNumeric($value)
{
// remove the last decimal separator only.
// If it has more decimal separators it's invalid.
$separatorPos = strrpos($value, '.');
if ($separatorPos !== false) {
$value = substr_replace($value, '', $separatorPos, 1);
}
return ctype_digit($value) || ($value[0] === '-' && ctype_digit(substr($value, 1)));
}
}

View File

@@ -0,0 +1,102 @@
<?php
namespace Yuloh\BcCompPolyfill{
if (!function_exists('Yuloh\BcCompPolyfill\bccomp')) {
function bccomp($leftOperand, $rightOperand, $scale = 0)
{
$leftOperand = new BigNumber((string) $leftOperand);
$rightOperand = new BigNumber((string) $rightOperand);
// The real bccomp casts floats to int but throws a warning for anything else.
if (is_float($scale)) {
$scale = (int) $scale;
}
if (!is_int($scale)) {
trigger_error(
sprintf('bccomp() expects parameter 3 to be integer, %s given', gettype($scale)),
E_USER_WARNING
);
}
// If both numbers are zero, they are equal.
if ($leftOperand->isZero() && $rightOperand->isZero()) {
return 0;
}
// If one number is positive while the other is negative we can return early.
if ($leftOperand->isPositive() && $rightOperand->isNegative()) {
return 1;
}
if ($leftOperand->isNegative() && $rightOperand->isPositive()) {
return -1;
}
$isPositiveComparison = $leftOperand->isPositive() && $rightOperand->isPositive();
// If the part to the left of the decimal is longer it's the larger number.
if ($leftOperand->getCharacteristicLength() > $rightOperand->getCharacteristicLength()) {
return $isPositiveComparison ? 1 : -1;
}
if ($leftOperand->getCharacteristicLength() < $rightOperand->getCharacteristicLength()) {
return $isPositiveComparison ? -1 : 1;
}
// if the part to the left of the decimal is equal, we check each place for a larger number.
for ($i = 0; $i < $leftOperand->getCharacteristicLength(); $i++) {
if ($leftOperand->getCharacteristic()[$i] > $rightOperand->getCharacteristic()[$i]) {
return $isPositiveComparison ? 1 : -1;
}
if ($leftOperand->getCharacteristic()[$i] < $rightOperand->getCharacteristic()[$i]) {
return $isPositiveComparison ? -1 : 1;
}
}
// if there is a scale and we still haven't found the larger number,
// check each place to the right of the decimal place.
$leftMantissa = $leftOperand->getMantissa();
$rightMantissa = $rightOperand->getMantissa();
for ($i = 0; $i < $scale; $i++) {
// If we are still iterating and out of digits to compare,
// we can return early.
if (!isset($leftMantissa[$i]) && !isset($rightMantissa[$i])) {
return 0;
}
// If there isn't a digit in this decimal place, set it to 0.
if (!isset($leftMantissa[$i])) {
$leftMantissa = $leftMantissa . '0';
}
if (!isset($rightMantissa[$i])) {
$rightMantissa = $rightMantissa . '0';
}
if ($leftMantissa[$i] > $rightMantissa[$i]) {
return $isPositiveComparison ? 1 : -1;
}
if ($leftMantissa[$i] < $rightMantissa[$i]) {
return $isPositiveComparison ? -1 : 1;
}
}
return 0;
}
}
}
namespace {
if (!function_exists('bccomp')) {
function bccomp($leftOperand, $rightOperand, $scale = 0)
{
return \Yuloh\BcCompPolyfill\bccomp($leftOperand, $rightOperand, $scale);
}
}
}

View File

@@ -0,0 +1,99 @@
<?php
namespace Yuloh\BcCompPolyfill;
class BcCompTest extends \PHPUnit_Framework_TestCase
{
public function bcCompData()
{
return [
['1', '2', 0, -1, 'lt'],
['2', '1', 0, 1, 'gt'],
['2', '2', 0, 0, 'eq'],
['123', '1', 0, 1, 'gt when left operand is longer'],
['1', '123', 0, -1, 'lt when left operand is shorter'],
['100.12', '100.13', 0, 0, 'eq when scale is 0 but mantissa is less than'],
['100.12', '100.13', 1, 0, 'eq when eq up to last decimal place checked'],
['100.12', '100.13', 2, -1, 'lt with two decimal places checked and last place is lt'],
['100.12', '100.13', 5, -1, 'lt when scale is larger than both operands'],
['1', '-1', 0, 1, 'gt when right operand is negative'],
['-1', '1', 0, -1, 'lt when left operand is negative'],
['-1', '-1', 0, 0, 'eq when both operands are negative'],
['-1', '-2', 0, 1, 'gt when both operands are negative'],
['-2', '-1', 0, -1, 'lt when both operands are negative'],
['-20', '-1', 0, -1, 'lt when both operands are negative and left operand is longer'],
['-2', '-10', 0, 1, 'gt when both operands are negative and left operand is shorter'],
['-200.12', '-200.13', 2, 1, 'gt when both operands are negative with mantissa'],
['-' . PHP_INT_MAX . '99', '-' . PHP_INT_MAX . '99', 0, 0, 'eq when negative and larger than PHP_INT_MAX'],
['-' . PHP_INT_MAX . '99', '-' . PHP_INT_MAX . '98', 0, -1, 'lt when negative and larger than PHP_INT_MAX'],
[PHP_INT_MAX . '99', PHP_INT_MAX . '99', 0, 0, 'eq when larger than PHP_INT_MAX'],
[PHP_INT_MAX . '99', PHP_INT_MAX . '97', 0, 1, 'gt when larger than PHP_INT_MAX'],
[PHP_INT_MAX . '99.999', PHP_INT_MAX . '99.997', 5, 1, 'lt when larger than PHP_INT_MAX with mantissa'],
['riffraff', '1', 0, -1, 'comparison when left operand is nonsense'],
['1', 'kodos', 0, 1, 'comparison when right operand is nonsense'],
['riffraff', 'kodos', 0, 0, 'comparison when both operands are nonsense'],
['1.2.3', '1', 5, -1, 'comparison when left operand has too many decimal separators'],
['1', '1.2.3', 5, 1, 'comparison when right operand has too many decimal separators'],
['1.12', '1.15', 1.6, 0, 'float scale should be cast to int, not rounded'],
['1a', '1b', 0, 0, 'comparison when both operands have a letter in a number'],
['0', '-0', 0, 0, 'comparison of 0 and -0'],
];
}
/**
* @dataProvider bcCompData
*/
public function testBcComp($leftOperand, $rightOperand, $scale, $result, $msg)
{
$realLibraryResult = \bccomp($leftOperand, $rightOperand, $scale);
$this->assertSame($result, $realLibraryResult, 'The actual function result should match the expected result');
$actual = \Yuloh\BcCompPolyfill\bccomp($leftOperand, $rightOperand, $scale);
$this->assertSame($result, $actual, $msg);
}
/**
* @expectedException PHPUnit_Framework_Error_Warning
*/
public function testInvalidScale()
{
\Yuloh\BcCompPolyfill\bccomp(1, 1, []);
}
public function fuzzTestData()
{
$data = [];
for ($i = 0; $i < 1000; $i++) {
$leftOperand = $this->randOperand();
$rightOperand = $this->randOperand();
$scale = rand(0, 200);
$result = \bccomp($leftOperand, $rightOperand, $scale);
$data[] = [$leftOperand, $rightOperand, $scale, $result];
}
return $data;
}
/**
* @dataProvider fuzzTestData
*/
public function testWithRandomData($leftOperand, $rightOperand, $scale, $result)
{
$actual = \Yuloh\BcCompPolyfill\bccomp($leftOperand, $rightOperand, $scale);
$this->assertSame($result, $actual);
}
public function randOperand()
{
$negative = rand() % 2 === 0 ? '-' : '';
$characteristic = rand();
$mantissa = rand() % 2 === 0 ? '.' . rand() : '';
return $negative . $characteristic . $mantissa;
}
}