Skip to content

Commit 34b8896

Browse files
committed
Cythonize LENGTH function
1 parent 3195598 commit 34b8896

4 files changed

Lines changed: 39 additions & 22 deletions

File tree

opteryx/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__build__ = 1394
1+
__build__ = 1395
22

33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# cython: language_level=3
2+
# cython: nonecheck=False
3+
# cython: cdivision=True
4+
# cython: initializedcheck=False
5+
# cython: infer_types=True
6+
# cython: wraparound=False
7+
# cython: boundscheck=False
8+
9+
import numpy
10+
cimport numpy
11+
numpy.import_array()
12+
13+
from libc.stdint cimport uint32_t
14+
15+
cpdef numpy.ndarray[numpy.uint32_t, ndim=1] list_length(numpy.ndarray array):
16+
cdef Py_ssize_t i, n = array.shape[0]
17+
cdef numpy.ndarray[numpy.uint32_t, ndim=1] result = numpy.empty(n, dtype=numpy.uint32)
18+
cdef uint32_t[::1] result_view = result
19+
cdef object val
20+
21+
for i in range(n):
22+
val = array[i]
23+
if isinstance(val, (str, bytes)):
24+
result_view[i] = len(val)
25+
else:
26+
result_view[i] = 0
27+
28+
return result

opteryx/functions/__init__.py

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import opteryx
2323
from opteryx.compiled.list_ops.list_contains_any import list_contains_any
2424
from opteryx.compiled.list_ops.list_encode_utf8 import list_encode_utf8 as to_blob
25+
from opteryx.compiled.list_ops.list_length import list_length
2526
from opteryx.exceptions import FunctionExecutionError
2627
from opteryx.exceptions import IncorrectTypeError
2728
from opteryx.functions import date_functions
@@ -260,19 +261,6 @@ def _inner(array, literal):
260261
return _inner
261262

262263

263-
def get_len(obj):
264-
"""len, but nullsafe"""
265-
if hasattr(obj, "__len__"):
266-
return len(obj)
267-
if hasattr(obj, "length"): # Some Arrow scalar types have .length property
268-
return obj.length
269-
if hasattr(obj, "nbytes"): # NumPy scalar types have .nbytes
270-
return obj.nbytes
271-
if hasattr(obj, "as_py") and isinstance(obj.as_py(), (bytes, str)): # PyArrow string scalar
272-
return len(obj.as_py())
273-
return None
274-
275-
276264
def _coalesce(*arrays):
277265
"""
278266
Element-wise coalesce function for multiple numpy arrays.
@@ -394,7 +382,7 @@ def sleep(x):
394382
"ASCII": (string_functions.to_ascii, "INTEGER", 1.0),
395383

396384
# STRINGS
397-
"LENGTH": (_iterate_single_parameter(get_len), "INTEGER", 1.0), # LENGTH(str) -> int
385+
"LENGTH": (list_length, "INTEGER", 1.0), # LENGTH(str) -> int
398386
"UPPER": (compute.utf8_upper, "VARCHAR", 1.0), # UPPER(str) -> str
399387
"LOWER": (compute.utf8_lower, "VARCHAR", 1.0), # LOWER(str) -> str
400388
"LEFT": (string_functions.string_slicer_left, "VARCHAR", 1.0),

opteryx/managers/expression/ops.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"""
66

77
import re
8+
from contextlib import suppress
89

910
import numpy
1011
import pyarrow
@@ -147,7 +148,7 @@ def _inner_filter_operations(arr, operator, value):
147148
"""
148149
if not operator.startswith(("AnyOp", "AllOp")) and len(value) == 1:
149150
value = value[0]
150-
if hasattr(value, "item"):
151+
with suppress(AttributeError):
151152
value = value.item()
152153
if isinstance(value, (tuple, list)):
153154
value = pyarrow.array(value)
@@ -165,24 +166,24 @@ def _inner_filter_operations(arr, operator, value):
165166
if operator == "GtEq":
166167
return compute.greater_equal(arr, value).to_numpy(False).astype(dtype=bool)
167168
if operator == "InList":
168-
if hasattr(value, "to_pylist"):
169+
with suppress(AttributeError):
169170
value = value.to_pylist()
170-
if hasattr(value, "to_numpy"):
171+
with suppress(AttributeError):
171172
value = value.to_numpy(zero_copy_only=False)
172173
values = set(value)
173-
if hasattr(arr, "to_numpy"):
174+
with suppress(AttributeError):
174175
arr = arr.to_numpy(zero_copy_only=False)
175176
if arr.dtype == numpy.int64:
176177
return list_ops.list_in_list.list_in_list_int64(memoryview(arr), values, len(arr))
177178
else:
178179
return list_ops.list_in_list.list_in_list(arr.astype(object), values)
179180
if operator == "NotInList":
180-
if hasattr(value, "to_pylist"):
181+
with suppress(AttributeError):
181182
value = value.to_pylist()
182-
if hasattr(value, "to_numpy"):
183+
with suppress(AttributeError):
183184
value = value.to_numpy(zero_copy_only=False)
184185
values = set(value)
185-
if hasattr(arr, "to_numpy"):
186+
with suppress(AttributeError):
186187
arr = arr.to_numpy(zero_copy_only=False)
187188
if arr.dtype == numpy.int64:
188189
matches = list_ops.list_in_list.list_in_list_int64(memoryview(arr), values, len(arr))

0 commit comments

Comments
 (0)