11# cython: language=c++
2+ # cython: boundscheck=False
3+ # cython: wraparound=False
4+ # cython: cdivision=True
25
36from typing import Any
47
@@ -10,11 +13,13 @@ from flask_inputfilter.models.cimports cimport BaseFilter, BaseValidator, FieldM
1013
1114# Compile-time constants for performance thresholds
1215DEF LARGE_DATASET_THRESHOLD = 10
16+ DEF SMALL_DICT_THRESHOLD = 5
1317
1418
1519cdef class DataMixin:
1620
1721 @staticmethod
22+ @cython.inline
1823 cdef bint has_unknown_fields(
1924 dict [str , Any] data,
2025 dict [str , FieldModel] fields
@@ -35,19 +40,22 @@ cdef class DataMixin:
3540 if not data and fields:
3641 return True
3742
38- cdef set field_set
43+ cdef:
44+ set field_set
45+ Py_ssize_t field_count = len (fields)
46+ Py_ssize_t data_count = len (data)
3947
40- # Use set operations for faster lookup when there are many fields
41- if len (fields) > LARGE_DATASET_THRESHOLD:
48+ if field_count > LARGE_DATASET_THRESHOLD and data_count > SMALL_DICT_THRESHOLD:
4249 field_set = set (fields.keys())
4350 for field_name in data.keys():
4451 if field_name not in field_set:
4552 return True
46- else :
47- # Use direct dict lookup for smaller field counts
53+ elif data_count < field_count:
4854 for field_name in data.keys():
4955 if field_name not in fields:
5056 return True
57+ else :
58+ return bool (set (data.keys()) - set (fields.keys()))
5159
5260 return False
5361
@@ -72,19 +80,30 @@ cdef class DataMixin:
7280 """
7381 cdef:
7482 dict [str , Any] filtered_data = {}
75- Py_ssize_t i, n = len (data) if data else 0
76- list keys = list (data.keys()) if n > 0 else []
77- list values = list (data.values()) if n > 0 else []
83+ Py_ssize_t i, n = len (data) if data is not None else 0
84+ list keys
85+ list values
7886 str field_name
7987 object field_value
88+ FieldModel field_info
89+
90+ # Early return for empty data
91+ if n == 0 :
92+ return filtered_data
93+
94+ # Pre-allocate lists
95+ keys = list (data.keys())
96+ values = list (data.values())
8097
8198 for i in range (n):
8299 field_name = keys[i]
83100 field_value = values[i]
84101
85- if field_name in fields:
102+ # Cache field lookup
103+ field_info = fields.get(field_name)
104+ if field_info is not None :
86105 field_value = ValidationMixin.apply_filters(
87- fields[field_name] .filters,
106+ field_info .filters,
88107 global_filters,
89108 field_value,
90109 )
@@ -94,6 +113,7 @@ cdef class DataMixin:
94113 return filtered_data
95114
96115 @staticmethod
116+ @cython.inline
97117 cdef tuple validate_with_conditions(
98118 dict [str , FieldModel] fields,
99119 dict [str , Any] data,
@@ -125,8 +145,8 @@ cdef class DataMixin:
125145 fields, data, global_filters, global_validators
126146 )
127147
128- # Check conditions if present and no errors yet
129- if conditions and not errors:
148+ # Check conditions only if present and no errors yet
149+ if conditions is not None and len (conditions) > 0 and not errors:
130150 try :
131151 ValidationMixin.check_conditions(conditions, validated_data)
132152 except ValidationError as e:
@@ -150,13 +170,19 @@ cdef class DataMixin:
150170 cdef:
151171 Py_ssize_t i, n
152172 dict source_inputs = source_filter.get_inputs()
153- list keys = list (source_inputs.keys()) if source_inputs else []
154- list new_fields = list (source_inputs.values()) if source_inputs else []
155-
156- # Merge fields efficiently
157- n = len (keys)
158- for i in range (n):
159- target_filter.fields[keys[i]] = new_fields[i]
173+ list keys
174+ list new_fields
175+
176+ if source_inputs:
177+ keys = list (source_inputs.keys())
178+ new_fields = list (source_inputs.values())
179+ n = len (keys)
180+
181+ # Batch update fields
182+ for i in range (n):
183+ target_filter.fields[keys[i]] = new_fields[i]
184+ else :
185+ n = 0
160186
161187 # Merge conditions
162188 target_filter.conditions.extend(source_filter.conditions)
@@ -174,6 +200,7 @@ cdef class DataMixin:
174200 )
175201
176202 @staticmethod
203+ @cython.inline
177204 cdef void _merge_component_list(list target_list, list source_list):
178205 """
179206 Helper method to merge component lists avoiding duplicates by type.
@@ -183,13 +210,21 @@ cdef class DataMixin:
183210 - **target_list** (*list*): The list to merge into.
184211 - **source_list** (*list*): The list to merge from.
185212 """
186- cdef dict existing_type_map
213+ cdef:
214+ dict existing_type_map = {}
215+ Py_ssize_t i, n = len (target_list)
216+ object component
217+ type component_type
218+
219+ # Build type map once
220+ for i in range (n):
221+ existing_type_map[type (target_list[i])] = i
187222
223+ # Process source components
188224 for component in source_list:
189- existing_type_map = {
190- type (v): i for i, v in enumerate (target_list)
191- }
192- if type (component) in existing_type_map:
193- target_list[existing_type_map[type (component)]] = component
225+ component_type = type (component)
226+ if component_type in existing_type_map:
227+ target_list[existing_type_map[component_type]] = component
194228 else :
195- target_list.append(component)
229+ target_list.append(component)
230+ existing_type_map[component_type] = len (target_list) - 1
0 commit comments