Skip to content
This repository was archived by the owner on Feb 2, 2024. It is now read-only.

Commit b369520

Browse files
committed
Adds zip and dict builtins overloads to support easy literal dict ctor
Motivation: there's no easy way to create Numba LiteralStrKeyDict objects for const dicts with many elements. This adds a special overload for dict builtin that creates LiteralStrKeyDict from tuple of pairs ('col_name', col_data).
1 parent da14ea0 commit b369520

File tree

1 file changed

+71
-1
lines changed

1 file changed

+71
-1
lines changed

sdc/functions/tuple_utils.py

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,14 @@
2525
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2626
# *****************************************************************************
2727

28+
from textwrap import dedent
29+
2830
from numba import types
29-
from numba.extending import (intrinsic, )
31+
from numba.extending import intrinsic
3032
from numba.core.typing.templates import (signature, )
3133

34+
from sdc.utilities.utils import sdc_overload
35+
3236

3337
@intrinsic
3438
def sdc_tuple_map(typingctx, func, data, *args):
@@ -205,3 +209,69 @@ def codegen(context, builder, sig, args):
205209
return context.make_tuple(builder, ret_type, [first_tup, second_tup])
206210

207211
return ret_type(data_type), codegen
212+
213+
214+
@sdc_overload(zip)
215+
def zip_tuples_spec_ovld(x, y):
216+
print("DEBUG: overload_zip x, y: ", x, y)
217+
218+
if not (isinstance(x, types.BaseAnonymousTuple) and isinstance(y, types.BaseAnonymousTuple)):
219+
return None
220+
221+
res_size = min(len(x), len(y))
222+
func_impl_name = 'zip_tuples_spec_impl'
223+
tup_elements = ', '.join([f"(x[{i}], y[{i}])" for i in range(res_size)])
224+
func_text = dedent(f"""
225+
def {func_impl_name}(x, y):
226+
return ({tup_elements}{',' if res_size else ''})
227+
""")
228+
use_globals, use_locals = {}, {}
229+
# print("DEBUG: func_text:", func_text)
230+
exec(func_text, use_globals, use_locals)
231+
return use_locals[func_impl_name]
232+
233+
# FIXME_Numba#6533: alternatively we could have used sdc_tuple_map_elementwise
234+
# to avoid another use of exec, but due to @intrinsic-s not supporting
235+
# prefer_literal option below implementation looses literaly of args!
236+
# from sdc.functions.tuple_utils import sdc_tuple_map_elementwise
237+
# def zip_tuples_spec_impl(x, y):
238+
# return sdc_tuple_map_elementwise(
239+
# lambda a, b: (a, b),
240+
# x,
241+
# y
242+
# )
243+
#
244+
# return zip_tuples_spec_impl
245+
246+
247+
@sdc_overload(dict)
248+
def dict_from_tuples_ovld(x):
249+
print("DEBUG: entered custom dict typing: x=", x)
250+
251+
accepted_tuple_types = (types.Tuple, types.UniTuple)
252+
if not isinstance (x, accepted_tuple_types):
253+
return None
254+
255+
def check_tuple_element(ty):
256+
return (isinstance(ty, accepted_tuple_types)
257+
and len(ty) == 2
258+
and isinstance(ty[0], types.StringLiteral))
259+
260+
# below checks that elements are tuples with size 2 and first element is literal string
261+
if not (len(x) != 0 and all(map(check_tuple_element, x))):
262+
assert False, f"Creating LiteralStrKeyDict not supported from pairs of: {x}"
263+
264+
# numba type-infers {'A': [1, 2, 3]} i.e. const dict of size 1 not as LiteralStrKeyDict
265+
# but as non literal dict! TO-DO: add special branch here and call literal dict ctor directly
266+
func_impl_name = 'dict_from_tuples_impl'
267+
dict_elements = ', '.join([f"x[{i}][0]:x[{i}][1]" for i in range(len(x))])
268+
func_text = dedent(f"""
269+
def {func_impl_name}(x):
270+
res = {{{dict_elements}}}
271+
return res
272+
""")
273+
use_globals, use_locals = {}, {}
274+
# print("DEBUG: dict func_text:\n", func_text)
275+
exec(func_text, use_globals, use_locals)
276+
return use_locals[func_impl_name]
277+

0 commit comments

Comments
 (0)