@@ -26,7 +26,7 @@ public static partial class CTypes {
2626 [ PythonType , PythonHidden ]
2727 public sealed class Field : PythonTypeDataSlot , ICodeFormattable {
2828 private readonly INativeType _fieldType ;
29- private readonly int _offset , _index , _bits = - 1 , _bitsOffset ;
29+ private readonly int _offset , _index , _bits , _bitsOffset ;
3030 private readonly string _fieldName ;
3131
3232 internal Field ( string fieldName , INativeType fieldType , int offset , int index ) {
@@ -42,51 +42,41 @@ internal Field(string fieldName, INativeType fieldType, int offset, int index, i
4242 _index = index ;
4343 _fieldName = fieldName ;
4444
45- // if the number of bits is the full type width, we don't
46- // need to do any masking anywhere, we may want to revisit this
47- // if the __repr__ is an issue
48- if ( bits != null && bits . Value != ( _fieldType . Size * 8 ) ) {
45+ if ( bits != null ) {
46+ Debug . Assert ( bitOffset != null ) ;
47+ Debug . Assert ( _fieldType is SimpleType ) ;
4948 _bits = bits . Value ;
5049 _bitsOffset = bitOffset . Value ;
50+ if ( ( ( SimpleType ) _fieldType ) . _swap ) {
51+ _bitsOffset = _fieldType . Size * 8 - _bitsOffset - _bits ;
52+ }
5153 }
5254 }
5355
54- public int offset {
55- get {
56- return _offset ;
57- }
58- }
56+ public int offset => _offset ;
5957
60- public int size {
61- get {
62- return _fieldType . Size ;
63- }
64- }
58+ public int size => _bits == 0 ? _fieldType . Size : ( _bits << 16 ) + _bitsOffset ;
6559
66- #region Internal APIs
60+ #region Internal APIs
6761
6862 internal override bool TryGetValue ( CodeContext context , object instance , PythonType owner , out object value ) {
6963 if ( instance != null ) {
7064 CData inst = ( CData ) instance ;
71- value = _fieldType . GetValue ( inst . MemHolder , inst , _offset , false ) ;
72- if ( _bits == - 1 ) {
65+ if ( ! IsProperBitfield ) {
66+ value = _fieldType . GetValue ( inst . MemHolder , inst , _offset , false ) ;
67+ return true ;
68+ } else {
69+ value = ExtractBits ( inst ) ;
7370 return true ;
7471 }
75-
76- value = ExtractBits ( value ) ;
77- return true ;
7872 }
7973
8074 value = this ;
8175 return true ;
8276 }
8377
8478
85- internal override bool GetAlwaysSucceeds {
86- get {
87- return true ;
88- }
89- }
79+ internal override bool GetAlwaysSucceeds => true ;
9080
9181 internal override bool TrySetValue ( CodeContext context , object instance , PythonType owner , object value ) {
9282 if ( instance != null ) {
@@ -98,7 +88,7 @@ internal override bool TrySetValue(CodeContext context, object instance, PythonT
9888 }
9989
10090 internal void SetValue ( MemoryHolder address , int baseOffset , object value ) {
101- if ( _bits == - 1 ) {
91+ if ( ! IsProperBitfield ) {
10292 object keepAlive = _fieldType . SetValue ( address , baseOffset + _offset , value ) ;
10393 if ( keepAlive != null ) {
10494 address . AddObject ( _index . ToString ( ) , keepAlive ) ;
@@ -112,110 +102,134 @@ internal override bool TryDeleteValue(CodeContext context, object instance, Pyth
112102 throw PythonOps . TypeError ( "cannot delete fields in ctypes structures/unions" ) ;
113103 }
114104
115- internal INativeType NativeType {
116- get {
117- return _fieldType ;
118- }
119- }
105+ internal INativeType NativeType => _fieldType ;
120106
121- internal int ? BitCount {
122- get {
123- if ( _bits == - 1 ) {
124- return null ;
125- }
126-
127- return _bits ;
128- }
129- }
107+ internal int ? BitCount => _bits == 0 ? null : _bits ;
130108
131- internal string FieldName {
132- get {
133- return _fieldName ;
134- }
135- }
109+ internal string FieldName => _fieldName ;
136110
137- #endregion
111+ #endregion
138112
139- #region ICodeFormattable Members
113+ #region ICodeFormattable Members
140114
141115 public string __repr__ ( CodeContext context ) {
142- if ( _bits == - 1 ) {
143- return String . Format ( "<Field type={0}, ofs={1}, size={2}>" , ( ( PythonType ) _fieldType ) . Name , offset , size ) ;
116+ if ( _bits == 0 ) {
117+ return string . Format ( "<Field type={0}, ofs={1}, size={2}>" , ( ( PythonType ) _fieldType ) . Name , offset , size ) ;
144118 }
145- return String . Format ( "<Field type={0}, ofs={1}:{2}, bits={3}>" , ( ( PythonType ) _fieldType ) . Name , offset , _bitsOffset , _bits ) ;
119+ return string . Format ( "<Field type={0}, ofs={1}:{2}, bits={3}>" , ( ( PythonType ) _fieldType ) . Name , offset , _bitsOffset , _bits ) ;
146120 }
147121
148- #endregion
122+ #endregion
149123
150- #region Private implementation
124+ #region Private implementation
151125
152126 /// <summary>
153127 /// Called for fields which have been limited to a range of bits. Given the
154128 /// value for the full type this extracts the individual bits.
155129 /// </summary>
156- private object ExtractBits ( object value ) {
157- if ( value is int ) {
158- int validBits = ( ( 1 << _bits ) - 1 ) ;
130+ private object ExtractBits ( CData instance ) {
131+ Debug . Assert ( _bits > 0 ) ;
132+ Debug . Assert ( _bits < sizeof ( ulong ) * 8 ) ; // Avoid unspecified shifts: ECMA 335: III.3.58-59
133+ Debug . Assert ( instance != null ) ;
134+
135+ object value ;
136+ if ( IsBoolType ) {
137+ int valueBits = instance . MemHolder . ReadByte ( offset ) ;
138+ int ibVal = ExtractBitsFromInt ( valueBits ) ;
139+ value = ScriptingRuntimeHelpers . BooleanToObject ( ibVal != 0 ) ;
159140
160- int iVal = ( int ) value ;
161- iVal = ( iVal >> _bitsOffset ) & validBits ;
162- if ( IsSignedType ) {
163- // need to sign extend if high bit is set
164- if ( ( iVal & ( 1 << ( _bits - 1 ) ) ) != 0 ) {
165- iVal |= ( - 1 ) ^ validBits ;
166- }
167- }
168- value = ScriptingRuntimeHelpers . Int32ToObject ( iVal ) ;
169141 } else {
170- Debug . Assert ( value is BigInteger ) ; // we only return ints or big ints from GetValue
171- ulong validBits = ( 1UL << _bits ) - 1 ;
142+ value = _fieldType . GetValue ( instance . MemHolder , instance , _offset , false ) ;
143+ if ( value is int iVal ) {
144+ iVal = ExtractBitsFromInt ( iVal ) ;
145+ value = ScriptingRuntimeHelpers . Int32ToObject ( iVal ) ;
146+ } else if ( value is BigInteger biVal ) {
147+ ulong validBits = ( 1UL << _bits ) - 1 ;
148+
149+ ulong bits ;
150+ if ( IsSignedType ) {
151+ bits = ( ulong ) ( long ) biVal ;
152+ } else {
153+ bits = ( ulong ) biVal ;
154+ }
155+
156+ bits = ( bits >> _bitsOffset ) & validBits ;
157+
158+ if ( IsSignedType ) {
159+ // need to sign extend if high bit is set
160+ if ( ( bits & ( 1UL << ( _bits - 1 ) ) ) != 0 ) {
161+ bits |= ulong . MaxValue ^ validBits ;
162+ }
163+ value = ( BigInteger ) ( long ) bits ;
164+ } else {
165+ value = ( BigInteger ) bits ;
166+ }
172167
173- BigInteger biVal = ( BigInteger ) value ;
174- ulong bits ;
175- if ( IsSignedType ) {
176- bits = ( ulong ) ( long ) biVal ;
177168 } else {
178- bits = ( ulong ) biVal ;
169+ throw new InvalidOperationException ( "we only return int, bigint from GetValue" ) ;
179170 }
171+ }
172+ return value ;
180173
181- bits = ( bits >> _bitsOffset ) & validBits ;
174+ int ExtractBitsFromInt ( int iVal ) {
175+ int validBits = ( ( 1 << _bits ) - 1 ) ;
182176
177+ iVal = ( iVal >> _bitsOffset ) & validBits ;
183178 if ( IsSignedType ) {
184179 // need to sign extend if high bit is set
185- if ( ( bits & ( 1UL << ( _bits - 1 ) ) ) != 0 ) {
186- bits |= ulong . MaxValue ^ validBits ;
180+ if ( ( iVal & ( 1 << ( _bits - 1 ) ) ) != 0 ) {
181+ iVal |= ( - 1 ) ^ validBits ;
187182 }
188- value = ( BigInteger ) ( long ) bits ;
189- } else {
190- value = ( BigInteger ) bits ;
191183 }
184+
185+ return iVal ;
192186 }
193- return value ;
194187 }
195188
196189 /// <summary>
197- /// Called for fields which have been limited to a range of bits. Sets the
190+ /// Called for fields which have been limited to a range of bits. Sets the
198191 /// specified value into the bits for the field.
199192 /// </summary>
200193 private void SetBitsValue ( MemoryHolder address , int baseOffset , object value ) {
201194 // get the value in the form of a ulong which can contain the biggest bitfield
202195 ulong newBits ;
203- if ( value is int ) {
204- newBits = ( ulong ) ( int ) value ;
205- } else if ( value is BigInteger ) {
206- newBits = ( ulong ) ( long ) ( BigInteger ) value ;
196+ if ( IsBoolType ) {
197+ newBits = PythonOps . IsTrue ( value ) ? 1ul : 0ul ;
207198 } else {
208- throw PythonOps . TypeErrorForTypeMismatch ( "int or long" , value ) ;
199+ value = PythonOps . Index ( value ) ; // since 3.8
200+ if ( value is int iVal ) {
201+ newBits = ( ulong ) iVal ;
202+ } else if ( value is BigInteger biVal ) {
203+ if ( biVal . Sign >= 0 ) {
204+ if ( biVal <= ulong . MaxValue ) {
205+ newBits = ( ulong ) biVal ;
206+ } else {
207+ newBits = ( ulong ) ( biVal & ulong . MaxValue ) ;
208+ }
209+ } else {
210+ if ( biVal >= long . MinValue ) {
211+ newBits = ( ulong ) ( long ) biVal ;
212+ } else {
213+ newBits = ( ulong ) ( biVal & ulong . MaxValue ) ;
214+ }
215+ }
216+ } else {
217+ throw new InvalidOperationException ( "unreachable" ) ;
218+ }
209219 }
210220
211221 // do the same for the existing value
212222 int offset = checked ( _offset + baseOffset ) ;
213- object curValue = _fieldType . GetValue ( address , null , offset , false ) ;
214223 ulong valueBits ;
215- if ( curValue is int ) {
216- valueBits = ( ulong ) ( int ) curValue ;
224+ if ( IsBoolType ) {
225+ valueBits = address . ReadByte ( offset ) ;
217226 } else {
218- valueBits = ( ulong ) ( long ) ( BigInteger ) curValue ;
227+ object curValue = _fieldType . GetValue ( address , null , offset , false ) ;
228+ if ( curValue is int iCurVal ) {
229+ valueBits = ( ulong ) iCurVal ;
230+ } else {
231+ valueBits = ( ulong ) ( long ) ( BigInteger ) curValue ;
232+ }
219233 }
220234
221235 // get a mask for the bits this field owns
@@ -225,8 +239,10 @@ private void SetBitsValue(MemoryHolder address, int baseOffset, object value) {
225239 // or in the new bits provided by the user
226240 valueBits |= ( newBits << _bitsOffset ) & targetBits ;
227241
228- // and set the value
229- if ( IsSignedType ) {
242+ // and set the value
243+ if ( IsBoolType ) {
244+ address . WriteByte ( offset , ( byte ) valueBits ) ;
245+ } else if ( IsSignedType ) {
230246 if ( _fieldType . Size <= 4 ) {
231247 _fieldType . SetValue ( address , offset , ( int ) ( long ) valueBits ) ;
232248 } else {
@@ -255,7 +271,14 @@ private bool IsSignedType {
255271 }
256272 }
257273
258- #endregion
274+ private bool IsBoolType => ( ( SimpleType ) _fieldType ) . _type is SimpleTypeKind . Boolean ;
275+
276+ /// <summary>
277+ /// Returns true if the field is a bitfield that does not span the whole width of the underlying field type.
278+ /// </summary>
279+ private bool IsProperBitfield => 0 < _bits && _bits < _fieldType . Size * 8 ;
280+
281+ #endregion
259282 }
260283 }
261284}
0 commit comments