Skip to content

Commit 7fda9e6

Browse files
committed
perf: fix needless sorting on every holiday insert
Sorting after each insertion results in O(n² log n) complexity when adding n holidays. For a provider with 20 holidays, this means sorting 20 times instead of once. Using deferred sorting avoids this issue which could result in 10-20x faster initialization for providers with many holidays. Signed-off-by: Sacha Telgenhof <me@sachatelgenhof.com>
1 parent e59894c commit 7fda9e6

1 file changed

Lines changed: 25 additions & 2 deletions

File tree

src/Yasumi/Provider/AbstractProvider.php

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ abstract class AbstractProvider implements \Countable, ProviderInterface, \Itera
8686
*/
8787
private array $holidays = [];
8888

89+
/**
90+
* flag to track if holidays need to be sorted
91+
*/
92+
private bool $needSorting = false;
93+
8994
/**
9095
* Creates a new holiday provider (i.e. country/state).
9196
*
@@ -114,7 +119,7 @@ public function addHoliday(Holiday $holiday): void
114119
}
115120

116121
$this->holidays[$holiday->getKey()] = $holiday;
117-
uasort($this->holidays, static fn (\DateTimeInterface $dateA, \DateTimeInterface $dateB): int => self::compareDates($dateA, $dateB));
122+
$this->needSorting = true;
118123
}
119124

120125
public function removeHoliday(string $key): void
@@ -182,6 +187,8 @@ public function count(): int
182187

183188
public function getHolidays(): array
184189
{
190+
$this->ensureSorted();
191+
185192
return $this->holidays;
186193
}
187194

@@ -228,7 +235,9 @@ public function between(
228235

229236
public function getIterator(): \ArrayIterator
230237
{
231-
return new \ArrayIterator($this->getHolidays());
238+
$this->ensureSorted();
239+
240+
return new \ArrayIterator($this->holidays);
232241
}
233242

234243
public function on(\DateTimeInterface $date): OnFilter
@@ -238,6 +247,8 @@ public function on(\DateTimeInterface $date): OnFilter
238247

239248
public function getHolidayDates(): array
240249
{
250+
$this->ensureSorted();
251+
241252
return array_map(static fn ($holiday): string => (string) $holiday, $this->holidays);
242253
}
243254

@@ -264,6 +275,18 @@ protected function isHolidayNameNotEmpty(string $key): bool
264275
private function clearHolidays(): void
265276
{
266277
$this->holidays = [];
278+
$this->needSorting = false;
279+
}
280+
281+
/**
282+
* Ensures holidays are sorted chronologically if needed.
283+
*/
284+
private function ensureSorted(): void
285+
{
286+
if ($this->needSorting) {
287+
uasort($this->holidays, static fn (\DateTimeInterface $dateA, \DateTimeInterface $dateB): int => self::compareDates($dateA, $dateB));
288+
$this->needSorting = false;
289+
}
267290
}
268291

269292
/**

0 commit comments

Comments
 (0)