From efa5c595598a94cc534cd917b39875e81f99f4b6 Mon Sep 17 00:00:00 2001
From: Paul Ganssle
Date: Tue, 11 May 2021 11:18:20 -0400
Subject: [PATCH] Replace hand-rolled binary search with bisect_left (#50410)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The `bisect` module exposes a `bisect_left` function which does
basically what the bulk of `_lower_bound` does. From my tests, it is
slightly faster (~5%) in the probably common ideal case where `arr` is short.
In the worst case scenario, `bisect.bisect_left` is *much* faster.
```
>>> arr = list(range(60))
>>> cmp = 59
>>> %timeit _lower_bound(arr, cmp)
736 ns ± 6.24 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
>>> %timeit bisect_lower_bound(arr, cmp)
290 ns ± 7.77 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
```
I doubt this is a huge bottleneck or anything, but I think it's a bit
more readable, and it's more efficient, so it seems like it's mostly a
win.
This commit *will* add a new unconditional import for `bisect` when
importing `util.dt`, and `bisect` is not currently imported for any of
the standard library modules. It is possible to make this conditional by
placing `import bisect` in the _lower_bound function, or in the function
it's nested in.
---
homeassistant/util/dt.py | 11 ++---------
1 file changed, 2 insertions(+), 9 deletions(-)
diff --git a/homeassistant/util/dt.py b/homeassistant/util/dt.py
index c818c955370..28aebc5db47 100644
--- a/homeassistant/util/dt.py
+++ b/homeassistant/util/dt.py
@@ -1,6 +1,7 @@
"""Helper methods to handle the time in Home Assistant."""
from __future__ import annotations
+import bisect
from contextlib import suppress
import datetime as dt
import re
@@ -265,15 +266,7 @@ def find_next_time_expression_time(
Return None if no such value exists.
"""
- left = 0
- right = len(arr)
- while left < right:
- mid = (left + right) // 2
- if arr[mid] < cmp:
- left = mid + 1
- else:
- right = mid
-
+ left = bisect.bisect_left(arr, cmp)
if left == len(arr):
return None
return arr[left]