11# cython: language=c++
2+ # cython: boundscheck=False
3+ # cython: wraparound=False
4+ # cython: cdivision=True
5+ # cython: overflowcheck=False
6+ # cython: initializedcheck=False
7+ # cython: nonecheck=False
8+ # cython: optimize.use_switch=True
9+ # cython: optimize.unpack_method_calls=True
10+ # cython: infer_types=True
211
312import json
413import logging
@@ -9,11 +18,14 @@ from flask import Response, g, request
918
1019from flask_inputfilter.exceptions import ValidationError
1120
21+ from flask_inputfilter.declarative.cimports cimport FieldDescriptor
1222from flask_inputfilter.mixins.cimports cimport DataMixin
1323from flask_inputfilter.models.cimports cimport BaseCondition, BaseFilter, BaseValidator, ExternalApiConfig, FieldModel
1424
1525from libcpp.vector cimport vector
1626from libcpp.string cimport string
27+ from libcpp cimport bool as cbool
28+ from libcpp.algorithm cimport find
1729
1830cdef dict _INTERNED_STRINGS = {
1931 " _condition" : sys.intern(" _condition" ),
@@ -36,6 +48,44 @@ cdef dict _INTERNED_STRINGS = {
3648cdef extern from " helper.h" :
3749 vector[string] make_default_methods()
3850
51+ cdef cppclass ObjectPool[T]:
52+ ObjectPool()
53+ T* acquire()
54+ void release(T* obj)
55+ void release_all()
56+ void reserve(size_t capacity)
57+ size_t size()
58+ size_t available()
59+
60+ cdef cppclass FieldLookup:
61+ FieldLookup()
62+ void add_field(const string& name)
63+ bint has_field(const string& name)
64+ size_t get_index(const string& name)
65+ const vector[string]& get_field_names()
66+ void clear()
67+ void reserve(size_t capacity)
68+
69+ cdef cppclass StringIntern:
70+ @staticmethod
71+ const string& intern (const string& str )
72+ @staticmethod
73+ void clear()
74+ @staticmethod
75+ size_t count()
76+
77+
78+ # Fast C++ string processing
79+ cdef extern from " <string_view>" namespace " std" :
80+ cdef cppclass string_view:
81+ string_view()
82+ string_view(const char * data)
83+ string_view(const char * data, size_t len )
84+ cbool empty()
85+ size_t size()
86+ const char * data()
87+ cbool starts_with(string_view prefix)
88+
3989T = TypeVar(" T" )
4090
4191
@@ -57,8 +107,22 @@ cdef class InputFilter:
57107
58108 def __init__(self , methods: Optional[list[str]] = None ) -> None:
59109 if methods is not None:
60- self.methods.clear()
61- [self.methods.push_back(method.encode()) for method in methods]
110+ self._set_methods(methods )
111+
112+ self._register_decorator_components()
113+
114+ cdef void _set_methods(self , list methods ):
115+ """ Efficiently set HTTP methods using C++ vector operations."""
116+ cdef str method
117+ cdef bytes encoded_method
118+ cdef Py_ssize_t n = len (methods)
119+
120+ self .methods.clear()
121+ self .methods.reserve(n)
122+
123+ for method in methods:
124+ encoded_method = method.encode(' utf-8' )
125+ self .methods.push_back(string(encoded_method))
62126
63127 cpdef bint is_valid(self ):
64128 """
@@ -122,8 +186,14 @@ cdef class InputFilter:
122186 """
123187
124188 cdef InputFilter input_filter = cls ()
125- cdef string request_method = request.method.encode()
126- if not any (request_method == method for method in input_filter.methods):
189+ cdef bytes request_method_bytes = request.method.encode(' utf-8' )
190+ cdef string request_method = string(request_method_bytes)
191+ cdef vector[string].iterator method_it = find(
192+ input_filter.methods.begin(),
193+ input_filter.methods.end(),
194+ request_method
195+ )
196+ if method_it == input_filter.methods.end():
127197 return Response(status = 405 , response = " Method Not Allowed" )
128198
129199 if request.is_json:
@@ -206,6 +276,48 @@ cdef class InputFilter:
206276 """
207277 self .conditions.append(condition)
208278
279+ cdef void _register_decorator_components(self ):
280+ """ Register decorator-based components from the current class only."""
281+ cdef object cls , attr_value, conditions, validators, filters
282+ cdef str attr_name
283+ cdef list dir_attrs
284+ cdef FieldDescriptor field_desc
285+
286+ cls = self .__class__
287+ dir_attrs = dir (cls )
288+
289+ for attr_name in dir_attrs:
290+ if (< bytes> attr_name.encode(' utf-8' )).startswith(b" _" ):
291+ continue
292+
293+ attr_value = getattr (cls , attr_name, None )
294+ if attr_value is not None and isinstance (attr_value, FieldDescriptor):
295+ field_desc = < FieldDescriptor> attr_value
296+ self .fields[attr_name] = FieldModel(
297+ field_desc.required,
298+ field_desc._default,
299+ field_desc.fallback,
300+ field_desc.filters,
301+ field_desc.validators,
302+ field_desc.steps,
303+ field_desc.external_api,
304+ field_desc.copy,
305+ )
306+
307+ conditions = getattr (cls , " _conditions" , None )
308+ if conditions is not None :
309+ self .conditions.extend(conditions)
310+
311+ validators = getattr (cls , " _global_validators" , None )
312+ if validators is not None :
313+ self .global_validators.extend(validators)
314+
315+ filters = getattr (cls , " _global_filters" , None )
316+ if filters is not None :
317+ self .global_filters.extend(filters)
318+
319+ self .model_class = getattr (cls , " _model" , self .model_class)
320+
209321 cpdef list get_conditions(self ):
210322 """
211323 Retrieve the list of all registered conditions.
@@ -307,14 +419,19 @@ cdef class InputFilter:
307419
308420 cdef:
309421 Py_ssize_t i, n = len (self .fields)
310- dict result = {}
422+ dict result
311423 list field_names = list (self .fields.keys())
312424 str field
425+ object field_value
426+
427+ # Pre-allocate dictionary size for better performance
428+ result = {}
313429
314430 for i in range (n):
315431 field = field_names[i]
316- if field in self .data:
317- result[field] = self .data[field]
432+ field_value = self .data.get(field)
433+ if field_value is not None :
434+ result[field] = field_value
318435 return result
319436
320437 cpdef dict [str , Any] get_unfiltered_data(self ):
0 commit comments