aggregation = $aggregation; $this->timestamp = $startTimestamp; $this->delta = new DeltaStorage($aggregation); } public function temporality() { return Temporality::DELTA; } public function timestamp(): int { return $this->timestamp; } public function push(Metric $metric): void { [$this->timestamp, $metric->timestamp] = [$metric->timestamp, $this->timestamp]; $this->delta->add($metric, $this->readers); } public function register($temporality): int { $reader = 0; for ($r = $this->readers; ($r & 1) != 0; $r >>= 1, $reader++) { } if ($reader === (PHP_INT_SIZE << 3) - 1 && is_int($this->readers)) { if (!extension_loaded('gmp')) { trigger_error(sprintf('GMP extension required to register over %d readers', (PHP_INT_SIZE << 3) - 1), E_USER_WARNING); $reader = PHP_INT_SIZE << 3; } else { assert(is_int($this->cumulative)); $this->readers = gmp_init($this->readers); $this->cumulative = gmp_init($this->cumulative); } } $readerMask = ($this->readers & 1 | 1) << $reader; $this->readers ^= $readerMask; if ($temporality === Temporality::CUMULATIVE) { $this->cumulative ^= $readerMask; } return $reader; } public function unregister(int $reader): void { $readerMask = ($this->readers & 1 | 1) << $reader; if (($this->readers & $readerMask) == 0) { return; } $this->delta->collect($reader); $this->readers ^= $readerMask; if (($this->cumulative & $readerMask) != 0) { $this->cumulative ^= $readerMask; } } public function collect(int $reader): DataInterface { $cumulative = ($this->cumulative >> $reader & 1) != 0; $metric = $this->delta->collect($reader, $cumulative) ?? new Metric([], [], $this->timestamp); $temporality = $cumulative ? Temporality::CUMULATIVE : Temporality::DELTA; return $this->aggregation->toData( $metric->attributes, $metric->summaries, Exemplar::groupByIndex($metric->exemplars), $metric->timestamp, $this->timestamp, $temporality, ); } }