Skip to content

Commit

Permalink
feat: introduce Range component (#378)
Browse files Browse the repository at this point in the history
Signed-off-by: azjezz <azjezz@protonmail.com>
  • Loading branch information
azjezz committed Dec 16, 2022
1 parent fcec35d commit fac0f15
Show file tree
Hide file tree
Showing 23 changed files with 1,212 additions and 73 deletions.
252 changes: 181 additions & 71 deletions composer.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/README.md
Expand Up @@ -34,6 +34,7 @@
- [Psl\Promise](./component/promise.md)
- [Psl\PseudoRandom](./component/pseudo-random.md)
- [Psl\RandomSequence](./component/random-sequence.md)
- [Psl\Range](./component/range.md)
- [Psl\Regex](./component/regex.md)
- [Psl\Result](./component/result.md)
- [Psl\Runtime](./component/runtime.md)
Expand Down
4 changes: 4 additions & 0 deletions docs/component/math.md
Expand Up @@ -22,10 +22,14 @@
- [INT53_MIN](./../../src/Psl/Math/constants.php#L0)
- [INT64_MAX](./../../src/Psl/Math/constants.php#L0)
- [INT64_MIN](./../../src/Psl/Math/constants.php#L0)
- [INT8_MAX](./../../src/Psl/Math/constants.php#L0)
- [INT8_MIN](./../../src/Psl/Math/constants.php#L0)
- [NAN](./../../src/Psl/Math/constants.php#L0)
- [PI](./../../src/Psl/Math/constants.php#L0)
- [UINT16_MAX](./../../src/Psl/Math/constants.php#L0)
- [UINT32_MAX](./../../src/Psl/Math/constants.php#L0)
- [UINT64_MAX](./../../src/Psl/Math/constants.php#L0)
- [UINT8_MAX](./../../src/Psl/Math/constants.php#L0)

#### `Functions`

Expand Down
33 changes: 33 additions & 0 deletions docs/component/range.md
@@ -0,0 +1,33 @@
<!--
This markdown file was generated using `docs/documenter.php`.
Any edits to it will likely be lost.
-->

[*index](./../README.md)

---

### `Psl\Range` Component

#### `Functions`

- [between](./../../src/Psl/Range/between.php#L17)
- [from](./../../src/Psl/Range/from.php#L16)
- [full](./../../src/Psl/Range/full.php#L14)
- [to](./../../src/Psl/Range/to.php#L16)

#### `Interfaces`

- [LowerBoundRangeInterface](./../../src/Psl/Range/LowerBoundRangeInterface.php#L18)
- [RangeInterface](./../../src/Psl/Range/RangeInterface.php#L14)
- [UpperBoundRangeInterface](./../../src/Psl/Range/UpperBoundRangeInterface.php#L14)

#### `Classes`

- [BetweenRange](./../../src/Psl/Range/BetweenRange.php#L45)
- [FromRange](./../../src/Psl/Range/FromRange.php#L36)
- [FullRange](./../../src/Psl/Range/FullRange.php#L20)
- [ToRange](./../../src/Psl/Range/ToRange.php#L22)


1 change: 1 addition & 0 deletions docs/documenter.php
Expand Up @@ -213,6 +213,7 @@ function get_all_components(): array
'Psl\\Promise',
'Psl\\PseudoRandom',
'Psl\\RandomSequence',
'Psl\\Range',
'Psl\\Regex',
'Psl\\Result',
'Psl\\Runtime',
Expand Down
15 changes: 15 additions & 0 deletions src/Psl/Internal/Loader.php
Expand Up @@ -37,8 +37,12 @@ final class Loader
'Psl\\Math\\INT32_MIN' => 'Psl/Math/constants.php',
'Psl\\Math\\INT16_MAX' => 'Psl/Math/constants.php',
'Psl\\Math\\INT16_MIN' => 'Psl/Math/constants.php',
'Psl\\Math\\INT8_MAX' => 'Psl/Math/constants.php',
'Psl\\Math\\INT8_MIN' => 'Psl/Math/constants.php',
'Psl\\Math\\UINT64_MAX' => 'Psl/Math/constants.php',
'Psl\\Math\\UINT32_MAX' => 'Psl/Math/constants.php',
'Psl\\Math\\UINT16_MAX' => 'Psl/Math/constants.php',
'Psl\\Math\\UINT8_MAX' => 'Psl/Math/constants.php',
'Psl\\Math\\PI' => 'Psl/Math/constants.php',
'Psl\\Math\\E' => 'Psl/Math/constants.php',
'Psl\\Math\\INFINITY' => 'Psl/Math/constants.php',
Expand Down Expand Up @@ -481,6 +485,10 @@ final class Loader
'Psl\\Option\\some' => 'Psl/Option/some.php',
'Psl\\Option\\none' => 'Psl/Option/none.php',
'Psl\\Option\\from_nullable' => 'Psl/Option/from_nullable.php',
'Psl\\Range\\from' => 'Psl/Range/from.php',
'Psl\\Range\\to' => 'Psl/Range/to.php',
'Psl\\Range\\between' => 'Psl/Range/between.php',
'Psl\\Range\\full' => 'Psl/Range/full.php',
];

public const INTERFACES = [
Expand Down Expand Up @@ -567,6 +575,9 @@ final class Loader
'Psl\\Dict\\Exception\\ExceptionInterface' => 'Psl/Dict/Exception/ExceptionInterface.php',
'Psl\\PseudoRandom\\Exception\\ExceptionInterface' => 'Psl/PseudoRandom/Exception/ExceptionInterface.php',
'Psl\\Option\\Exception\\ExceptionInterface' => 'Psl/Option/Exception/ExceptionInterface.php',
'Psl\\Range\\RangeInterface' => 'Psl/Range/RangeInterface.php',
'Psl\\Range\\LowerBoundRangeInterface' => 'Psl/Range/LowerBoundRangeInterface.php',
'Psl\\Range\\UpperBoundRangeInterface' => 'Psl/Range/UpperBoundRangeInterface.php',
];

public const TRAITS = [
Expand Down Expand Up @@ -748,6 +759,10 @@ final class Loader
'Psl\\Async\\Exception\\InvalidArgumentException' => 'Psl/Async/Exception/InvalidArgumentException.php',
'Psl\\Option\\Exception\\NoneException' => 'Psl/Option/Exception/NoneException.php',
'Psl\\Option\\Option' => 'Psl/Option/Option.php',
'Psl\\Range\\FromRange' => 'Psl/Range/FromRange.php',
'Psl\\Range\\ToRange' => 'Psl/Range/ToRange.php',
'Psl\\Range\\BetweenRange' => 'Psl/Range/BetweenRange.php',
'Psl\\Range\\FullRange' => 'Psl/Range/FullRange.php',
];

public const ENUMS = [
Expand Down
4 changes: 2 additions & 2 deletions src/Psl/Iter/Iterator.php
Expand Up @@ -20,7 +20,7 @@
final class Iterator implements Countable, SeekableIterator
{
/**
* @var Generator<Tk, Tv, mixed, mixed>
* @var null|Generator<Tk, Tv, mixed, mixed>
*/
private ?Generator $generator;

Expand All @@ -42,7 +42,7 @@ final class Iterator implements Countable, SeekableIterator
/**
* The size of the generator.
*
* @var int<0, max>
* @var null|int<0, max>
*/
private ?int $count = null;

Expand Down
28 changes: 28 additions & 0 deletions src/Psl/Math/constants.php
Expand Up @@ -91,6 +91,27 @@
*/
const INT16_MIN = -32768;

/**
* The maximum integer value representable in a 8-bit binary-coded decimal.
*
* @var int
*/
const INT8_MAX = 128;

/**
* The minimum integer value representable in a 8-bit binary-coded decimal.
*
* @var int
*/
const INT8_MIN = -128;

/**
* The maximum unsigned integer value representable in a 64-bit binary-coded decimal.
*
* @var int
*/
const UINT64_MAX = 18446744073709551615;

/**
* The maximum unsigned integer value representable in a 32-bit binary-coded decimal.
*
Expand All @@ -104,3 +125,10 @@
* @var int
*/
const UINT16_MAX = 65535;

/**
* The maximum unsigned integer value representable in a 8-bit binary-coded decimal.
*
* @var int
*/
const UINT8_MAX = 255;
143 changes: 143 additions & 0 deletions src/Psl/Range/BetweenRange.php
@@ -0,0 +1,143 @@
<?php

declare(strict_types=1);

namespace Psl\Range;

use Generator;
use Psl\Iter;

/**
* A `BetweenRange` is a range that contains all values between the given lower and upper bound.
*
* This range can serve as an Iterator, starting from the lower bound, and ending at the upper bound.
*
* Example:
*
* ```php
* use Psl\Range;
*
* $range = new Range\BetweenRange(1, 10, inclusive: false);
*
* foreach ($range as $value) {
* // $value will be 1, 2, 3, 4, 5, 6, 7, 8, 9
* }
*
* $range = new Range\BetweenRange(1, 10, inclusive: true);
*
* foreach ($range as $value) {
* // $value will be 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
* }
* ```
*
* @template T of int|float
*
* @implements LowerBoundRangeInterface<T>
* @implements UpperBoundRangeInterface<T>
*
* @see RangeInterface::contains()
* @see LowerBoundRangeInterface::getLowerBound()
* @see UpperBoundRangeInterface::getUpperBound()
* @see UpperBoundRangeInterface::isUpperInclusive()
*
* @immutable
*/
final class BetweenRange implements LowerBoundRangeInterface, UpperBoundRangeInterface
{
/**
* @param T $lower_bound
* @param T $upper_bound
*
* @psalm-mutation-free
*/
public function __construct(
private readonly int|float $lower_bound,
private readonly int|float $upper_bound,
private readonly bool $upper_inclusive = false,
) {
}

/**
* {@inheritDoc}
*
* @param T $value
*
* @psalm-mutation-free
*/
public function contains(int|float $value): bool
{
if ($value < $this->lower_bound) {
return false;
}

if ($this->upper_inclusive) {
return $value <= $this->upper_bound;
}

return $value < $this->upper_bound;
}

/**
* {@inheritDoc}
*
* @return T
*
* @psalm-mutation-free
*/
public function getLowerBound(): int|float
{
return $this->lower_bound;
}

/**
* {@inheritDoc}
*
* @return T
*
* @psalm-mutation-free
*/
public function getUpperBound(): int|float
{
return $this->upper_bound;
}

/**
* {@inheritDoc}
*
* @psalm-mutation-free
*/
public function isUpperInclusive(): bool
{
return $this->upper_inclusive;
}

/**
* {@inheritDoc}
*
* @return Iter\Iterator<int, T>
*
* @psalm-mutation-free
*
* @psalm-suppress ImpureMethodCall
* @psalm-suppress InvalidReturnStatement
* @psalm-suppress InvalidReturnType
* @psalm-suppress InvalidOperand
* @psalm-suppress MixedOperand
* @psalm-suppress MixedAssignment
*/
public function getIterator(): Iter\Iterator
{
$lower = $this->lower_bound;
$upper = $this->upper_bound;
$inclusive = $this->upper_inclusive;

return Iter\Iterator::from(static function () use ($lower, $upper, $inclusive): Generator {
$to = $inclusive ? $upper : $upper - 1;

for ($i = $lower; $i <= $to; $i++) {
/** @var T $i */
yield $i;
}
});
}
}

0 comments on commit fac0f15

Please sign in to comment.