From 5e1035a7969e9b900da63a772f0d10d490ea888e Mon Sep 17 00:00:00 2001 From: Jan Langer Date: Mon, 10 Jun 2024 16:56:03 +0200 Subject: [PATCH] Added generics to IntervalData classes --- src/Time/IntervalData/DateIntervalData.php | 56 +++++++----- src/Time/IntervalData/DateIntervalDataSet.php | 84 ++++++++++++------ src/Time/IntervalData/NightIntervalData.php | 56 +++++++----- .../IntervalData/NightIntervalDataSet.php | 86 +++++++++++++------ src/common/lists/Arr.php | 12 ++- 5 files changed, 197 insertions(+), 97 deletions(-) diff --git a/src/Time/IntervalData/DateIntervalData.php b/src/Time/IntervalData/DateIntervalData.php index c922d701..9d8993b3 100644 --- a/src/Time/IntervalData/DateIntervalData.php +++ b/src/Time/IntervalData/DateIntervalData.php @@ -32,6 +32,7 @@ /** * Interval of dates with data bound to it. + * @template TData */ class DateIntervalData implements Equalable, Comparable, IntersectComparable, Pokeable { @@ -50,7 +51,7 @@ class DateIntervalData implements Equalable, Comparable, IntersectComparable, Po private $data; /** - * @param mixed|null $data + * @param TData $data */ final public function __construct(Date $start, Date $end, $data) { @@ -64,14 +65,17 @@ final public function __construct(Date $start, Date $end, $data) } /** - * @param mixed|null $data - * @return self + * @param TData $data + * @return self */ public static function createFromDateInterval(DateInterval $interval, $data): self { return new static($interval->getStart(), $interval->getEnd(), $data); } + /** + * @return self + */ public static function empty(): self { $interval = new static(new Date(), new Date(), null); @@ -82,8 +86,8 @@ public static function empty(): self } /** - * @param mixed|null $data - * @return self + * @param TData $data + * @return self */ public static function all($data): self { @@ -124,11 +128,17 @@ public function shift(string $value): self return new static($this->start->modify($value), $this->end->modify($value), $this->data); } + /** + * @return static + */ public function setStart(Date $start): self { return new static($start, $this->end, $this->data); } + /** + * @return static + */ public function setEnd(Date $end): self { return new static($this->start, $end, $this->data); @@ -162,7 +172,7 @@ public function toDateInterval(): DateInterval } /** - * @return Date[]|mixed[] array of pairs (Date $date, mixed $data) + * @return list */ public function toDateDataArray(): array { @@ -191,7 +201,7 @@ public function getEnd(): Date } /** - * @return Date[] + * @return array{0: Date, 1: Date} */ public function getStartEnd(): array { @@ -199,7 +209,7 @@ public function getStartEnd(): array } /** - * @return mixed|null + * @return TData */ public function getData() { @@ -212,7 +222,7 @@ public function isEmpty(): bool } /** - * @param self $other + * @param self $other * @return bool */ public function equals(Equalable $other): bool @@ -223,7 +233,7 @@ public function equals(Equalable $other): bool } /** - * @param mixed|null $otherData + * @param TData $otherData * @return bool */ public function dataEquals($otherData): bool @@ -236,7 +246,7 @@ public function dataEquals($otherData): bool } /** - * @param self $other + * @param self $other * @return int */ public function compare(Comparable $other): int @@ -248,7 +258,7 @@ public function compare(Comparable $other): int } /** - * @param self $other + * @param self $other * @return int */ public function compareIntersects(IntersectComparable $other): int @@ -277,7 +287,7 @@ public function containsValue($date): bool } /** - * @param DateInterval|DateIntervalData $interval + * @param DateInterval|DateIntervalData $interval * @return bool */ public function contains($interval): bool @@ -290,7 +300,7 @@ public function contains($interval): bool } /** - * @param DateInterval|DateIntervalData $interval + * @param DateInterval|DateIntervalData $interval * @return bool */ public function intersects($interval): bool @@ -299,7 +309,7 @@ public function intersects($interval): bool } /** - * @param DateInterval|DateIntervalData $interval + * @param DateInterval|DateIntervalData $interval * @return bool */ public function touches($interval): bool @@ -309,10 +319,13 @@ public function touches($interval): bool // actions --------------------------------------------------------------------------------------------------------- + /** + * @return self + */ public function intersect(DateInterval ...$items): self { $items[] = $this->toDateInterval(); - /** @var self[] $items */ + /** @var array $items */ $items = Arr::sortComparable($items); /** @var DateInterval $result */ @@ -328,6 +341,9 @@ public function intersect(DateInterval ...$items): self return new static($result->getStart(), $result->getEnd(), $this->data); } + /** + * @return DateIntervalDataSet + */ public function subtract(DateInterval ...$items): DateIntervalDataSet { $intervals = [$this]; @@ -355,8 +371,8 @@ public function subtract(DateInterval ...$items): DateIntervalDataSet // static ---------------------------------------------------------------------------------------------------------- /** - * @param self[] $intervals - * @return self[] + * @param list $intervals + * @return list * @deprecated will be removed. use Arr::sortComparable() instead. */ public static function sort(array $intervals): array @@ -365,8 +381,8 @@ public static function sort(array $intervals): array } /** - * @param self[] $intervals - * @return self[] + * @param list $intervals + * @return list * @deprecated will be removed. use Arr::sortComparable() instead. */ public static function sortByStart(array $intervals): array diff --git a/src/Time/IntervalData/DateIntervalDataSet.php b/src/Time/IntervalData/DateIntervalDataSet.php index 55ace58b..f449e671 100644 --- a/src/Time/IntervalData/DateIntervalDataSet.php +++ b/src/Time/IntervalData/DateIntervalDataSet.php @@ -36,16 +36,17 @@ /** * @implements IteratorAggregate + * @template TData */ class DateIntervalDataSet implements Equalable, Pokeable, IteratorAggregate { use StrictBehaviorMixin; - /** @var DateIntervalData[] */ + /** @var list> */ private $intervals; /** - * @param DateIntervalData[] $intervals + * @param list> $intervals */ final public function __construct(array $intervals) { @@ -55,8 +56,8 @@ final public function __construct(array $intervals) } /** - * @param mixed|null $data - * @return DateIntervalDataSet + * @param TData $data + * @return DateIntervalDataSet */ public static function createFromDateIntervalSet(DateIntervalSet $set, $data): self { @@ -105,7 +106,7 @@ public function dump(): string public function toDateIntervalSet(): DateIntervalSet { $intervals = []; - /** @var DateIntervalData $interval */ + /** @var DateIntervalData $interval */ foreach ($this->intervals as $interval) { $intervals[] = $interval->toDateInterval(); } @@ -114,7 +115,7 @@ public function toDateIntervalSet(): DateIntervalSet } /** - * @return Date[][]|mixed[][] array of pairs: (Date $date, Equalable $data) + * @return list */ public function toDateDataArray(): array { @@ -126,7 +127,7 @@ public function toDateDataArray(): array } /** - * @return DateIntervalData[] + * @return list> */ public function getIntervals(): array { @@ -134,7 +135,7 @@ public function getIntervals(): array } /** - * @return Traversable + * @return Traversable> */ public function getIterator(): Traversable { @@ -147,7 +148,7 @@ public function isEmpty(): bool } /** - * @param self $other + * @param self $other * @return bool */ public function equals(Equalable $other): bool @@ -180,11 +181,11 @@ public function containsValue(Date $value): bool /** * Join overlapping intervals in set, if they have the same data. - * @return self + * @return self */ public function normalize(): self { - /** @var DateIntervalData[] $intervals */ + /** @var DateIntervalData[] $intervals */ $intervals = Arr::sortComparableValues($this->intervals); $count = count($intervals) - 1; for ($n = 0; $n < $count; $n++) { @@ -205,32 +206,43 @@ public function normalize(): self /** * Add another set of intervals to this one without normalization. - * @return self + * @param self $set + * @return self */ public function add(self $set): self { return $this->addIntervals(...$set->intervals); } + /** + * @param DateIntervalData ...$intervals + * @return self + */ public function addIntervals(DateIntervalData ...$intervals): self { - return new static(array_merge($this->intervals, $intervals)); + /** @var list> $merge */ + $merge = array_merge($this->intervals, $intervals); + + return new static($merge); } /** * Remove another set of intervals from this one. - * @return self + * @return self */ public function subtract(DateIntervalSet $set): self { return $this->subtractIntervals(...$set->getIntervals()); } + /** + * @return self + */ public function subtractIntervals(DateInterval ...$intervals): self { $sources = $this->intervals; $results = []; - /** @var DateIntervalData $result */ + /** @var DateIntervalData $result */ while ($result = array_shift($sources)) { foreach ($intervals as $interval) { $result = $result->subtract($interval); @@ -246,7 +258,7 @@ public function subtractIntervals(DateInterval ...$intervals): self } } - /** @var DateIntervalData[] $results */ + /** @var DateIntervalData[] $results */ $results = $results; return new static($results); @@ -254,13 +266,16 @@ public function subtractIntervals(DateInterval ...$intervals): self /** * Intersect with another set of intervals. - * @return self + * @return self */ public function intersect(DateIntervalSet $set): self { return $this->intersectIntervals(...$set->getIntervals()); } + /** + * @return self + */ public function intersectIntervals(DateInterval ...$intervals): self { $results = []; @@ -275,6 +290,11 @@ public function intersectIntervals(DateInterval ...$intervals): self return new static($results); } + /** + * @template TNewData + * @param callable(DateIntervalData $data): (self|DateIntervalData|array>) $mapper + * @return self + */ public function map(callable $mapper): self { $results = []; @@ -294,6 +314,11 @@ public function map(callable $mapper): self return new static($results); } + /** + * @template TNewData + * @param callable(DateIntervalData $data): (self|DateIntervalData|array>|null) $mapper + * @return self + */ public function collect(callable $mapper): self { $results = []; @@ -318,8 +343,9 @@ public function collect(callable $mapper): self /** * Maps data with mapper and collects intervals with non-null results. * - * @param callable $mapper (mixed $data): mixed|null $data - * @return self + * @template TOtherData + * @param callable(TData $data):(TOtherData|null) $mapper + * @return self */ public function collectData(callable $mapper): self { @@ -339,8 +365,10 @@ public function collectData(callable $mapper): self * Only modifies and splits intersecting intervals. Does not insert new ones nor remove things. * Complexity O(m*n). For bigger sets use modifyDataByStream() * - * @param callable $reducer (mixed $oldData, mixed $input): mixed $newData - * @return self + * @template TOther + * @param self $other + * @param callable(TData, TOther): TData $reducer + * @return self */ public function modifyData(self $other, callable $reducer): self { @@ -383,10 +411,11 @@ public function modifyData(self $other, callable $reducer): self * Both $this and inputs must be ordered to work properly, $this must be normalized. * Complexity ~O(m+n), worst case O(m*n) if all inputs cover whole interval set. * - * @param iterable|mixed[] $inputs - * @param callable $mapper (mixed $input): array{0: Date $start, 1: Date $end} - * @param callable $reducer (mixed $oldData, mixed $input): mixed $newData - * @return self + * @template TInput + * @param iterable $inputs + * @param callable(TInput): array{0: Date, 1: Date} $mapper + * @param callable(TData, TInput): TData $reducer + * @return self */ public function modifyDataByStream(iterable $inputs, callable $mapper, callable $reducer): self { @@ -479,8 +508,9 @@ public function modifyDataByStream(iterable $inputs, callable $mapper, callable * Split interval set to more interval sets with different subsets of original data. * Splitter maps original data to a group of data. Should return array with keys indicating the data set group. * - * @param callable $splitter (mixed $data): array - * @return self[] + * @template TOther + * @param callable(TData): array $splitter + * @return list> */ public function splitData(callable $splitter): array { diff --git a/src/Time/IntervalData/NightIntervalData.php b/src/Time/IntervalData/NightIntervalData.php index 2056ed0b..f982e35f 100644 --- a/src/Time/IntervalData/NightIntervalData.php +++ b/src/Time/IntervalData/NightIntervalData.php @@ -32,6 +32,7 @@ /** * Interval of nights with data bound to it. + * @template TData */ class NightIntervalData implements Equalable, Comparable, IntersectComparable, Pokeable { @@ -50,7 +51,7 @@ class NightIntervalData implements Equalable, Comparable, IntersectComparable, P private $data; /** - * @param mixed|null $data + * @param TData $data */ final public function __construct(Date $start, Date $end, $data) { @@ -64,14 +65,17 @@ final public function __construct(Date $start, Date $end, $data) } /** - * @param mixed|null $data - * @return self + * @param TData $data + * @return self */ public static function createFromNightInterval(NightInterval $interval, $data): self { return new static($interval->getStart(), $interval->getEnd(), $data); } + /** + * @return self + */ public static function empty(): self { $interval = new static(new Date(), new Date(), null); @@ -82,8 +86,8 @@ public static function empty(): self } /** - * @param mixed|null $data - * @return self + * @param TData $data + * @return self */ public static function all($data): self { @@ -124,11 +128,17 @@ public function shift(string $value): self return new static($this->start->modify($value), $this->end->modify($value), $this->data); } + /** + * @return static + */ public function setStart(Date $start): self { return new static($start, $this->end, $this->data); } + /** + * @return static + */ public function setEnd(Date $end): self { return new static($this->start, $end, $this->data); @@ -162,7 +172,7 @@ public function toNightInterval(): NightInterval } /** - * @return Date[]|mixed[] array of pairs (Date $date, mixed $data) + * @return list */ public function toDateDataArray(): array { @@ -191,7 +201,7 @@ public function getEnd(): Date } /** - * @return Date[] + * @return array{0: Date, 1: Date} */ public function getStartEnd(): array { @@ -199,7 +209,7 @@ public function getStartEnd(): array } /** - * @return mixed|null + * @return TData */ public function getData() { @@ -212,7 +222,7 @@ public function isEmpty(): bool } /** - * @param self $other + * @param self $other * @return bool */ public function equals(Equalable $other): bool @@ -223,7 +233,7 @@ public function equals(Equalable $other): bool } /** - * @param mixed|null $otherData + * @param TData $otherData * @return bool */ public function dataEquals($otherData): bool @@ -236,7 +246,7 @@ public function dataEquals($otherData): bool } /** - * @param self $other + * @param self $other * @return int */ public function compare(Comparable $other): int @@ -248,7 +258,7 @@ public function compare(Comparable $other): int } /** - * @param self $other + * @param self $other * @return int */ public function compareIntersects(IntersectComparable $other): int @@ -277,7 +287,7 @@ public function containsValue($date): bool } /** - * @param NightInterval|NightIntervalData $interval + * @param NightInterval|NightIntervalData $interval * @return bool */ public function contains($interval): bool @@ -290,7 +300,7 @@ public function contains($interval): bool } /** - * @param NightInterval|NightIntervalData $interval + * @param NightInterval|NightIntervalData $interval * @return bool */ public function intersects($interval): bool @@ -299,7 +309,7 @@ public function intersects($interval): bool } /** - * @param NightInterval|NightIntervalData $interval + * @param NightInterval|NightIntervalData $interval * @return bool */ public function touches($interval): bool @@ -309,10 +319,13 @@ public function touches($interval): bool // actions --------------------------------------------------------------------------------------------------------- + /** + * @return self + */ public function intersect(NightInterval ...$items): self { $items[] = $this->toNightInterval(); - /** @var self[] $items */ + /** @var self[] $items */ $items = Arr::sortComparable($items); /** @var NightInterval $result */ @@ -328,6 +341,9 @@ public function intersect(NightInterval ...$items): self return new static($result->getStart(), $result->getEnd(), $this->data); } + /** + * @return NightIntervalDataSet + */ public function subtract(NightInterval ...$items): NightIntervalDataSet { $intervals = [$this]; @@ -355,8 +371,8 @@ public function subtract(NightInterval ...$items): NightIntervalDataSet // static ---------------------------------------------------------------------------------------------------------- /** - * @param self[] $intervals - * @return self[] + * @param list $intervals + * @return list * @deprecated will be removed. use Arr::sortComparable() instead. */ public static function sort(array $intervals): array @@ -365,8 +381,8 @@ public static function sort(array $intervals): array } /** - * @param self[] $intervals - * @return self[] + * @param list $intervals + * @return list * @deprecated will be removed. use Arr::sortComparable() instead. */ public static function sortByStart(array $intervals): array diff --git a/src/Time/IntervalData/NightIntervalDataSet.php b/src/Time/IntervalData/NightIntervalDataSet.php index 1f6452a2..ddcecf7d 100644 --- a/src/Time/IntervalData/NightIntervalDataSet.php +++ b/src/Time/IntervalData/NightIntervalDataSet.php @@ -36,16 +36,17 @@ /** * @implements IteratorAggregate + * @template TData */ class NightIntervalDataSet implements Equalable, Pokeable, IteratorAggregate { use StrictBehaviorMixin; - /** @var NightIntervalData[] */ + /** @var list> */ private $intervals; /** - * @param NightIntervalData[] $intervals + * @param list> $intervals */ final public function __construct(array $intervals) { @@ -55,8 +56,8 @@ final public function __construct(array $intervals) } /** - * @param mixed|null $data - * @return NightIntervalDataSet + * @param TData $data + * @return NightIntervalDataSet */ public static function createFromNightIntervalSet(NightIntervalSet $set, $data): self { @@ -105,7 +106,7 @@ public function dump(): string public function toNightIntervalSet(): NightIntervalSet { $intervals = []; - /** @var NightIntervalData $interval */ + /** @var NightIntervalData $interval */ foreach ($this->intervals as $interval) { $intervals[] = $interval->toNightInterval(); } @@ -114,7 +115,7 @@ public function toNightIntervalSet(): NightIntervalSet } /** - * @return Date[][]|mixed[][] array of pairs: (Date $date, Equalable $data) + * @return list */ public function toDateDataArray(): array { @@ -126,7 +127,7 @@ public function toDateDataArray(): array } /** - * @return NightIntervalData[] + * @return list> */ public function getIntervals(): array { @@ -134,7 +135,7 @@ public function getIntervals(): array } /** - * @return Traversable + * @return Traversable> */ public function getIterator(): Traversable { @@ -147,7 +148,7 @@ public function isEmpty(): bool } /** - * @param self $other + * @param self $other * @return bool */ public function equals(Equalable $other): bool @@ -180,11 +181,11 @@ public function containsValue(Date $value): bool /** * Join overlapping intervals in set, if they have the same data. - * @return self + * @return self */ public function normalize(): self { - /** @var NightIntervalData[] $intervals */ + /** @var list> $intervals */ $intervals = Arr::sortComparableValues($this->intervals); $count = count($intervals) - 1; for ($n = 0; $n < $count; $n++) { @@ -205,32 +206,43 @@ public function normalize(): self /** * Add another set of intervals to this one without normalization. - * @return self + * @param self $set + * @return self */ public function add(self $set): self { return $this->addIntervals(...$set->intervals); } + /** + * @param NightIntervalData ...$intervals + * @return static + */ public function addIntervals(NightIntervalData ...$intervals): self { - return new static(array_merge($this->intervals, $intervals)); + /** @var list> $merge */ + $merge = array_merge($this->intervals, $intervals); + + return new static($merge); } /** * Remove another set of intervals from this one. - * @return self + * @return self */ public function subtract(NightIntervalSet $set): self { return $this->subtractIntervals(...$set->getIntervals()); } + /** + * @return static + */ public function subtractIntervals(NightInterval ...$intervals): self { $sources = $this->intervals; $results = []; - /** @var NightIntervalData $result */ + /** @var NightIntervalData $result */ while ($result = array_shift($sources)) { foreach ($intervals as $interval) { $result = $result->subtract($interval); @@ -246,7 +258,7 @@ public function subtractIntervals(NightInterval ...$intervals): self } } - /** @var NightIntervalData[] $results */ + /** @var NightIntervalData[] $results */ $results = $results; return new static($results); @@ -254,13 +266,16 @@ public function subtractIntervals(NightInterval ...$intervals): self /** * Intersect with another set of intervals. - * @return self + * @return self */ public function intersect(NightIntervalSet $set): self { return $this->intersectIntervals(...$set->getIntervals()); } + /** + * @return static + */ public function intersectIntervals(NightInterval ...$intervals): self { $results = []; @@ -275,6 +290,11 @@ public function intersectIntervals(NightInterval ...$intervals): self return new static($results); } + /** + * @template TNewData + * @param callable(NightIntervalData $data): (self|NightIntervalData|array>) $mapper + * @return self + */ public function map(callable $mapper): self { $results = []; @@ -294,6 +314,11 @@ public function map(callable $mapper): self return new static($results); } + /** + * @template TNewData + * @param callable(NightIntervalData $data): (self|NightIntervalData|array>|null) $mapper + * @return self + */ public function collect(callable $mapper): self { $results = []; @@ -315,6 +340,11 @@ public function collect(callable $mapper): self return new static($results); } + /** + * @template TOtherData + * @param callable(TData $data):(TOtherData|null) $mapper + * @return self + */ public function collectData(callable $mapper): self { $results = []; @@ -333,8 +363,10 @@ public function collectData(callable $mapper): self * Only modifies and splits intersecting intervals. Does not insert new ones nor remove things. * Complexity O(m*n). For bigger sets use modifyDataByStream() * - * @param callable $reducer (mixed $oldData, mixed $input): mixed $newData - * @return self + * @template TOther + * @param self $other + * @param callable(TData, TOther): TData $reducer + * @return self */ public function modifyData(self $other, callable $reducer): self { @@ -377,10 +409,11 @@ public function modifyData(self $other, callable $reducer): self * Both $this and inputs must be ordered to work properly, $this must be normalized. * Complexity ~O(m+n), worst case O(m*n) if all inputs cover whole interval set. * - * @param iterable|mixed[] $inputs - * @param callable $mapper (mixed $input): array{0: Date $start, 1: Date $end} - * @param callable $reducer (mixed $oldData, mixed $input): mixed $newData - * @return self + * @template TInput + * @param iterable $inputs + * @param callable(TInput): array{0: Date, 1: Date} $mapper + * @param callable(TData, TInput): TData $reducer + * @return self */ public function modifyDataByStream(iterable $inputs, callable $mapper, callable $reducer): self { @@ -466,13 +499,14 @@ public function modifyDataByStream(iterable $inputs, callable $mapper, callable } } - return new NightIntervalDataSet($results); + return new static($results); } /** * Split interval set to more interval sets with different subsets of original data. - * @param callable $splitter Maps original data set to a group of data sets. Should return array with keys indicating the data set group. - * @return self[] $this + * @template TOther + * @param callable(TData): array $splitter + * @return list> */ public function splitData(callable $splitter): array { diff --git a/src/common/lists/Arr.php b/src/common/lists/Arr.php index 667e3b9c..bcff95ef 100644 --- a/src/common/lists/Arr.php +++ b/src/common/lists/Arr.php @@ -1101,8 +1101,10 @@ public static function flatMap(array $array, callable $function): array } /** - * @param mixed[] $array - * @return mixed[] + * @param array|array> $array + * @return list + * + * @template T */ public static function flatten(array $array): array { @@ -1314,8 +1316,10 @@ public static function sortKeysWith(array $array, callable $function, int $flags } /** - * @param Comparable[] $array - * @return mixed[] + * @param array $array + * @return list + * + * @template T of Comparable */ public static function sortComparable(array $array, int $flags = Sorting::REGULAR): array {