diff --git a/src/TimeBucket.php b/src/TimeBucket.php index dbed339..a5fadd1 100644 --- a/src/TimeBucket.php +++ b/src/TimeBucket.php @@ -110,9 +110,7 @@ public function count() : int */ public function sliceCount() : int { - $iter = $this->getIterator(); //Perform this action on a copy of the queue to ensure we don't modify it - $iter->setExtractFlags(SplPriorityQueue::EXTR_PRIORITY); - return $iter->isEmpty() ? 0 : count(array_unique(iterator_to_array($iter))); + return $this->innerQueue->priorityCount(); } /** @@ -167,6 +165,7 @@ public function insert($datum, $priority) */ public function getIterator() : TimeOrderedStorageInterface { + $this->innerQueue->beforeClone(); return clone $this->innerQueue; } @@ -416,6 +415,7 @@ public function unserialize($data) */ function __clone() { + $this->innerQueue->beforeClone(); $this->innerQueue = clone $this->innerQueue; } } diff --git a/src/TimeOrderedArray.php b/src/TimeOrderedArray.php index 57a80da..fa0aa44 100644 --- a/src/TimeOrderedArray.php +++ b/src/TimeOrderedArray.php @@ -54,7 +54,7 @@ class TimeOrderedArray implements TimeOrderedStorageInterface { * * @var ?int|string */ - protected $top = null; + protected string|int|null $top = null; /** * Total elements contained in the queue @@ -94,7 +94,7 @@ public function compare($priority1, $priority2) : int * @param mixed $value Element to insert * @param string|int $priority Priority can be any key acceptable to a PHP array (so int|string) */ - public function insert($value, $priority) + public function insert($value, $priority) : void { if (!array_key_exists($priority, $this->priorities)) { @@ -102,7 +102,7 @@ public function insert($value, $priority) $newIndex = array_key_last($this->values); $this->priorities[$priority] = $newIndex; $this->prioritiesUnsorted = true; - if (null === $this->top || 1 == $this->compare($priority, $this->top)) { + if (null === $this->top || 1 === $this->compare($priority, $this->top)) { $this->top = $priority; } } @@ -115,7 +115,7 @@ public function insert($value, $priority) * * @return mixed */ - public function extract() + public function extract() : mixed { if (!$this->valid()) { return false; @@ -130,12 +130,12 @@ public function extract() * * @return mixed */ - public function top() + public function top() : mixed { if ($this->isEmpty()) { return false; } - return$this->current(); + return $this->current(); } /** @@ -235,7 +235,7 @@ public function isEmpty() : bool * Set the extraction flag for the queue. Priority / Data / Both * @param int $flag */ - public function setExtractFlags(int $flag) + public function setExtractFlags(int $flag): void { $this->mode = $flag; } @@ -248,4 +248,16 @@ public function getExtractFlags() : int { return $this->mode; } + + public function beforeClone() : void { + if ($this->prioritiesUnsorted) { + uksort($this->priorities, array($this, 'compare')); + $this->prioritiesUnsorted = false; + } + } + + public function priorityCount(): int + { + return count($this->priorities); + } } \ No newline at end of file diff --git a/src/TimeOrderedQueue.php b/src/TimeOrderedQueue.php index f841900..b4e7927 100644 --- a/src/TimeOrderedQueue.php +++ b/src/TimeOrderedQueue.php @@ -12,6 +12,9 @@ namespace EdgeTelemetrics\TimeBucket; use SplPriorityQueue; +use function array_unique; +use function count; +use function iterator_to_array; class TimeOrderedQueue extends SplPriorityQueue implements TimeOrderedStorageInterface { /** @@ -19,7 +22,7 @@ class TimeOrderedQueue extends SplPriorityQueue implements TimeOrderedStorageInt */ protected int $serial = PHP_INT_MIN; - public function insert($value, $priority) + public function insert($value, $priority) : void { if (! is_array($priority)) { $priority = [$priority, $this->serial++]; @@ -55,15 +58,29 @@ public function current() : mixed return $this->fixPriority($extract); } - public function extract() + public function extract() : mixed { $extract = parent::extract(); return $this->fixPriority($extract); } - public function top() + public function top() : mixed { $extract = parent::top(); return $this->fixPriority($extract); } + + public function beforeClone() : void { + //NOOP + } + + public function priorityCount(): int + { + if ($this->isEmpty()) { + return 0; + } + $iter = clone $this; + $iter->setExtractFlags(SplPriorityQueue::EXTR_PRIORITY); + return count(array_unique(iterator_to_array($iter))); + } } \ No newline at end of file diff --git a/src/TimeOrderedStorageInterface.php b/src/TimeOrderedStorageInterface.php index 273fce2..4e05f25 100644 --- a/src/TimeOrderedStorageInterface.php +++ b/src/TimeOrderedStorageInterface.php @@ -19,14 +19,20 @@ * @package EdgeTelemetrics\TimeBucket */ interface TimeOrderedStorageInterface extends Iterator, Countable { - public function insert($value, $priority); - /** - * @return int - */ - public function count() : int; + public function insert($value, $priority) : void; + public function current() : mixed; public function compare($priority1, $priority2) : int; - public function extract(); - public function top(); - public function isEmpty() : bool; + public function extract() : mixed; + public function top() : mixed; + + /** + * @return bool + */ + public function isEmpty(); + + public function priorityCount() : int; + + /** Perform any tasks on parent object prior to clone being called */ + public function beforeClone() : void; } \ No newline at end of file diff --git a/tests/timeBucketOrderTest.php b/tests/timeBucketOrderTest.php index 1fcca56..5797ae1 100644 --- a/tests/timeBucketOrderTest.php +++ b/tests/timeBucketOrderTest.php @@ -78,9 +78,14 @@ public function __construct($array) echo '**** Validate getTimeSlices()' . PHP_EOL; $totalDatapoints = 0; +echo $prevTime = null; foreach($bucket->getTimeSlices() as ['time' => $time, 'data' => $data]) { $totalDatapoints += count($data); + if ($prevTime !== null && $time < $prevTime) { + echo '***ERROR*** Time out of order. ' . PHP_EOL; + } + $prevTime = $time; // echo 'Slice ' . $time . " contains " . count($data) . " datapoints" . PHP_EOL; } echo 'Bucket contains ' . $totalDatapoints . " datapoints." . PHP_EOL;