mirror of
https://github.com/python/cpython.git
synced 2025-08-04 17:08:35 +00:00
gh-133583: Add support for fixed size unsigned integers in argument parsing (GH-133584)
* Add Argument Clinic converters: uint8, uint16, uint32, uint64. * Add private C API: _PyLong_UInt8_Converter(), _PyLong_UInt16_Converter(), _PyLong_UInt32_Converter(), _PyLong_UInt64_Converter().
This commit is contained in:
parent
3224b99872
commit
4c914e7a36
7 changed files with 87 additions and 93 deletions
|
@ -17,6 +17,54 @@ from libclinic.converter import (
|
|||
TypeSet = set[bltns.type[object]]
|
||||
|
||||
|
||||
class BaseUnsignedIntConverter(CConverter):
|
||||
|
||||
def use_converter(self) -> None:
|
||||
if self.converter:
|
||||
self.add_include('pycore_long.h',
|
||||
f'{self.converter}()')
|
||||
|
||||
def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None:
|
||||
if not limited_capi:
|
||||
return super().parse_arg(argname, displayname, limited_capi=limited_capi)
|
||||
return self.format_code("""
|
||||
{{{{
|
||||
Py_ssize_t _bytes = PyLong_AsNativeBytes({argname}, &{paramname}, sizeof({type}),
|
||||
Py_ASNATIVEBYTES_NATIVE_ENDIAN |
|
||||
Py_ASNATIVEBYTES_ALLOW_INDEX |
|
||||
Py_ASNATIVEBYTES_REJECT_NEGATIVE |
|
||||
Py_ASNATIVEBYTES_UNSIGNED_BUFFER);
|
||||
if (_bytes < 0) {{{{
|
||||
goto exit;
|
||||
}}}}
|
||||
if ((size_t)_bytes > sizeof({type})) {{{{
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"Python int too large for C {type}");
|
||||
goto exit;
|
||||
}}}}
|
||||
}}}}
|
||||
""",
|
||||
argname=argname,
|
||||
type=self.type)
|
||||
|
||||
|
||||
class uint8_converter(BaseUnsignedIntConverter):
|
||||
type = "uint8_t"
|
||||
converter = '_PyLong_UInt8_Converter'
|
||||
|
||||
class uint16_converter(BaseUnsignedIntConverter):
|
||||
type = "uint16_t"
|
||||
converter = '_PyLong_UInt16_Converter'
|
||||
|
||||
class uint32_converter(BaseUnsignedIntConverter):
|
||||
type = "uint32_t"
|
||||
converter = '_PyLong_UInt32_Converter'
|
||||
|
||||
class uint64_converter(BaseUnsignedIntConverter):
|
||||
type = "uint64_t"
|
||||
converter = '_PyLong_UInt64_Converter'
|
||||
|
||||
|
||||
class bool_converter(CConverter):
|
||||
type = 'int'
|
||||
default_type = bool
|
||||
|
@ -211,29 +259,7 @@ class short_converter(CConverter):
|
|||
return super().parse_arg(argname, displayname, limited_capi=limited_capi)
|
||||
|
||||
|
||||
def format_inline_unsigned_int_converter(self: CConverter, argname: str) -> str:
|
||||
return self.format_code("""
|
||||
{{{{
|
||||
Py_ssize_t _bytes = PyLong_AsNativeBytes({argname}, &{paramname}, sizeof({type}),
|
||||
Py_ASNATIVEBYTES_NATIVE_ENDIAN |
|
||||
Py_ASNATIVEBYTES_ALLOW_INDEX |
|
||||
Py_ASNATIVEBYTES_REJECT_NEGATIVE |
|
||||
Py_ASNATIVEBYTES_UNSIGNED_BUFFER);
|
||||
if (_bytes < 0) {{{{
|
||||
goto exit;
|
||||
}}}}
|
||||
if ((size_t)_bytes > sizeof({type})) {{{{
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"Python int too large for C {type}");
|
||||
goto exit;
|
||||
}}}}
|
||||
}}}}
|
||||
""",
|
||||
argname=argname,
|
||||
type=self.type)
|
||||
|
||||
|
||||
class unsigned_short_converter(CConverter):
|
||||
class unsigned_short_converter(BaseUnsignedIntConverter):
|
||||
type = 'unsigned short'
|
||||
default_type = int
|
||||
c_ignored_default = "0"
|
||||
|
@ -244,11 +270,6 @@ class unsigned_short_converter(CConverter):
|
|||
else:
|
||||
self.converter = '_PyLong_UnsignedShort_Converter'
|
||||
|
||||
def use_converter(self) -> None:
|
||||
if self.converter == '_PyLong_UnsignedShort_Converter':
|
||||
self.add_include('pycore_long.h',
|
||||
'_PyLong_UnsignedShort_Converter()')
|
||||
|
||||
def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None:
|
||||
if self.format_unit == 'H':
|
||||
return self.format_code("""
|
||||
|
@ -258,9 +279,7 @@ class unsigned_short_converter(CConverter):
|
|||
}}}}
|
||||
""",
|
||||
argname=argname)
|
||||
if not limited_capi:
|
||||
return super().parse_arg(argname, displayname, limited_capi=limited_capi)
|
||||
return format_inline_unsigned_int_converter(self, argname)
|
||||
return super().parse_arg(argname, displayname, limited_capi=limited_capi)
|
||||
|
||||
|
||||
@add_legacy_c_converter('C', accept={str})
|
||||
|
@ -311,7 +330,7 @@ class int_converter(CConverter):
|
|||
return super().parse_arg(argname, displayname, limited_capi=limited_capi)
|
||||
|
||||
|
||||
class unsigned_int_converter(CConverter):
|
||||
class unsigned_int_converter(BaseUnsignedIntConverter):
|
||||
type = 'unsigned int'
|
||||
default_type = int
|
||||
c_ignored_default = "0"
|
||||
|
@ -322,11 +341,6 @@ class unsigned_int_converter(CConverter):
|
|||
else:
|
||||
self.converter = '_PyLong_UnsignedInt_Converter'
|
||||
|
||||
def use_converter(self) -> None:
|
||||
if self.converter == '_PyLong_UnsignedInt_Converter':
|
||||
self.add_include('pycore_long.h',
|
||||
'_PyLong_UnsignedInt_Converter()')
|
||||
|
||||
def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None:
|
||||
if self.format_unit == 'I':
|
||||
return self.format_code("""
|
||||
|
@ -336,9 +350,7 @@ class unsigned_int_converter(CConverter):
|
|||
}}}}
|
||||
""",
|
||||
argname=argname)
|
||||
if not limited_capi:
|
||||
return super().parse_arg(argname, displayname, limited_capi=limited_capi)
|
||||
return format_inline_unsigned_int_converter(self, argname)
|
||||
return super().parse_arg(argname, displayname, limited_capi=limited_capi)
|
||||
|
||||
|
||||
class long_converter(CConverter):
|
||||
|
@ -359,7 +371,7 @@ class long_converter(CConverter):
|
|||
return super().parse_arg(argname, displayname, limited_capi=limited_capi)
|
||||
|
||||
|
||||
class unsigned_long_converter(CConverter):
|
||||
class unsigned_long_converter(BaseUnsignedIntConverter):
|
||||
type = 'unsigned long'
|
||||
default_type = int
|
||||
c_ignored_default = "0"
|
||||
|
@ -370,11 +382,6 @@ class unsigned_long_converter(CConverter):
|
|||
else:
|
||||
self.converter = '_PyLong_UnsignedLong_Converter'
|
||||
|
||||
def use_converter(self) -> None:
|
||||
if self.converter == '_PyLong_UnsignedLong_Converter':
|
||||
self.add_include('pycore_long.h',
|
||||
'_PyLong_UnsignedLong_Converter()')
|
||||
|
||||
def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None:
|
||||
if self.format_unit == 'k':
|
||||
return self.format_code("""
|
||||
|
@ -387,9 +394,7 @@ class unsigned_long_converter(CConverter):
|
|||
argname=argname,
|
||||
bad_argument=self.bad_argument(displayname, 'int', limited_capi=limited_capi),
|
||||
)
|
||||
if not limited_capi:
|
||||
return super().parse_arg(argname, displayname, limited_capi=limited_capi)
|
||||
return format_inline_unsigned_int_converter(self, argname)
|
||||
return super().parse_arg(argname, displayname, limited_capi=limited_capi)
|
||||
|
||||
|
||||
class long_long_converter(CConverter):
|
||||
|
@ -410,7 +415,7 @@ class long_long_converter(CConverter):
|
|||
return super().parse_arg(argname, displayname, limited_capi=limited_capi)
|
||||
|
||||
|
||||
class unsigned_long_long_converter(CConverter):
|
||||
class unsigned_long_long_converter(BaseUnsignedIntConverter):
|
||||
type = 'unsigned long long'
|
||||
default_type = int
|
||||
c_ignored_default = "0"
|
||||
|
@ -421,11 +426,6 @@ class unsigned_long_long_converter(CConverter):
|
|||
else:
|
||||
self.converter = '_PyLong_UnsignedLongLong_Converter'
|
||||
|
||||
def use_converter(self) -> None:
|
||||
if self.converter == '_PyLong_UnsignedLongLong_Converter':
|
||||
self.add_include('pycore_long.h',
|
||||
'_PyLong_UnsignedLongLong_Converter()')
|
||||
|
||||
def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None:
|
||||
if self.format_unit == 'K':
|
||||
return self.format_code("""
|
||||
|
@ -438,9 +438,7 @@ class unsigned_long_long_converter(CConverter):
|
|||
argname=argname,
|
||||
bad_argument=self.bad_argument(displayname, 'int', limited_capi=limited_capi),
|
||||
)
|
||||
if not limited_capi:
|
||||
return super().parse_arg(argname, displayname, limited_capi=limited_capi)
|
||||
return format_inline_unsigned_int_converter(self, argname)
|
||||
return super().parse_arg(argname, displayname, limited_capi=limited_capi)
|
||||
|
||||
|
||||
class Py_ssize_t_converter(CConverter):
|
||||
|
@ -557,15 +555,11 @@ class slice_index_converter(CConverter):
|
|||
argname=argname)
|
||||
|
||||
|
||||
class size_t_converter(CConverter):
|
||||
class size_t_converter(BaseUnsignedIntConverter):
|
||||
type = 'size_t'
|
||||
converter = '_PyLong_Size_t_Converter'
|
||||
c_ignored_default = "0"
|
||||
|
||||
def use_converter(self) -> None:
|
||||
self.add_include('pycore_long.h',
|
||||
'_PyLong_Size_t_Converter()')
|
||||
|
||||
def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None:
|
||||
if self.format_unit == 'n':
|
||||
return self.format_code("""
|
||||
|
@ -575,9 +569,7 @@ class size_t_converter(CConverter):
|
|||
}}}}
|
||||
""",
|
||||
argname=argname)
|
||||
if not limited_capi:
|
||||
return super().parse_arg(argname, displayname, limited_capi=limited_capi)
|
||||
return format_inline_unsigned_int_converter(self, argname)
|
||||
return super().parse_arg(argname, displayname, limited_capi=limited_capi)
|
||||
|
||||
|
||||
class fildes_converter(CConverter):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue