}> $units In output order. * @param int $allowanceBytes Bytes the lines (one newline each) may occupy. * @return array The admitted lines, plus the omission notice when any unit was left out. */ public static function fit(array $units, int $allowanceBytes): array { $remaining = $allowanceBytes - self::OMISSION_NOTICE_RESERVE_BYTES; $admitted = array(); foreach (self::admissionOrder($units) as $position) { $unit = $units[$position]; $bytes = self::bytesOf($unit['lines']); if ($bytes <= $remaining) { $admitted[$position] = true; $remaining -= $bytes; } } $lines = array(); $omittedRecords = 0; $omittedBytes = 0; foreach ($units as $position => $unit) { if (isset($admitted[$position])) { foreach ($unit['lines'] as $line) { $lines[] = $line; } continue; } $omittedRecords += count($unit['lines']); $omittedBytes += self::bytesOf($unit['lines']); } if ($omittedRecords > 0) { $lines[] = sprintf( 'Required checkpoint evidence trimmed: %d lower-priority record%s (%d bytes) omitted' . ' to keep room for the failing-request ranking.', $omittedRecords, $omittedRecords === 1 ? '' : 's', $omittedBytes ); } return $lines; } /** * Positions in the order units compete for room: tier ascending, then the * later position (the newer evidence) first. * * @param array}> $units * @return array */ private static function admissionOrder(array $units): array { $positions = array_keys($units); usort($positions, static function (int $a, int $b) use ($units): int { return ($units[$a]['tier'] <=> $units[$b]['tier']) ?: ($b <=> $a); }); return $positions; } /** @param array $lines */ private static function bytesOf(array $lines): int { $bytes = 0; foreach ($lines as $line) { $bytes += strlen($line) + 1; } return $bytes; } }