From 290bbcf333679ffa057d57d1b540608e3bec8ada Mon Sep 17 00:00:00 2001 From: Mark Rowe Date: Thu, 17 Jul 2025 11:32:16 -0700 Subject: Specify fixed underlying types for enums exposed by core This allows a few widely-used enums to be shrunk from 4 bytes to 1 byte, improving packing when they're used as struct members. To remain compatible with C, we follow CoreFoundation's approach and use a macro when defining the enum: ``` #if defined(__cplusplus) || __has_extension(c_fixed_enum) #define BN_ENUM(type, name) enum name : type #else #define BN_ENUM(type, name) typedef type name; enum #endif BN_ENUM(uint8_t, SomeEnum) { ... } ``` In C++ and C23 this will expand to an enum with a fixed underlying type. In older C language versions, this will result in the enum type being a typedef of the underlying type, with an unnamed enum providing the enum values. Minor changes were needed within the Python bindings to update places that made assumptions about the underlying type of the enums. --- python/generator.cpp | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) (limited to 'python/generator.cpp') diff --git a/python/generator.cpp b/python/generator.cpp index 6dd983b4..45ca1e4a 100644 --- a/python/generator.cpp +++ b/python/generator.cpp @@ -363,7 +363,23 @@ int main(int argc, char* argv[]) if (name.size() > 2 && name.substr(0, 2) == "BN") name = name.substr(2); - fprintf(out, "%sEnum = ctypes.c_int\n", name.c_str()); + const char* ctypesType = nullptr; + switch (i.second->GetWidth()) + { + case 1: + ctypesType = i.second->IsSigned() ? "ctypes.c_int8" : "ctypes.c_uint8"; + break; + case 2: + ctypesType = i.second->IsSigned() ? "ctypes.c_int16" : "ctypes.c_uint16"; + break; + case 4: + ctypesType = i.second->IsSigned() ? "ctypes.c_int32" : "ctypes.c_uint32"; + break; + default: + ctypesType = i.second->IsSigned() ? "ctypes.c_int64" : "ctypes.c_uint64"; + break; + } + fprintf(out, "%sEnum = %s\n", name.c_str(), ctypesType); fprintf(enums, "\n\nclass %s(enum.IntEnum):\n", name.c_str()); for (auto& j : i.second->GetEnumeration()->GetMembers()) @@ -465,9 +481,10 @@ int main(int argc, char* argv[]) // Check for a string result, these will be automatically wrapped to free the string // memory and return a Python string - bool stringResult = (i.second->GetChildType()->GetClass() == PointerTypeClass) - && (i.second->GetChildType()->GetChildType()->GetWidth() == 1) - && (i.second->GetChildType()->GetChildType()->IsSigned()); + bool stringResult = i.second->GetChildType()->GetClass() == PointerTypeClass + && i.second->GetChildType()->GetChildType()->GetClass() == IntegerTypeClass + && i.second->GetChildType()->GetChildType()->GetWidth() == 1 + && i.second->GetChildType()->GetChildType()->IsSigned(); // Pointer returns will be automatically wrapped to return None on null pointer bool pointerResult = (i.second->GetChildType()->GetClass() == PointerTypeClass); // Enum returns will automatically cast to the enum type -- cgit v1.3.1