From 39b43461110e509aa88c76d0bce025434233780b Mon Sep 17 00:00:00 2001 From: Pavel Koneski Date: Sat, 22 Feb 2025 13:00:37 -0800 Subject: [PATCH] Typecode cleanup --- src/core/IronPython.Modules/ModuleOps.cs | 423 +++++++++--------- .../IronPython.Modules/_ctypes/SimpleType.cs | 96 ++-- src/core/IronPython.Modules/_struct.cs | 40 +- src/core/IronPython.Modules/array.cs | 29 +- .../IronPython/Runtime/ConversionWrappers.cs | 14 +- src/core/IronPython/Runtime/TypecodeOps.cs | 49 +- 6 files changed, 319 insertions(+), 332 deletions(-) diff --git a/src/core/IronPython.Modules/ModuleOps.cs b/src/core/IronPython.Modules/ModuleOps.cs index 7050a46e8..9e3336a4d 100644 --- a/src/core/IronPython.Modules/ModuleOps.cs +++ b/src/core/IronPython.Modules/ModuleOps.cs @@ -231,130 +231,175 @@ public static bool CheckFunctionId(CTypes._CFuncPtr func, int id) { return func.Id == id; } - public static IntPtr GetWCharPointer(object value) { - if (value is string strVal) { - return Marshal.StringToCoTaskMemUni(strVal); - } + public static Bytes IntPtrToBytes(IntPtr ptr) { + // TODO: optimize this? + var str = Marshal.PtrToStringAnsi(ptr); + if (str is null) return null; + return Bytes.Make(str.MakeByteArray()); + } + + public static object IntPtrToObject(IntPtr address) { + GCHandle handle = GCHandle.FromIntPtr(address); + object res = handle.Target; + handle.Free(); + return res; + } - if (value == null) { - return IntPtr.Zero; + public static byte GetBoolean(object value, object type) { + if (value is bool) { + return ((bool)value) ? (byte)1 : (byte)0; + } else if (value is int) { + return ((int)value) != 0 ? (byte)1 : (byte)0; } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { - return GetWCharPointer(asParam); + return GetBoolean(asParam, type); } - throw PythonOps.TypeErrorForTypeMismatch("wchar pointer", value); + throw PythonOps.TypeErrorForTypeMismatch("bool", value); } - public static IntPtr GetBSTR(object value) { - if (value is string strVal) { - return Marshal.StringToBSTR(strVal); + public static int GetVariantBool(object value, object type) { + return Converter.ConvertToBoolean(value) ? 1 : 0; + } + + public static byte GetChar(object value, object type) { + // TODO: .NET interop? + if (value is Bytes bytes && bytes.Count == 1) { + return ((IList)bytes)[0]; + } + if (value is ByteArray bytearray && bytearray.Count == 1) { + return ((IList)bytearray)[0]; + } + if (value is int i) { + try { + return checked((byte)i); + } catch (OverflowException) { + throw PythonOps.TypeError("one character bytes, bytearray or integer expected"); + } } + if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { + return GetChar(asParam, type); + } - if (value == null) { - return IntPtr.Zero; + throw PythonOps.TypeError("one character bytes, bytearray or integer expected"); + } + + public static char GetWChar(object value, object type) { + if (value is string strVal) { + if (strVal.Length != 1) throw PythonOps.TypeError("one character unicode string expected"); + return strVal[0]; } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { - return GetBSTR(asParam); + return GetWChar(asParam, type); } - throw PythonOps.TypeErrorForTypeMismatch("BSTR", value); + throw PythonOps.TypeErrorForBadInstance("unicode string expected instead of {0} instance", value); } - public static IntPtr GetCharPointer(object value) { - if (value is Bytes bytes) { - var data = bytes.UnsafeByteArray; - var ptr = Marshal.AllocCoTaskMem(data.Length + 1); - Marshal.Copy(data, 0, ptr, data.Length); - Marshal.WriteByte(ptr, data.Length, 0); - return ptr; + public static sbyte GetSignedByte(object value, object type) { + if (TryToIntStrict(value, out BigInteger bi)) { + return unchecked((sbyte)(byte)(bi & byte.MaxValue)); } - if (value == null) { - return IntPtr.Zero; + if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { + return GetSignedByte(asParam, type); + } + + throw PythonOps.TypeErrorForTypeMismatch("signed byte", value); + } + + public static byte GetUnsignedByte(object value, object type) { + if (TryToIntStrict(value, out BigInteger bi)) { + return (byte)(bi & byte.MaxValue); } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { - return GetCharPointer(asParam); + return GetUnsignedByte(asParam, type); } - throw PythonOps.TypeErrorForTypeMismatch("char pointer", value); + throw PythonOps.TypeErrorForTypeMismatch("unsigned byte", value); } - public static Bytes IntPtrToBytes(IntPtr ptr) { - // TODO: optimize this? - var str = Marshal.PtrToStringAnsi(ptr); - if (str is null) return null; - return Bytes.Make(str.MakeByteArray()); - } - public static IntPtr GetPointer(object value) { - if (value == null) { - return IntPtr.Zero; + public static short GetSignedShort(object value, object type) { + if (TryToIntStrict(value, out BigInteger bi)) { + return unchecked((short)(ushort)(bi & ushort.MaxValue)); } - if (value is int iVal) { - return new IntPtr(iVal); + if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { + return GetSignedShort(asParam, type); } - if (value is BigInteger bigVal) { - if(bigVal > long.MaxValue) { - bigVal = -1; - } - return new IntPtr((long)bigVal); - } + throw PythonOps.TypeErrorForTypeMismatch("signed short", value); + } - if (value is long lVal) { - return new IntPtr(lVal); + public static ushort GetUnsignedShort(object value, object type) { + if (TryToIntStrict(value, out BigInteger bi)) { + return (ushort)(bi & ushort.MaxValue); } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { - return GetPointer(asParam); + return GetUnsignedShort(asParam, type); } - if (value is CTypes.SimpleCData sd) { - CTypes.SimpleType simpType = (CTypes.SimpleType)sd.NativeType; - if (simpType._type == CTypes.SimpleTypeKind.WCharPointer || - simpType._type == CTypes.SimpleTypeKind.CharPointer) { - return sd.UnsafeAddress; - } else if (simpType._type == CTypes.SimpleTypeKind.Pointer) { - return sd.MemHolder.ReadIntPtr(0); - } + throw PythonOps.TypeErrorForTypeMismatch("unsigned short", value); + } + + public static int GetSignedInt(object value, object type) { + if (TryToIntStrict(value, out BigInteger bi)) { + return unchecked((int)(uint)(bi & uint.MaxValue)); } - if (value is CTypes._Array arr) { - return arr.UnsafeAddress; + + if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { + return GetSignedInt(asParam, type); } - if (value is CTypes._CFuncPtr func) { - return func.UnsafeAddress; + throw PythonOps.TypeErrorForTypeMismatch("signed int", value); + } + + public static uint GetUnsignedInt(object value, object type) { + if (TryToIntStrict(value, out BigInteger bi)) { + return (uint)(bi & uint.MaxValue); } - if (value is CTypes.Pointer pointer) { - return pointer.UnsafeAddress; + if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { + return GetUnsignedInt(asParam, type); } - throw PythonOps.TypeErrorForTypeMismatch("pointer", value); + throw PythonOps.TypeErrorForTypeMismatch("unsigned int", value); } - public static IntPtr GetInterfacePointer(IntPtr self, int offset) { - var vtable = Marshal.ReadIntPtr(self); - return Marshal.ReadIntPtr(vtable, offset * IntPtr.Size); + public static long GetSignedLong(object value, object type) { + if (TryToIntStrict(value, out BigInteger bi)) { + return unchecked((long)(ulong)(bi & uint.MaxValue)); + } + + if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { + return GetSignedLong(asParam, type); + } + + throw PythonOps.TypeErrorForTypeMismatch("signed long", value); } - public static IntPtr GetObject(object value) { - GCHandle handle = GCHandle.Alloc(value); + public static ulong GetUnsignedLong(object value, object type) { + if (TryToIntStrict(value, out BigInteger bi)) { + return (ulong)(bi & uint.MaxValue); + } - // TODO: Need to free the handle at some point - return GCHandle.ToIntPtr(handle); + if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { + return GetUnsignedLong(asParam, type); + } + + throw PythonOps.TypeErrorForTypeMismatch("unsigned long", value); } public static long GetSignedLongLong(object value, object type) { - if (PythonOps.TryToInt(value, out BigInteger bi)) { + if (TryToIntStrict(value, out BigInteger bi)) { return unchecked((long)(ulong)(bi & ulong.MaxValue)); } @@ -366,7 +411,7 @@ public static long GetSignedLongLong(object value, object type) { } public static ulong GetUnsignedLongLong(object value, object type) { - if (PythonOps.TryToInt(value, out BigInteger bi)) { + if (TryToIntStrict(value, out BigInteger bi)) { return (ulong)(bi & ulong.MaxValue); } @@ -377,33 +422,15 @@ public static ulong GetUnsignedLongLong(object value, object type) { throw PythonOps.TypeErrorForTypeMismatch("unsigned long long", value); } - public static double GetDouble(object value, object type) { - if (value is double) { - return (double)value; - } else if (value is float) { - return (float)value; - } else if (value is int) { - return (double)(int)value; - } else if (value is BigInteger) { - return (double)((BigInteger)value).ToFloat64(); - } - - if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { - return GetDouble(asParam, type); - } - - return Converter.ConvertToDouble(value); - } - public static float GetSingle(object value, object type) { - if (value is double) { - return (float)(double)value; - } else if (value is float) { - return (float)value; - } else if (value is int) { - return (float)(int)value; - } else if (value is BigInteger) { - return (float)((BigInteger)value).ToFloat64(); + if (value is double d) { + return (float)d; + } else if (value is float f) { + return f; + } else if (value is int i) { + return (float)i; + } else if (value is BigInteger bi) { + return (float)bi.ToFloat64(); } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { @@ -413,22 +440,22 @@ public static float GetSingle(object value, object type) { return (float)Converter.ConvertToDouble(value); } - public static long GetDoubleBits(object value) { - if (value is double) { - return BitConverter.ToInt64(BitConverter.GetBytes((double)value), 0); - } else if (value is float) { - return BitConverter.ToInt64(BitConverter.GetBytes((float)value), 0); - } else if (value is int) { - return BitConverter.ToInt64(BitConverter.GetBytes((double)(int)value), 0); - } else if (value is BigInteger) { - return BitConverter.ToInt64(BitConverter.GetBytes((double)((BigInteger)value).ToFloat64()), 0); + public static double GetDouble(object value, object type) { + if (value is double d) { + return d; + } else if (value is float f) { + return (double)f; + } else if (value is int i) { + return (double)i; + } else if (value is BigInteger bi) { + return bi.ToFloat64(); } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { - return GetDoubleBits(asParam); + return GetDouble(asParam, type); } - return BitConverter.ToInt64(BitConverter.GetBytes(Converter.ConvertToDouble(value)), 0); + return Converter.ConvertToDouble(value); } public static int GetSingleBits(object value) { @@ -449,163 +476,137 @@ public static int GetSingleBits(object value) { return BitConverter.ToInt32(BitConverter.GetBytes((float)Converter.ConvertToDouble(value)), 0); } - public static int GetSignedLong(object value, object type) { - if (TryToIntStrict(value, out BigInteger bi)) { - return unchecked((int)(uint)(bi & uint.MaxValue)); + public static long GetDoubleBits(object value) { + if (value is double) { + return BitConverter.ToInt64(BitConverter.GetBytes((double)value), 0); + } else if (value is float) { + return BitConverter.ToInt64(BitConverter.GetBytes((float)value), 0); + } else if (value is int) { + return BitConverter.ToInt64(BitConverter.GetBytes((double)(int)value), 0); + } else if (value is BigInteger) { + return BitConverter.ToInt64(BitConverter.GetBytes((double)((BigInteger)value).ToFloat64()), 0); } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { - return GetSignedLong(asParam, type); + return GetDoubleBits(asParam); } - throw PythonOps.TypeErrorForTypeMismatch("signed long", value); + return BitConverter.ToInt64(BitConverter.GetBytes(Converter.ConvertToDouble(value)), 0); } - public static uint GetUnsignedLong(object value, object type) { - if (PythonOps.TryToInt(value, out BigInteger bi)) { - return (uint)(bi & uint.MaxValue); - } - - if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { - return GetUnsignedLong(asParam, type); - } + public static IntPtr GetObject(object value) { + GCHandle handle = GCHandle.Alloc(value); - throw PythonOps.TypeErrorForTypeMismatch("unsigned long", value); + // TODO: Need to free the handle at some point + return GCHandle.ToIntPtr(handle); } - public static uint GetUnsignedInt(object value, object type) { - if (TryToIntStrict(value, out BigInteger bi)) { - return (uint)(bi & uint.MaxValue); + public static IntPtr GetPointer(object value) { + if (value == null) { + return IntPtr.Zero; } - if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { - return GetUnsignedInt(asParam, type); + if (value is int iVal) { + return new IntPtr(iVal); } - throw PythonOps.TypeErrorForTypeMismatch("unsigned int", value); - } + if (value is BigInteger bigVal) { + if(bigVal > long.MaxValue) { + bigVal = -1; + } + return new IntPtr((long)bigVal); + } - public static int GetSignedInt(object value, object type) { - if (TryToIntStrict(value, out BigInteger bi)) { - return unchecked((int)(bi & uint.MaxValue)); + if (value is long lVal) { + return new IntPtr(lVal); } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { - return GetSignedInt(asParam, type); + return GetPointer(asParam); } - throw PythonOps.TypeErrorForTypeMismatch("signed int", value); - } - - public static ushort GetUnsignedShort(object value, object type) { - if (PythonOps.TryToInt(value, out BigInteger bi)) { - return (ushort)(bi & ushort.MaxValue); + if (value is CTypes.SimpleCData sd) { + CTypes.SimpleType simpType = (CTypes.SimpleType)sd.NativeType; + if (simpType._type == CTypes.SimpleTypeKind.WCharPointer || + simpType._type == CTypes.SimpleTypeKind.CharPointer) { + return sd.UnsafeAddress; + } else if (simpType._type == CTypes.SimpleTypeKind.Pointer) { + return sd.MemHolder.ReadIntPtr(0); + } } - if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { - return GetUnsignedShort(asParam, type); + if (value is CTypes._Array arr) { + return arr.UnsafeAddress; } - throw PythonOps.TypeErrorForTypeMismatch("unsigned short", value); - } - - public static short GetSignedShort(object value, object type) { - if (PythonOps.TryToInt(value, out BigInteger bi)) { - return unchecked((short)(ushort)(bi & ushort.MaxValue)); + if (value is CTypes._CFuncPtr func) { + return func.UnsafeAddress; } - if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { - return GetSignedShort(asParam, type); + if (value is CTypes.Pointer pointer) { + return pointer.UnsafeAddress; } - throw PythonOps.TypeErrorForTypeMismatch("signed short", value); + throw PythonOps.TypeErrorForTypeMismatch("pointer", value); } - public static int GetVariantBool(object value, object type) { - return Converter.ConvertToBoolean(value) ? 1 : 0; + public static IntPtr GetInterfacePointer(IntPtr self, int offset) { + var vtable = Marshal.ReadIntPtr(self); + return Marshal.ReadIntPtr(vtable, offset * IntPtr.Size); } - public static byte GetUnsignedByte(object value, object type) { - if (PythonOps.TryToInt(value, out BigInteger bi)) { - return (byte)(bi & byte.MaxValue); - } - - if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { - return GetUnsignedByte(asParam, type); + public static IntPtr GetCharPointer(object value) { + if (value is Bytes bytes) { + var data = bytes.UnsafeByteArray; + var ptr = Marshal.AllocCoTaskMem(data.Length + 1); + Marshal.Copy(data, 0, ptr, data.Length); + Marshal.WriteByte(ptr, data.Length, 0); + return ptr; } - throw PythonOps.TypeErrorForTypeMismatch("unsigned byte", value); - } - - public static sbyte GetSignedByte(object value, object type) { - if (PythonOps.TryToInt(value, out BigInteger bi)) { - return unchecked((sbyte)(byte)(bi & byte.MaxValue)); + if (value == null) { + return IntPtr.Zero; } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { - return GetSignedByte(asParam, type); + return GetCharPointer(asParam); } - throw PythonOps.TypeErrorForTypeMismatch("signed byte", value); + throw PythonOps.TypeErrorForTypeMismatch("char pointer", value); } - - public static byte GetBoolean(object value, object type) { - if (value is bool) { - return ((bool)value) ? (byte)1 : (byte)0; - } else if (value is int) { - return ((int)value) != 0 ? (byte)1 : (byte)0; - } - - if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { - return GetBoolean(asParam, type); + public static IntPtr GetWCharPointer(object value) { + if (value is string strVal) { + return Marshal.StringToCoTaskMemUni(strVal); } - throw PythonOps.TypeErrorForTypeMismatch("bool", value); - } - public static byte GetChar(object value, object type) { - // TODO: .NET interop? - if (value is Bytes bytes && bytes.Count == 1) { - return ((IList)bytes)[0]; - } - if (value is ByteArray bytearray && bytearray.Count == 1) { - return ((IList)bytearray)[0]; - } - if (value is int i) { - try { - return checked((byte)i); - } catch (OverflowException) { - throw PythonOps.TypeError("one character bytes, bytearray or integer expected"); - } + if (value == null) { + return IntPtr.Zero; } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { - return GetChar(asParam, type); + return GetWCharPointer(asParam); } - throw PythonOps.TypeError("one character bytes, bytearray or integer expected"); + throw PythonOps.TypeErrorForTypeMismatch("wchar pointer", value); } - public static char GetWChar(object value, object type) { + public static IntPtr GetBSTR(object value) { if (value is string strVal) { - if (strVal.Length != 1) throw PythonOps.TypeError("one character unicode string expected"); - return strVal[0]; + return Marshal.StringToBSTR(strVal); } - if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { - return GetWChar(asParam, type); - } - throw PythonOps.TypeErrorForBadInstance("unicode string expected instead of {0} instance", value); - } + if (value == null) { + return IntPtr.Zero; + } - public static object IntPtrToObject(IntPtr address) { - GCHandle handle = GCHandle.FromIntPtr(address); + if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { + return GetBSTR(asParam); + } - object res = handle.Target; - handle.Free(); - return res; + throw PythonOps.TypeErrorForTypeMismatch("BSTR", value); } internal static bool TryToIntStrict(object value, out BigInteger bi) { @@ -619,11 +620,11 @@ internal static bool TryToIntStrict(object value, out BigInteger bi) { } internal static bool IsFloatingPoint(object value) - => value is double or float -#if NETCOREAPP - or Half +#if NET6_0_OR_GREATER + => value is double or float or Half; +#else + => value is double or float; #endif - ; } } #endif diff --git a/src/core/IronPython.Modules/_ctypes/SimpleType.cs b/src/core/IronPython.Modules/_ctypes/SimpleType.cs index 2af7309c2..03504a09d 100644 --- a/src/core/IronPython.Modules/_ctypes/SimpleType.cs +++ b/src/core/IronPython.Modules/_ctypes/SimpleType.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Numerics; using System.Reflection; using System.Reflection.Emit; @@ -13,7 +14,6 @@ using System.Runtime.InteropServices; using IronPython.Runtime; -using IronPython.Runtime.Exceptions; using IronPython.Runtime.Operations; using IronPython.Runtime.Types; @@ -170,25 +170,25 @@ public SimpleCData in_dll(CodeContext/*!*/ context, object library, string name) int INativeType.Size { get { switch (_type) { + case SimpleTypeKind.Boolean: case SimpleTypeKind.Char: case SimpleTypeKind.SignedByte: case SimpleTypeKind.UnsignedByte: - case SimpleTypeKind.Boolean: return 1; + case SimpleTypeKind.VariantBool: + case SimpleTypeKind.WChar: case SimpleTypeKind.SignedShort: case SimpleTypeKind.UnsignedShort: - case SimpleTypeKind.WChar: - case SimpleTypeKind.VariantBool: return 2; case SimpleTypeKind.SignedInt: case SimpleTypeKind.UnsignedInt: - case SimpleTypeKind.UnsignedLong: case SimpleTypeKind.SignedLong: + case SimpleTypeKind.UnsignedLong: case SimpleTypeKind.Single: return 4; - case SimpleTypeKind.Double: case SimpleTypeKind.UnsignedLongLong: case SimpleTypeKind.SignedLongLong: + case SimpleTypeKind.Double: return 8; case SimpleTypeKind.Object: case SimpleTypeKind.Pointer: @@ -211,21 +211,21 @@ object INativeType.GetValue(MemoryHolder/*!*/ owner, object readingFrom, int off object res; switch (_type) { case SimpleTypeKind.Boolean: res = owner.ReadByte(offset) != 0 ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False; break; + case SimpleTypeKind.VariantBool: res = owner.ReadInt16(offset, _swap) != 0 ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False; break; case SimpleTypeKind.Char: res = Bytes.FromByte(owner.ReadByte(offset)); break; + case SimpleTypeKind.WChar: res = new string((char)owner.ReadInt16(offset), 1); break; case SimpleTypeKind.SignedByte: res = GetIntReturn((int)(sbyte)owner.ReadByte(offset)); break; case SimpleTypeKind.UnsignedByte: res = GetIntReturn((int)owner.ReadByte(offset)); break; case SimpleTypeKind.SignedShort: res = GetIntReturn(owner.ReadInt16(offset, _swap)); break; - case SimpleTypeKind.WChar: res = new string((char)owner.ReadInt16(offset), 1); break; case SimpleTypeKind.UnsignedShort: res = GetIntReturn((ushort)owner.ReadInt16(offset, _swap)); break; - case SimpleTypeKind.VariantBool: res = owner.ReadInt16(offset, _swap) != 0 ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False; break; case SimpleTypeKind.SignedInt: res = GetIntReturn(owner.ReadInt32(offset, _swap)); break; case SimpleTypeKind.UnsignedInt: res = GetIntReturn((uint)owner.ReadInt32(offset, _swap)); break; - case SimpleTypeKind.UnsignedLong: res = GetIntReturn((uint)owner.ReadInt32(offset, _swap)); break; case SimpleTypeKind.SignedLong: res = GetIntReturn(owner.ReadInt32(offset, _swap)); break; + case SimpleTypeKind.UnsignedLong: res = GetIntReturn((uint)owner.ReadInt32(offset, _swap)); break; + case SimpleTypeKind.SignedLongLong: res = GetIntReturn(owner.ReadInt64(offset, _swap)); break; + case SimpleTypeKind.UnsignedLongLong: res = GetIntReturn((ulong)owner.ReadInt64(offset, _swap)); break; case SimpleTypeKind.Single: res = GetSingleReturn(owner.ReadInt32(offset, _swap)); break; case SimpleTypeKind.Double: res = GetDoubleReturn(owner.ReadInt64(offset, _swap)); break; - case SimpleTypeKind.UnsignedLongLong: res = GetIntReturn((ulong)owner.ReadInt64(offset, _swap)); break; - case SimpleTypeKind.SignedLongLong: res = GetIntReturn(owner.ReadInt64(offset, _swap)); break; case SimpleTypeKind.Object: res = GetObjectReturn(owner.ReadIntPtr(offset)); break; case SimpleTypeKind.Pointer: res = owner.ReadIntPtr(offset).ToPython(); break; case SimpleTypeKind.CharPointer: res = owner.ReadMemoryHolder(offset).ReadBytes(0); break; @@ -250,21 +250,21 @@ object INativeType.SetValue(MemoryHolder/*!*/ owner, int offset, object value) { switch (_type) { case SimpleTypeKind.Boolean: owner.WriteByte(offset, ModuleOps.GetBoolean(value, this)); break; + case SimpleTypeKind.VariantBool: owner.WriteInt16(offset, unchecked((short)ModuleOps.GetVariantBool(value, this)), _swap); break; case SimpleTypeKind.Char: owner.WriteByte(offset, ModuleOps.GetChar(value, this)); break; + case SimpleTypeKind.WChar: owner.WriteInt16(offset, unchecked((short)ModuleOps.GetWChar(value, this))); break; case SimpleTypeKind.SignedByte: owner.WriteByte(offset, unchecked((byte)ModuleOps.GetSignedByte(value, this))); break; case SimpleTypeKind.UnsignedByte: owner.WriteByte(offset, ModuleOps.GetUnsignedByte(value, this)); break; - case SimpleTypeKind.WChar: owner.WriteInt16(offset, unchecked((short)ModuleOps.GetWChar(value, this))); break; case SimpleTypeKind.SignedShort: owner.WriteInt16(offset, ModuleOps.GetSignedShort(value, this), _swap); break; case SimpleTypeKind.UnsignedShort: owner.WriteInt16(offset, unchecked((short)ModuleOps.GetUnsignedShort(value, this)), _swap); break; - case SimpleTypeKind.VariantBool: owner.WriteInt16(offset, unchecked((short)ModuleOps.GetVariantBool(value, this)), _swap); break; case SimpleTypeKind.SignedInt: owner.WriteInt32(offset, ModuleOps.GetSignedInt(value, this), _swap); break; case SimpleTypeKind.UnsignedInt: owner.WriteInt32(offset, unchecked((int)ModuleOps.GetUnsignedInt(value, this)), _swap); break; + case SimpleTypeKind.SignedLong: owner.WriteInt32(offset, unchecked((int)ModuleOps.GetSignedLong(value, this)), _swap); break; case SimpleTypeKind.UnsignedLong: owner.WriteInt32(offset, unchecked((int)ModuleOps.GetUnsignedLong(value, this)), _swap); break; - case SimpleTypeKind.SignedLong: owner.WriteInt32(offset, ModuleOps.GetSignedLong(value, this), _swap); break; - case SimpleTypeKind.Single: owner.WriteInt32(offset, ModuleOps.GetSingleBits(value), _swap); break; - case SimpleTypeKind.Double: owner.WriteInt64(offset, ModuleOps.GetDoubleBits(value), _swap); break; case SimpleTypeKind.UnsignedLongLong: owner.WriteInt64(offset, unchecked((long)ModuleOps.GetUnsignedLongLong(value, this)), _swap); break; case SimpleTypeKind.SignedLongLong: owner.WriteInt64(offset, ModuleOps.GetSignedLongLong(value, this), _swap); break; + case SimpleTypeKind.Single: owner.WriteInt32(offset, ModuleOps.GetSingleBits(value), _swap); break; + case SimpleTypeKind.Double: owner.WriteInt64(offset, ModuleOps.GetDoubleBits(value), _swap); break; case SimpleTypeKind.Object: owner.WriteIntPtr(offset, ModuleOps.GetObject(value)); break; case SimpleTypeKind.Pointer: owner.WriteIntPtr(offset, ModuleOps.GetPointer(value)); break; case SimpleTypeKind.CharPointer: @@ -286,33 +286,34 @@ object INativeType.SetValue(MemoryHolder/*!*/ owner, int offset, object value) { switch (_type) { case SimpleTypeKind.Boolean: return typeof(bool); + case SimpleTypeKind.VariantBool: + return typeof(short); case SimpleTypeKind.Char: return typeof(byte); + case SimpleTypeKind.WChar: + return typeof(char); case SimpleTypeKind.SignedByte: return typeof(sbyte); case SimpleTypeKind.UnsignedByte: return typeof(byte); case SimpleTypeKind.SignedShort: - case SimpleTypeKind.VariantBool: return typeof(short); case SimpleTypeKind.UnsignedShort: return typeof(ushort); - case SimpleTypeKind.WChar: - return typeof(char); case SimpleTypeKind.SignedInt: case SimpleTypeKind.SignedLong: return typeof(int); case SimpleTypeKind.UnsignedInt: case SimpleTypeKind.UnsignedLong: return typeof(uint); + case SimpleTypeKind.SignedLongLong: + return typeof(long); + case SimpleTypeKind.UnsignedLongLong: + return typeof(ulong); case SimpleTypeKind.Single: return typeof(float); case SimpleTypeKind.Double: return typeof(double); - case SimpleTypeKind.UnsignedLongLong: - return typeof(ulong); - case SimpleTypeKind.SignedLongLong: - return typeof(long); case SimpleTypeKind.Object: return typeof(IntPtr); case SimpleTypeKind.Pointer: @@ -361,21 +362,21 @@ MarshalCleanup INativeType.EmitMarshalling(ILGenerator/*!*/ method, LocalOrArg a } switch (_type) { case SimpleTypeKind.Boolean: + case SimpleTypeKind.VariantBool: case SimpleTypeKind.Char: + case SimpleTypeKind.WChar: case SimpleTypeKind.SignedByte: case SimpleTypeKind.UnsignedByte: case SimpleTypeKind.SignedShort: case SimpleTypeKind.UnsignedShort: - case SimpleTypeKind.WChar: case SimpleTypeKind.SignedInt: case SimpleTypeKind.UnsignedInt: - case SimpleTypeKind.UnsignedLong: case SimpleTypeKind.SignedLong: + case SimpleTypeKind.UnsignedLong: + case SimpleTypeKind.SignedLongLong: + case SimpleTypeKind.UnsignedLongLong: case SimpleTypeKind.Single: case SimpleTypeKind.Double: - case SimpleTypeKind.UnsignedLongLong: - case SimpleTypeKind.SignedLongLong: - case SimpleTypeKind.VariantBool: constantPool.Add(this); method.Emit(OpCodes.Ldarg, constantPoolArgument); method.Emit(OpCodes.Ldc_I4, constantPool.Count - 1); @@ -608,16 +609,16 @@ private Type GetPythonTypeWorker() { void INativeType.EmitReverseMarshalling(ILGenerator method, LocalOrArg value, List constantPool, int constantPoolArgument) { value.Emit(method); switch (_type) { + case SimpleTypeKind.VariantBool: case SimpleTypeKind.SignedByte: case SimpleTypeKind.UnsignedByte: case SimpleTypeKind.SignedShort: case SimpleTypeKind.UnsignedShort: - case SimpleTypeKind.VariantBool: method.Emit(OpCodes.Conv_I4); break; + case SimpleTypeKind.Boolean: case SimpleTypeKind.SignedInt: case SimpleTypeKind.SignedLong: - case SimpleTypeKind.Boolean: break; case SimpleTypeKind.Single: method.Emit(OpCodes.Conv_R8); @@ -626,11 +627,11 @@ void INativeType.EmitReverseMarshalling(ILGenerator method, LocalOrArg value, Li break; case SimpleTypeKind.UnsignedInt: case SimpleTypeKind.UnsignedLong: + case SimpleTypeKind.UnsignedLongLong: EmitUIntToObject(method, value); break; - case SimpleTypeKind.UnsignedLongLong: case SimpleTypeKind.SignedLongLong: - EmitXInt64ToObject(method, value); + EmitInt64ToObject(method, value); break; case SimpleTypeKind.Object: method.Emit(OpCodes.Call, typeof(ModuleOps).GetMethod(nameof(ModuleOps.IntPtrToObject))); @@ -685,7 +686,7 @@ void INativeType.EmitReverseMarshalling(ILGenerator method, LocalOrArg value, Li method.MarkLabel(notNull); method.Emit(OpCodes.Ldloc, tmpLocal); - EmitXInt64ToObject(method, new Local(tmpLocal)); + EmitInt64ToObject(method, new Local(tmpLocal)); } method.MarkLabel(done); @@ -710,13 +711,15 @@ void INativeType.EmitReverseMarshalling(ILGenerator method, LocalOrArg value, Li } } - private static void EmitXInt64ToObject(ILGenerator method, LocalOrArg value) { + /// + /// Converts Int64 to boxed Int32 if the value fits, otherwise converts to boxed BigInteger. + /// + private static void EmitInt64ToObject(ILGenerator method, LocalOrArg value) { + Debug.Assert(value.Type == typeof(long)); + Label done; Label bigInt = method.DefineLabel(); done = method.DefineLabel(); - if (value.Type == typeof(ulong)) { - method.Emit(OpCodes.Conv_I8); - } method.Emit(OpCodes.Ldc_I4, Int32.MaxValue); method.Emit(OpCodes.Conv_I8); method.Emit(OpCodes.Bgt, bigInt); @@ -739,7 +742,13 @@ private static void EmitXInt64ToObject(ILGenerator method, LocalOrArg value) { method.MarkLabel(done); } + /// + /// Handles UInt32 and UInt64 (assumes no negative values), converting to boxed Int32 if the value fits, + /// otherwise converts to boxed BigInteger. + /// private static void EmitUIntToObject(ILGenerator method, LocalOrArg value) { + Debug.Assert(value.Type == typeof(uint) || value.Type == typeof(ulong)); + Label intVal, done; intVal = method.DefineLabel(); done = method.DefineLabel(); @@ -761,11 +770,8 @@ private static void EmitUIntToObject(ILGenerator method, LocalOrArg value) { method.MarkLabel(done); } - private bool IsSubClass { - get { - return BaseTypes.Count != 1 || BaseTypes[0] != CTypes._SimpleCData; - } - } + private bool IsSubClass + => BaseTypes.Count != 1 || BaseTypes[0] != CTypes._SimpleCData; private object GetObjectReturn(IntPtr intPtr) { GCHandle handle = GCHandle.FromIntPtr(intPtr); @@ -812,11 +818,7 @@ private static object GetIntReturn(ulong value) { return (BigInteger)value; } - string INativeType.TypeFormat { - get { - return _format; - } - } + string INativeType.TypeFormat => _format; #endregion } diff --git a/src/core/IronPython.Modules/_struct.cs b/src/core/IronPython.Modules/_struct.cs index 6ed985086..9758b8640 100644 --- a/src/core/IronPython.Modules/_struct.cs +++ b/src/core/IronPython.Modules/_struct.cs @@ -150,6 +150,16 @@ public void __init__(CodeContext/*!*/ context, object fmt) { WriteUInt(res, _isLittleEndian, GetULongValue(context, curObj++, values)); } break; + case FormatType.LongLong: + for (int j = 0; j < curFormat.Count; j++) { + WriteLong(res, _isLittleEndian, GetLongLongValue(context, curObj++, values)); + } + break; + case FormatType.UnsignedLongLong: + for (int j = 0; j < curFormat.Count; j++) { + WriteULong(res, _isLittleEndian, GetULongLongValue(context, curObj++, values)); + } + break; case FormatType.Pointer: for (int j = 0; j < curFormat.Count; j++) { WritePointer(res, _isLittleEndian, GetPointer(context, curObj++, values)); @@ -175,16 +185,6 @@ public void __init__(CodeContext/*!*/ context, object fmt) { WriteUInt(res, _isLittleEndian, GetSizeT(context, curObj++, values)); } break; - case FormatType.LongLong: - for (int j = 0; j < curFormat.Count; j++) { - WriteLong(res, _isLittleEndian, GetLongLongValue(context, curObj++, values)); - } - break; - case FormatType.UnsignedLongLong: - for (int j = 0; j < curFormat.Count; j++) { - WriteULong(res, _isLittleEndian, GetULongLongValue(context, curObj++, values)); - } - break; case FormatType.Double: for (int j = 0; j < curFormat.Count; j++) { WriteDouble(res, _isLittleEndian, GetDoubleValue(context, curObj++, values)); @@ -315,6 +315,16 @@ public void pack_into(CodeContext/*!*/ context, [NotNone] IBufferProtocol/*!*/ b res[res_idx++] = BigIntegerOps.__int__(CreateUIntValue(context, ref curIndex, _isLittleEndian, data)); } break; + case FormatType.LongLong: + for (int j = 0; j < curFormat.Count; j++) { + res[res_idx++] = BigIntegerOps.__int__(CreateLongValue(context, ref curIndex, _isLittleEndian, data)); + } + break; + case FormatType.UnsignedLongLong: + for (int j = 0; j < curFormat.Count; j++) { + res[res_idx++] = BigIntegerOps.__int__(CreateULongValue(context, ref curIndex, _isLittleEndian, data)); + } + break; case FormatType.Pointer: for (int j = 0; j < curFormat.Count; j++) { if (IntPtr.Size == 4) { @@ -352,16 +362,6 @@ public void pack_into(CodeContext/*!*/ context, [NotNone] IBufferProtocol/*!*/ b res[res_idx++] = BigIntegerOps.__int__(CreateUIntValue(context, ref curIndex, _isLittleEndian, data)); } break; - case FormatType.LongLong: - for (int j = 0; j < curFormat.Count; j++) { - res[res_idx++] = BigIntegerOps.__int__(CreateLongValue(context, ref curIndex, _isLittleEndian, data)); - } - break; - case FormatType.UnsignedLongLong: - for (int j = 0; j < curFormat.Count; j++) { - res[res_idx++] = BigIntegerOps.__int__(CreateULongValue(context, ref curIndex, _isLittleEndian, data)); - } - break; #if NET6_0_OR_GREATER case FormatType.Half: for (int j = 0; j < curFormat.Count; j++) { diff --git a/src/core/IronPython.Modules/array.cs b/src/core/IronPython.Modules/array.cs index 900b9d5b8..32a29b1f0 100644 --- a/src/core/IronPython.Modules/array.cs +++ b/src/core/IronPython.Modules/array.cs @@ -117,7 +117,7 @@ public class array : IEnumerable, IWeakReferenceable, ICollection, ICodeFormatta public array([NotNone] string type) { if (type == null || type.Length != 1) { - throw PythonOps.TypeError("expected character, got {0}", PythonOps.GetPythonTypeName(type)); + throw PythonOps.TypeErrorForBadInstance("expected character, got {0}", type); } _typeCode = type[0]; @@ -388,31 +388,8 @@ public void insert(int i, [NotNone] object x) { _data.Insert(i, x); } - public int itemsize { - get { - switch (_typeCode) { - case 'b': // signed byte - case 'B': // unsigned byte - return 1; - case 'u': // unicode char - case 'h': // signed short - case 'H': // unsigned short - return 2; - case 'i': // signed int - case 'I': // unsigned int - case 'l': // signed long - case 'L': // unsigned long - case 'f': // float - return 4; - case 'q': // signed long long - case 'Q': // unsigned long long - case 'd': // double - return 8; - default: - throw new InvalidOperationException(); // should never happen - } - } - } + public int itemsize + => TypecodeOps.GetTypecodeWidth(_typeCode); public object pop() { return pop(-1); diff --git a/src/core/IronPython/Runtime/ConversionWrappers.cs b/src/core/IronPython/Runtime/ConversionWrappers.cs index f6fa6aaf4..acdbc6c3e 100644 --- a/src/core/IronPython/Runtime/ConversionWrappers.cs +++ b/src/core/IronPython/Runtime/ConversionWrappers.cs @@ -405,8 +405,10 @@ public MemoryBufferProtocolWrapper(Memory memory) { return new MemoryBufferWrapper(this, flags); } - private static char GetFormatChar() - => Type.GetTypeCode(typeof(T)) switch { + private static char GetFormatChar() { + Type type_T = typeof(T); + return Type.GetTypeCode(type_T) switch { + TypeCode.Boolean => '?', TypeCode.SByte => 'b', TypeCode.Byte => 'B', TypeCode.Char => 'u', @@ -418,9 +420,13 @@ private static char GetFormatChar() TypeCode.UInt64 => 'Q', TypeCode.Single => 'f', TypeCode.Double => 'd', - _ => throw new ArgumentException("Unsupported type"), + _ => +#if NET6_0_OR_GREATER + type_T == typeof(Half) ? 'e' : +#endif + throw new ArgumentException("Unsupported type"), }; - + } private sealed unsafe class MemoryBufferWrapper : IPythonBuffer { private readonly MemoryBufferProtocolWrapper _wrapper; diff --git a/src/core/IronPython/Runtime/TypecodeOps.cs b/src/core/IronPython/Runtime/TypecodeOps.cs index e11e97ae1..58c5b6afe 100644 --- a/src/core/IronPython/Runtime/TypecodeOps.cs +++ b/src/core/IronPython/Runtime/TypecodeOps.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information. @@ -50,11 +50,12 @@ public static bool IsFloatCode(char typecode) public static int GetTypecodeWidth(char typecode) { switch (typecode) { + case '?': // bool case 'c': // bytechar case 'b': // signed byte case 'B': // unsigned byte - case '?': // bool return 1; + case 'u': // unicode char case 'h': // signed short case 'H': // unsigned short return 2; @@ -70,8 +71,8 @@ public static int GetTypecodeWidth(char typecode) { case 'Q': // unsigned long long case 'd': // double return 8; - case 's': // char pointer - case 'p': // char pointer + case 's': // char pointer (C-style string) + case 'p': // char pointer (Pascal-style string) case 'P': // void pointer case 'r': // .NET signed pointer case 'R': // .NET unsigned pointer @@ -83,6 +84,9 @@ public static int GetTypecodeWidth(char typecode) { public static bool TryGetFromBytes(char typecode, ReadOnlySpan bytes, [NotNullWhen(true)]out object? result) { switch (typecode) { + case '?': + result = bytes[0] != 0; + return true; case 'c': result = Bytes.FromByte(bytes[0]); return true; @@ -92,9 +96,6 @@ public static bool TryGetFromBytes(char typecode, ReadOnlySpan bytes, [Not case 'B': result = bytes[0]; return true; - case '?': - result = bytes[0] != 0; - return true; case 'h': result = MemoryMarshal.Read(bytes); return true; @@ -111,18 +112,18 @@ public static bool TryGetFromBytes(char typecode, ReadOnlySpan bytes, [Not case 'N': result = MemoryMarshal.Read(bytes); return true; - case 'f': - result = MemoryMarshal.Read(bytes); - return true; - case 'd': - result = MemoryMarshal.Read(bytes); - return true; case 'q': result = MemoryMarshal.Read(bytes); return true; case 'Q': result = MemoryMarshal.Read(bytes); return true; + case 'f': + result = MemoryMarshal.Read(bytes); + return true; + case 'd': + result = MemoryMarshal.Read(bytes); + return true; case 'P': if (UIntPtr.Size == 4) goto case 'L'; else goto case 'Q'; @@ -141,6 +142,9 @@ public static bool TryGetFromBytes(char typecode, ReadOnlySpan bytes, [Not #pragma warning disable CS9191 // The 'ref' modifier for an argument corresponding to 'in' parameter is equivalent to 'in'. Consider using 'in' instead. public static bool TryGetBytes(char typecode, object obj, Span dest) { switch (typecode) { + case '?': + var boolVal = PythonOps.IsTrue(obj); + return MemoryMarshal.TryWrite(dest, ref boolVal); case 'c': var bytecharVal = (byte)((Bytes)obj)[0]; return MemoryMarshal.TryWrite(dest, ref bytecharVal); @@ -150,9 +154,6 @@ public static bool TryGetBytes(char typecode, object obj, Span dest) { case 'B': var byteVal = Convert.ToByte(obj); return MemoryMarshal.TryWrite(dest, ref byteVal); - case '?': - var boolVal = PythonOps.IsTrue(obj); - return MemoryMarshal.TryWrite(dest, ref boolVal); case 'h': var shortVal = Convert.ToInt16(obj); return MemoryMarshal.TryWrite(dest, ref shortVal); @@ -169,18 +170,18 @@ public static bool TryGetBytes(char typecode, object obj, Span dest) { case 'N': var uintVal = Convert.ToUInt32(obj); return MemoryMarshal.TryWrite(dest, ref uintVal); - case 'f': - var singleVal = Convert.ToSingle(obj); - return MemoryMarshal.TryWrite(dest, ref singleVal); - case 'd': - var doubleVal = Convert.ToDouble(obj); - return MemoryMarshal.TryWrite(dest, ref doubleVal); case 'q': var longVal = Convert.ToInt64(obj); return MemoryMarshal.TryWrite(dest, ref longVal); case 'Q': var ulongVal = Convert.ToUInt64(obj); return MemoryMarshal.TryWrite(dest, ref ulongVal); + case 'f': + var singleVal = Convert.ToSingle(obj); + return MemoryMarshal.TryWrite(dest, ref singleVal); + case 'd': + var doubleVal = Convert.ToDouble(obj); + return MemoryMarshal.TryWrite(dest, ref doubleVal); case 'P': var bi = (BigInteger)obj; if (UIntPtr.Size == 4) { @@ -219,6 +220,8 @@ public static bool CausesOverflow(object value, char typecode) { long minValue; switch (typecode) { + case '?': // bool + return false; // bool never causes overflow but is coerced to 0/1 case 'b': // signed byte minValue = sbyte.MinValue; maxValue = (ulong)sbyte.MaxValue; @@ -227,8 +230,6 @@ public static bool CausesOverflow(object value, char typecode) { minValue = byte.MinValue; maxValue = byte.MaxValue; break; - case '?': // bool - return false; // bool never causes overflow but is coerced to 0/1 case 'h': // signed short minValue = short.MinValue; maxValue = (ulong)short.MaxValue;