@@ -151,8 +151,47 @@ def _maybe_panel(textgen, title: str, rich: bool):
151
151
return title + ":\n " + text
152
152
153
153
154
- def find_set_bits (mask , value , repeated_masks ):
155
- bitpos = np .arange (8 )[::- 1 ]
154
+ def _get_bit_length (dtype ):
155
+ # Check if dtype is a numpy dtype, if not, convert it
156
+ if not isinstance (dtype , np .dtype ):
157
+ dtype = np .dtype (dtype )
158
+
159
+ # Calculate the bit length
160
+ bit_length = 8 * dtype .itemsize
161
+
162
+ return bit_length
163
+
164
+
165
+ def _unpackbits (mask , bit_length ):
166
+ # Ensure the array is a numpy array
167
+ arr = np .asarray (mask )
168
+
169
+ # Create an output array of the appropriate shape
170
+ output_shape = arr .shape + (bit_length ,)
171
+ output = np .zeros (output_shape , dtype = np .uint8 )
172
+
173
+ # Unpack bits
174
+ for i in range (bit_length ):
175
+ output [..., i ] = (arr >> i ) & 1
176
+
177
+ return output [..., ::- 1 ]
178
+
179
+
180
+ def _max_chars_for_bit_length (bit_length ):
181
+ """
182
+ Find the maximum characters needed for a fixed-width display
183
+ for integer values of a certain bit_length. Use calculation
184
+ for signed integers, since it conservatively will always have
185
+ enough characters for signed or unsigned.
186
+ """
187
+ # Maximum value for signed integers of this bit length
188
+ max_val = 2 ** (bit_length - 1 ) - 1
189
+ # Add 1 for the negative sign
190
+ return len (str (max_val )) + 1
191
+
192
+
193
+ def find_set_bits (mask , value , repeated_masks , bit_length ):
194
+ bitpos = np .arange (bit_length )[::- 1 ]
156
195
if mask not in repeated_masks :
157
196
if value == 0 :
158
197
return [- 1 ]
@@ -161,8 +200,8 @@ def find_set_bits(mask, value, repeated_masks):
161
200
else :
162
201
return [int (np .log2 (mask ))]
163
202
else :
164
- allset = bitpos [np . unpackbits ( np . uint8 ( mask ) ) == 1 ]
165
- setbits = bitpos [np . unpackbits ( np . uint8 ( mask & value ) ) == 1 ]
203
+ allset = bitpos [_unpackbits ( mask , bit_length ) == 1 ]
204
+ setbits = bitpos [_unpackbits ( mask & value , bit_length ) == 1 ]
166
205
return [b if abs (b ) in setbits else - b for b in allset ]
167
206
168
207
@@ -184,25 +223,30 @@ def _format_flags(accessor, rich):
184
223
# for f, (m, _) in flag_dict.items()
185
224
# if m is not None and m not in repeated_masks
186
225
# ]
226
+
227
+ bit_length = _get_bit_length (accessor ._obj .dtype )
228
+ mask_width = _max_chars_for_bit_length (bit_length )
229
+ key_width = max (len (key ) for key in flag_dict )
230
+
187
231
bit_text = []
188
232
value_text = []
189
233
for key , (mask , value ) in flag_dict .items ():
190
234
if mask is None :
191
235
bit_text .append ("✗" if rich else "" )
192
236
value_text .append (str (value ))
193
237
continue
194
- bits = find_set_bits (mask , value , repeated_masks )
195
- bitstring = ["." ] * 8
238
+ bits = find_set_bits (mask , value , repeated_masks , bit_length )
239
+ bitstring = ["." ] * bit_length
196
240
if bits == [- 1 ]:
197
241
continue
198
242
else :
199
243
for b in bits :
200
244
bitstring [abs (b )] = _format_cf_name ("1" if b >= 0 else "0" , rich )
201
245
text = "" .join (bitstring [::- 1 ])
202
246
value_text .append (
203
- f"{ mask } & { value } "
247
+ f"{ mask :{ mask_width } } & { value } "
204
248
if key in excl_flags and value is not None
205
- else str ( mask )
249
+ else f" { mask :{ mask_width } } "
206
250
)
207
251
bit_text .append (text if rich else f" / Bit: { text } " )
208
252
@@ -230,7 +274,9 @@ def _format_flags(accessor, rich):
230
274
else :
231
275
rows = []
232
276
for val , bit , key in zip (value_text , bit_text , flag_dict ):
233
- rows .append (f"{ TAB } { _format_cf_name (key , rich )} : { TAB } { val } { bit } " )
277
+ rows .append (
278
+ f"{ TAB } { _format_cf_name (key , rich ):>{key_width }} : { TAB } { val } { bit } "
279
+ )
234
280
return _print_rows ("Flag Meanings" , rows , rich )
235
281
236
282
0 commit comments