@@ -433,6 +433,20 @@ def gen_external_functions(funcs: list[dict]) -> str:
433433 "short" : "short" ,
434434}
435435
436+ # How to read one element of a scalar array `Marshal.Copy` has no overload for.
437+ # `{0}` is the array's base pointer and `{1}` the byte offset of the element.
438+ # Reading such an array as an array of POINTERS walks it at eight bytes a step,
439+ # which runs off the end of a `bool` array and answers addresses that are the
440+ # values' own bytes.
441+ _SCALAR_ELEM_READER : dict [str , tuple [int , str ]] = {
442+ "bool" : (1 , "Marshal.ReadByte({0}, {1}) != 0" ),
443+ "sbyte" : (1 , "(sbyte) Marshal.ReadByte({0}, {1})" ),
444+ "ushort" : (2 , "(ushort) Marshal.ReadInt16({0}, {1})" ),
445+ "uint" : (4 , "(uint) Marshal.ReadInt32({0}, {1})" ),
446+ "ulong" : (8 , "(ulong) Marshal.ReadInt64({0}, {1})" ),
447+ "float" : (4 , "BitConverter.Int32BitsToSingle(Marshal.ReadInt32({0}, {1}))" ),
448+ }
449+
436450
437451def _strip_const_stars (c_type : str ) -> tuple [str , int ]:
438452 s = c_type .replace ("const " , "" ).strip ()
@@ -462,6 +476,8 @@ def _csharp_array_element(c_type: str, canonical: str) -> tuple[str, str]:
462476 return (elem , "Marshal.Copy" )
463477 if base == "uint8_t" :
464478 return ("byte" , "ByteBuffer" )
479+ if elem in _SCALAR_ELEM_READER :
480+ return (elem , f"ScalarArray:{ elem } " )
465481 if stars == 1 and base in STRUCTS :
466482 # A single pointer to a catalog struct is an array of struct VALUES, not
467483 # of pointers: element i sits at the struct's own stride, and reading it
@@ -567,6 +583,12 @@ def _emit_outputs_wrapper(f: dict) -> list[str]:
567583 stride = ret_strategy .split (":" , 1 )[1 ]
568584 lines .append (" for (int _i = 0; _i < _n; _i++)" )
569585 lines .append (f" {{ _resultArr[_i] = IntPtr.Add(_resultPtr, _i * { stride } ); }}" )
586+ elif ret_strategy .startswith ("ScalarArray:" ):
587+ size , reader = _SCALAR_ELEM_READER [ret_strategy .split (":" , 1 )[1 ]]
588+ offset = "_i" if size == 1 else f"_i * { size } "
589+ lines .append (" for (int _i = 0; _i < _n; _i++)" )
590+ lines .append (f" {{ _resultArr[_i] = "
591+ f"{ reader .format ('_resultPtr' , offset )} ; }}" )
570592 else :
571593 lines .append (" for (int _i = 0; _i < _n; _i++)" )
572594 lines .append (" { _resultArr[_i] = Marshal.ReadIntPtr(_resultPtr, _i * IntPtr.Size); }" )
@@ -577,6 +599,12 @@ def _emit_outputs_wrapper(f: dict) -> list[str]:
577599 stride = strategy .split (":" , 1 )[1 ]
578600 lines .append (f" for (int _i = 0; _i < _n; _i++)" )
579601 lines .append (f" {{ _{ local } _out[_i] = IntPtr.Add(_{ local } _arr, _i * { stride } ); }}" )
602+ elif strategy .startswith ("ScalarArray:" ):
603+ size , reader = _SCALAR_ELEM_READER [strategy .split (":" , 1 )[1 ]]
604+ offset = "_i" if size == 1 else f"_i * { size } "
605+ lines .append (f" for (int _i = 0; _i < _n; _i++)" )
606+ lines .append (f" {{ _{ local } _out[_i] = "
607+ f"{ reader .format (f'_{ local } _arr' , offset )} ; }}" )
580608 elif elem == "IntPtr" :
581609 lines .append (f" for (int _i = 0; _i < _n; _i++)" )
582610 lines .append (f" {{ _{ local } _out[_i] = Marshal.ReadIntPtr(_{ local } _arr, _i * IntPtr.Size); }}" )
@@ -623,6 +651,11 @@ def _copy(indent: str) -> list[str]:
623651 stride = strategy .split (":" , 1 )[1 ]
624652 out .append (f"{ indent } for (int _i = 0; _i < _n; _i++)" )
625653 out .append (f"{ indent } {{ _out[_i] = IntPtr.Add(_p, _i * { stride } ); }}" )
654+ elif strategy .startswith ("ScalarArray:" ):
655+ size , reader = _SCALAR_ELEM_READER [strategy .split (":" , 1 )[1 ]]
656+ offset = "_i" if size == 1 else f"_i * { size } "
657+ out .append (f"{ indent } for (int _i = 0; _i < _n; _i++)" )
658+ out .append (f"{ indent } {{ _out[_i] = { reader .format ('_p' , offset )} ; }}" )
626659 else :
627660 out .append (f"{ indent } for (int _i = 0; _i < _n; _i++)" )
628661 out .append (f"{ indent } {{ _out[_i] = Marshal.ReadIntPtr(_p, _i * IntPtr.Size); }}" )
0 commit comments