mirror of
https://github.com/PHPOffice/PhpSpreadsheet.git
synced 2026-08-31 04:28:51 +00:00
Merge pull request #4609 from Fuzuki785/fix/4607
Performance improvement when working with large amounts of cells
This commit is contained in:
@@ -43,6 +43,25 @@ class Cells
|
||||
*/
|
||||
private array $index = [];
|
||||
|
||||
/**
|
||||
* Flag to avoid sorting the index every time.
|
||||
*/
|
||||
private bool $indexSorted = false;
|
||||
|
||||
/**
|
||||
* Index keys cache to avoid recalculating on large arrays.
|
||||
*
|
||||
* @var null|string[]
|
||||
*/
|
||||
private ?array $indexKeysCache = null;
|
||||
|
||||
/**
|
||||
* Index values cache to avoid recalculating on large arrays.
|
||||
*
|
||||
* @var null|int[]
|
||||
*/
|
||||
private ?array $indexValuesCache = null;
|
||||
|
||||
/**
|
||||
* Prefix used to uniquely identify cache data for this worksheet.
|
||||
*/
|
||||
@@ -112,6 +131,10 @@ class Cells
|
||||
|
||||
unset($this->index[$cellCoordinate]);
|
||||
|
||||
// Clear index caches
|
||||
$this->indexKeysCache = null;
|
||||
$this->indexValuesCache = null;
|
||||
|
||||
// Delete the entry from cache
|
||||
$this->cache->delete($this->cachePrefix . $cellCoordinate);
|
||||
}
|
||||
@@ -123,7 +146,12 @@ class Cells
|
||||
*/
|
||||
public function getCoordinates(): array
|
||||
{
|
||||
return array_keys($this->index);
|
||||
// Build or rebuild index keys cache
|
||||
if ($this->indexKeysCache === null) {
|
||||
$this->indexKeysCache = array_keys($this->index);
|
||||
}
|
||||
|
||||
return $this->indexKeysCache;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,9 +161,21 @@ class Cells
|
||||
*/
|
||||
public function getSortedCoordinates(): array
|
||||
{
|
||||
asort($this->index);
|
||||
// Sort only when required
|
||||
if (!$this->indexSorted) {
|
||||
asort($this->index);
|
||||
$this->indexSorted = true;
|
||||
// Clear unsorted cache
|
||||
$this->indexKeysCache = null;
|
||||
$this->indexValuesCache = null;
|
||||
}
|
||||
|
||||
return array_keys($this->index);
|
||||
// Build or rebuild index keys cache
|
||||
if ($this->indexKeysCache === null) {
|
||||
$this->indexKeysCache = array_keys($this->index);
|
||||
}
|
||||
|
||||
return $this->indexKeysCache;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,9 +185,19 @@ class Cells
|
||||
*/
|
||||
public function getSortedCoordinatesInt(): array
|
||||
{
|
||||
asort($this->index);
|
||||
if (!$this->indexSorted) {
|
||||
asort($this->index);
|
||||
$this->indexSorted = true;
|
||||
// Clear unsorted cache
|
||||
$this->indexKeysCache = null;
|
||||
$this->indexValuesCache = null;
|
||||
}
|
||||
|
||||
return array_values($this->index);
|
||||
if ($this->indexValuesCache === null) {
|
||||
$this->indexValuesCache = array_values($this->index);
|
||||
}
|
||||
|
||||
return $this->indexValuesCache;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -300,6 +350,11 @@ class Cells
|
||||
}
|
||||
}
|
||||
|
||||
// Clear index sorted flag and index caches
|
||||
$newCollection->indexSorted = false;
|
||||
$newCollection->indexKeysCache = null;
|
||||
$newCollection->indexValuesCache = null;
|
||||
|
||||
return $newCollection;
|
||||
}
|
||||
|
||||
@@ -390,6 +445,11 @@ class Cells
|
||||
/** @var int $row */
|
||||
$this->index[$cellCoordinate] = (--$row * self::MAX_COLUMN_ID) + Coordinate::columnIndexFromString((string) $column);
|
||||
|
||||
// Clear index sorted flag and index caches
|
||||
$this->indexSorted = false;
|
||||
$this->indexKeysCache = null;
|
||||
$this->indexValuesCache = null;
|
||||
|
||||
$this->currentCoordinate = $cellCoordinate;
|
||||
$this->currentCell = $cell;
|
||||
$this->currentCellIsDirty = true;
|
||||
@@ -444,6 +504,11 @@ class Cells
|
||||
|
||||
$this->index = [];
|
||||
|
||||
// Clear index sorted flag and index caches
|
||||
$this->indexSorted = false;
|
||||
$this->indexKeysCache = null;
|
||||
$this->indexValuesCache = null;
|
||||
|
||||
// detach ourself from the worksheet, so that it can then delete this object successfully
|
||||
$this->parent = null;
|
||||
}
|
||||
|
||||
@@ -3100,9 +3100,30 @@ class Worksheet
|
||||
|
||||
$index = ($row - 1) * AddressRange::MAX_COLUMN_INT + 1;
|
||||
$indexPlus = $index + AddressRange::MAX_COLUMN_INT - 1;
|
||||
|
||||
// Binary search to quickly approach the correct index
|
||||
$keyIndex = intdiv($keysCount, 2);
|
||||
$boundLow = 0;
|
||||
$boundHigh = $keysCount - 1;
|
||||
while ($boundLow <= $boundHigh) {
|
||||
$keyIndex = intdiv($boundLow + $boundHigh, 2);
|
||||
if ($keys[$keyIndex] < $index) {
|
||||
$boundLow = $keyIndex + 1;
|
||||
} elseif ($keys[$keyIndex] > $index) {
|
||||
$boundHigh = $keyIndex - 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Realign to the proper index value
|
||||
while ($keyIndex > 0 && $keys[$keyIndex] > $index) {
|
||||
--$keyIndex;
|
||||
}
|
||||
while ($keyIndex < $keysCount && $keys[$keyIndex] < $index) {
|
||||
++$keyIndex;
|
||||
}
|
||||
|
||||
while ($keyIndex < $keysCount && $keys[$keyIndex] <= $indexPlus) {
|
||||
$key = $keys[$keyIndex];
|
||||
$thisRow = intdiv($key - 1, AddressRange::MAX_COLUMN_INT) + 1;
|
||||
|
||||
Reference in New Issue
Block a user