Variation.php 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. <?php
  2. namespace App\Yr\Forecast\Tabular\Variation;
  3. use App\Yr\Forecast\Tabular\Time;
  4. use App\Yr\Forecast\Tabular\Time\DiffInterface;
  5. if (!function_exists('array_key_last')) {
  6. function array_key_last(array $args): ?int {
  7. $keys = array_keys($args);
  8. return array_pop($keys);
  9. }
  10. }
  11. class VariationFn {
  12. private $fn, $v;
  13. public function __construct(callable $fn, Variation $v) {
  14. $this->fn = $fn;
  15. $this->v = $v;
  16. }
  17. public function callable(DiffInterface $e): ?bool {
  18. $callable = $this->fn;
  19. return $callable(
  20. $e,
  21. $this->v->getIntersect($e),
  22. $this->v->getIntersected($e)
  23. );
  24. }
  25. }
  26. class Variation implements \IteratorAggregate {
  27. private $time;
  28. private $entities = [];
  29. private $intersected = [];
  30. private $intersects = [];
  31. public function __construct(Time $t) {
  32. $this->time = $t;
  33. }
  34. public function addEntity(DiffInterface $entity, ?Variation $intersects): self {
  35. $this->entities[] = $entity;
  36. if ($intersects != null) {
  37. $this->intersects[array_key_last($this->entities)] = $intersects;
  38. $intersects->addIntersected($entity, $this);
  39. }
  40. return $this;
  41. }
  42. public function getTime(): Time {
  43. return $this->time;
  44. }
  45. private function getEntityKey(DiffInterface $entity): ?int {
  46. $key = (function() use ($entity) : ?int {
  47. foreach ($this->entities as $key => $ent)
  48. if ($ent instanceof $entity)
  49. return $key;
  50. return null;
  51. })();
  52. return $key;
  53. }
  54. public function getIntersect(DiffInterface $entity): ?Variation {
  55. $key = $this->getEntityKey($entity);
  56. if ($key === null || !isset($this->intersects[$key]))
  57. return null;
  58. return $this->intersects[$key];
  59. }
  60. public function getIntersected(DiffInterface $entity): ?Variation {
  61. $key = $this->getEntityKey($entity);
  62. if ($key === null || !isset($this->intersected[$key]))
  63. return null;
  64. foreach ($this->intersected[$key] as $var)
  65. if ($var->getEntity(get_class($entity)) != null)
  66. return $var;
  67. }
  68. protected function addIntersected(DiffInterface $entity, Variation $var): self {
  69. $key = $this->getEntityKey($entity);
  70. if ($key === null)
  71. return $this;
  72. if (!isset($this->intersected[$key]))
  73. $this->intersected[$key] = [$var];
  74. else
  75. $this->intersected[$key][] = $var;
  76. return $this;
  77. }
  78. public function isEmpty(): bool {
  79. return empty($this->entities);
  80. }
  81. public function filter(callable $filterFn): ?Variation {
  82. $entities = array_filter($this->entities, [
  83. new VariationFn($filterFn, $this), 'callable',
  84. ]);
  85. if (count($entities) == 0)
  86. return null;
  87. $var = new Variation($this->time);
  88. foreach ($entities as $entity)
  89. $var->addEntity($entity, $this->getIntersect($entity));
  90. return $var;
  91. }
  92. public function operate(callable $opFn): void {
  93. array_walk($this->entities, [
  94. new VariationFn($opFn, $this), 'callable'
  95. ]);
  96. }
  97. public function numEntities(): int {
  98. return sizeof($this->entities);
  99. }
  100. public function getEntity(string $class): ?DiffInterface {
  101. foreach ($this as $entity)
  102. if ($entity instanceof $class)
  103. return $entity;
  104. return null;
  105. }
  106. public function getIterator(): ?\Generator {
  107. foreach ($this->entities as $entity)
  108. yield $entity;
  109. return null;
  110. }
  111. }