@@ -35,6 +35,7 @@ cdef extern from "include/basetraj_seq.h" nogil:
3535
3636__all__ = [' CBaseTrajSeq' ]
3737
38+
3839cdef class CBaseTrajSeq:
3940 """
4041 C Buffer Trajectory Sequence
@@ -59,7 +60,6 @@ cdef class CBaseTrajSeq:
5960 traj_seq.append(time, px, py, pz, vx, vy, vz, mach)
6061 trajectory_data = traj_seq[0] # Lazily converted to BaseTrajData
6162 """
62-
6363 # Attributes declared in the matching .pxd; do not redeclare here.
6464
6565 def __cinit__ (self ):
@@ -120,7 +120,7 @@ cdef class CBaseTrajSeq:
120120 self ._capacity = new_capacity
121121
122122 cdef void _append_c(self , double time, double px, double py, double pz,
123- double vx, double vy, double vz, double mach):
123+ double vx, double vy, double vz, double mach):
124124 """
125125 Append a new BaseTrajC entry to the buffer.
126126
@@ -129,10 +129,11 @@ cdef class CBaseTrajSeq:
129129 px, py, pz: Position coordinates
130130 vx, vy, vz: Velocity coordinates
131131 mach: Mach number
132+
133+ Note: This is the C-level `append` implementation and requires the GIL (because it references `self`).
134+ Callers who want a nogil fast-path should use the module-level raw helpers `ensure_capacity_try_nogil_raw`
135+ and `append_nogil_raw` which operate on raw C pointers and can be used inside with nogil: blocks.
132136 """
133- # Note: this is the raw C implementation used on hot paths. It is declared
134- # nogil so callers that hold the GIL may release it for faster operation.
135- # Python-level callers should use the thin Python wrapper `append` below.
136137 self ._ensure_capacity(self ._length + 1 )
137138
138139 # Calculate pointer to new entry using byte arithmetic (self._buffer + self._length)
@@ -148,11 +149,9 @@ cdef class CBaseTrajSeq:
148149
149150 # increment length (must be done while still holding the GIL in typical callers)
150151 self ._length += 1
151- # Nogil try/grow and append helpers are implemented as module-level raw
152- # helpers to avoid touching 'self' without holding the GIL.
153152
154153 def append (self , double time , double px , double py , double pz ,
155- double vx , double vy , double vz , double mach ):
154+ double vx , double vy , double vz , double mach ):
156155 """ Python wrapper around the cdef hot-path `_append_c`.
157156
158157 Attempt a nogil fast-path that grows and appends using the raw
@@ -163,12 +162,14 @@ cdef class CBaseTrajSeq:
163162 cdef BaseTrajC* local_buf = self ._buffer
164163 cdef size_t local_cap = self ._capacity
165164 cdef size_t local_len = self ._length
166- cdef bint ok = False
165+ # Explicitly initialize as bint to avoid mypy/cython literal-to-bool diagnostics
166+ cdef bint ok = < bint> 0
167167
168168 # Try the nogil fast-path: grow (if needed) and append while holding no GIL.
169169 # We use local copies and then write them back into `self` on success.
170170 with nogil:
171- ok = ensure_capacity_try_nogil_raw(& local_buf, & local_cap, < size_t> (local_len + 1 ))
171+ # Cast the C-return value to bint explicitly to satisfy static typing
172+ ok = < bint> ensure_capacity_try_nogil_raw(& local_buf, & local_cap, < size_t> (local_len + 1 ))
172173 if ok:
173174 append_nogil_raw(& local_buf, & local_len, time, px, py, pz, vx, vy, vz, mach)
174175
@@ -183,6 +184,16 @@ cdef class CBaseTrajSeq:
183184 # which will raise MemoryError on failure.
184185 self ._ensure_capacity(self ._length + 1 )
185186 self ._append_c(time, px, py, pz, vx, vy, vz, mach)
187+
188+ def reserve (self , Py_ssize_t min_capacity ):
189+ """ Public helper to pre-allocate buffer capacity from Python tests/benchmarks.
190+
191+ This calls the underlying cdef `_ensure_capacity` which performs the
192+ realloc logic. It's small and safe to expose for testing/benching.
193+ """
194+ if min_capacity < 0 :
195+ raise ValueError (" min_capacity must be non-negative" )
196+ self ._ensure_capacity(< size_t> min_capacity)
186197
187198 cdef BaseTrajC* c_getitem(self , Py_ssize_t idx):
188199 """
@@ -282,7 +293,7 @@ cdef class CBaseTrajSeq:
282293 with nogil:
283294 outp = _interpolate_nogil_raw(_buf, _len, idx, key_kind, key_value)
284295
285- if outp == NULL :
296+ if outp == < BaseTrajC * > NULL :
286297 raise IndexError (" interpolate_at requires idx with valid neighbors (idx-1, idx, idx+1)" )
287298
288299 pos.x = outp.px; pos.y = outp.py; pos.z = outp.pz
@@ -299,7 +310,7 @@ cdef class CBaseTrajSeq:
299310 return res
300311
301312# Module-level nogil implementation that operates on raw buffers.
302- cdef BaseTrajC* _interpolate_nogil_raw(BaseTrajC* buffer , size_t length, Py_ssize_t idx, int key_kind, double key_value) nogil:
313+ cdef BaseTrajC* _interpolate_nogil_raw(BaseTrajC* buffer , size_t length, Py_ssize_t idx, int key_kind, double key_value) except NULL nogil:
303314 cdef Py_ssize_t plength = < Py_ssize_t> length
304315 cdef BaseTrajC * p0
305316 cdef BaseTrajC * p1
@@ -337,24 +348,42 @@ cdef BaseTrajC* _interpolate_nogil_raw(BaseTrajC* buffer, size_t length, Py_ssiz
337348 else :
338349 return < BaseTrajC* > NULL
339350
351+ # Inline Lagrange quadratic interpolation to keep this function fully nogil-safe.
352+ cdef double L0, L1, L2, denom0, denom1, denom2, x
353+ x = key_value
354+
355+ # Compute denominators and check for degenerate points
356+ denom0 = (x0 - x1) * (x0 - x2)
357+ denom1 = (x1 - x0) * (x1 - x2)
358+ denom2 = (x2 - x0) * (x2 - x1)
359+ if denom0 == 0.0 or denom1 == 0.0 or denom2 == 0.0 :
360+ # Degenerate points - cannot interpolate safely
361+ return < BaseTrajC* > NULL
362+
363+ L0 = ((x - x1) * (x - x2)) / denom0
364+ L1 = ((x - x0) * (x - x2)) / denom1
365+ L2 = ((x - x0) * (x - x1)) / denom2
366+
340367 if key_kind != 0 :
341- time = lagrange_quadratic(key_value, x0, p0.time, x1, p1.time, x2, p2.time)
368+ time = p0.time * L0 + p1.time * L1 + p2.time * L2
342369 else :
343- time = key_value
370+ time = x
344371
345- px = lagrange_quadratic(key_value, x0, p0.px, x1, p1.px, x2, p2.px)
346- py = lagrange_quadratic(key_value, x0, p0.py, x1, p1.py, x2, p2.py)
347- pz = lagrange_quadratic(key_value, x0, p0.pz, x1, p1.pz, x2, p2.pz)
348- vx = lagrange_quadratic(key_value, x0, p0.vx, x1, p1.vx, x2, p2.vx)
349- vy = lagrange_quadratic(key_value, x0, p0.vy, x1, p1.vy, x2, p2.vy)
350- vz = lagrange_quadratic(key_value, x0, p0.vz, x1, p1.vz, x2, p2.vz)
372+ px = p0.px * L0 + p1.px * L1 + p2.px * L2
373+ py = p0.py * L0 + p1.py * L1 + p2.py * L2
374+ pz = p0.pz * L0 + p1.pz * L1 + p2.pz * L2
375+ vx = p0.vx * L0 + p1.vx * L1 + p2.vx * L2
376+ vy = p0.vy * L0 + p1.vy * L1 + p2.vy * L2
377+ vz = p0.vz * L0 + p1.vz * L1 + p2.vz * L2
351378
352379 if key_kind != 1 :
353- mach = lagrange_quadratic(key_value, x0, p0.mach, x1, p1.mach, x2, p2.mach)
380+ mach = p0.mach * L0 + p1.mach * L1 + p2.mach * L2
354381 else :
355- mach = key_value
382+ mach = x
356383
357- outp = < BaseTrajC* > malloc(< size_t> (sizeof(BaseTrajC)))
384+ # Cast sizeof(...) to size_t to match malloc's size parameter and avoid
385+ # implicit-int-to-size_t warnings on some compilers/platforms.
386+ outp = < BaseTrajC* > malloc(< size_t> sizeof(BaseTrajC))
358387 if outp == NULL :
359388 return < BaseTrajC* > NULL
360389
@@ -368,14 +397,14 @@ cdef BaseTrajC* _interpolate_nogil_raw(BaseTrajC* buffer, size_t length, Py_ssiz
368397
369398# Nogil-safe raw capacity/append helpers implemented to match .pxd declarations.
370399# These operate purely on C pointers and primitive types so they can run without the GIL.
371- cdef bint ensure_capacity_try_nogil_raw(BaseTrajC** buf_p, size_t* capacity_p, size_t min_capacity) nogil:
400+ cdef bint ensure_capacity_try_nogil_raw(BaseTrajC** buf_p, size_t* capacity_p, size_t min_capacity) except False nogil:
372401 cdef size_t cur = capacity_p[0 ]
373402 cdef size_t new_capacity
374403 cdef BaseTrajC* new_buf
375404 cdef size_t doubled
376405
377406 if min_capacity <= cur:
378- return True
407+ return < bint > 1
379408
380409 if cur > 0 :
381410 doubled = < size_t> (cur * 2 )
@@ -388,15 +417,15 @@ cdef bint ensure_capacity_try_nogil_raw(BaseTrajC** buf_p, size_t* capacity_p, s
388417
389418 new_buf = < BaseTrajC* > realloc(< void * > buf_p[0 ], new_capacity * sizeof(BaseTrajC))
390419 if new_buf == NULL :
391- return False
420+ return < bint > 0
392421
393422 buf_p[0 ] = new_buf
394423 capacity_p[0 ] = new_capacity
395- return True
424+ return < bint > 1
396425
397426
398427cdef void append_nogil_raw(BaseTrajC** buf_p, size_t* length_p, double time, double px, double py, double pz,
399- double vx, double vy, double vz, double mach) nogil:
428+ double vx, double vy, double vz, double mach) noexcept nogil:
400429 cdef BaseTrajC* entry_ptr = < BaseTrajC* > ((< char * > buf_p[0 ]) + (< size_t> length_p[0 ]) * sizeof(BaseTrajC))
401430 entry_ptr.time = time
402431 entry_ptr.px = px; entry_ptr.py = py; entry_ptr.pz = pz
0 commit comments