• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Nic30 / pyMathBitPrecise / 2fd037fb-a15f-4333-8cc6-71ed98b25546

20 Nov 2024 08:42PM UTC coverage: 73.307% (-2.7%) from 76.055%
2fd037fb-a15f-4333-8cc6-71ed98b25546

push

circleci

Nic30
fix(Bits3t): repr and __int__ of negative signed numbers

200 of 296 branches covered (67.57%)

Branch coverage included in aggregate %.

4 of 4 new or added lines in 1 file covered. (100.0%)

81 existing lines in 2 files now uncovered.

742 of 989 relevant lines covered (75.03%)

0.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.43
/pyMathBitPrecise/bits3t.py
1
#!/usr/bin/env python3
2
# -*- coding: UTF-8 -*-
3

4
from copy import copy
1✔
5
from enum import Enum
1✔
6
from math import log2, ceil
1✔
7
from operator import le, ge, gt, lt, ne, eq, and_, or_, xor, sub, add
1✔
8
from typing import Union, Optional, Callable
1✔
9

10
from pyMathBitPrecise.array3t import Array3t
1✔
11
from pyMathBitPrecise.bit_utils import mask, get_bit, get_bit_range, \
1✔
12
    to_signed, set_bit_range, bit_set_to, bit_field, to_unsigned, INT_BASES, \
13
    ValidityError, normalize_slice, rotate_right, rotate_left
14
from pyMathBitPrecise.bits3t_vld_masks import vld_mask_for_xor, vld_mask_for_and, \
1✔
15
    vld_mask_for_or
16

17

18
class Bits3t():
1✔
19
    """
20
    Meta type for integer of specified size where
21
    each bit can be '1', '0' or 'X' for undefined value.
22

23
    :ivar ~.bit_length: number representation of value of this type
24
    :ivar ~.signed: flag which tells if this type is signed or not
25
    :ivar ~._all_mask: cached value of mask for all bits
26
    :ivar ~.name: name for annotation
27
    :ivar ~.force_vector: use always hdl vector type
28
            (for example std_logic_vector(0 downto 0)
29
             instead of std_logic in VHDL,
30
             wire[1] instead of wire)
31
    :ivar ~.strict_sign: same thing as strict_width just for signed/unsigned
32
    :ivar ~.strict_width: if True the arithmetic, bitwise
33
        and comparison operators can be performed only on value
34
        of this exact same width
35
    :note: operation is not strict if at least one operand
36
        does not have strict flag set,
37
        the result width/sign is taken from other operand
38
        (or first if both are not strict)
39
    """
40

41
    def __init__(self, bit_length: int, signed:Optional[bool]=False, name: Optional[str]=None,
1✔
42
                 force_vector=False,
43
                 strict_sign=True, strict_width=True):
44
        if force_vector and bit_length != 1:
1!
45
            assert bit_length == 1, "force_vector=True is appliable only for 1b values"
×
46
        self._bit_length = bit_length
1✔
47
        self.signed = signed
1✔
48
        self._all_mask = mask(bit_length)
1✔
49
        self.name = name
1✔
50
        self.force_vector = force_vector
1✔
51
        self.strict_sign = strict_sign
1✔
52
        self.strict_width = strict_width
1✔
53

54
    def __copy__(self):
1✔
55
        t = self.__class__(self._bit_length, signed=self.signed,
1✔
56
                           name=self.name,
57
                           force_vector=self.force_vector,
58
                           strict_sign=self.strict_sign,
59
                           strict_width=self.strict_width)
60
        return t
1✔
61

62
    def all_mask(self):
1✔
63
        """
64
        :return: mask for bites of this type ( 0b111 for Bits(3) )
65
        """
66
        return self._all_mask
1✔
67

68
    def bit_length(self):
1✔
69
        """
70
        :return: number of bits required for representation
71
            of value of this type
72
        """
73
        return self._bit_length
1✔
74

75
    def __eq__(self, other):
1✔
76
        return (self is other
×
77
                or (isinstance(other, Bits3t)
78
                    and self._bit_length == other._bit_length
79
                    and self.name == other.name
80
                    and self.force_vector == other.force_vector
81
                    and self.strict_sign == other.strict_sign
82
                    and self.strict_width == other.strict_width
83
                    and self.signed == other.signed
84
                    )
85
                )
86

87
    def _normalize_val_and_mask(self, val, vld_mask):
1✔
88
        if val is None:
1✔
89
            vld = 0
1✔
90
            val = 0
1✔
91
            assert vld_mask is None or vld_mask == 0
1✔
92
        else:
93
            all_mask = self.all_mask()
1✔
94
            w = self._bit_length
1✔
95
            if isinstance(val, int):
1✔
96
                pass
1✔
97
            elif isinstance(val, bytes):
1!
98
                val = int.from_bytes(
×
99
                    val, byteorder="little", signed=bool(self.signed))
100
            elif isinstance(val, str):
1✔
101
                if not (val.startswith("0") and len(val) > 2):
1!
102
                    raise ValueError(val)
×
103

104
                base = INT_BASES[val[1]]
1✔
105
                try:
1✔
106
                    _val = int(val[2:], base)
1✔
107
                except ValueError:
1✔
108
                    _val = None
1✔
109

110
                if _val is None:
1!
111
                    assert vld_mask is None
1✔
112
                    val = val.lower()
1✔
113
                    if base == 10 and "x" in val:
1✔
114
                        raise NotImplementedError()
115
                    v = 0
1✔
116
                    m = 0
1✔
117
                    bits_per_char = ceil(log2(base))
1✔
118
                    char_mask = mask(bits_per_char)
1✔
119
                    for digit in val[2:]:
1✔
120
                        v <<= bits_per_char
1✔
121
                        m <<= bits_per_char
1✔
122
                        if digit == "x":
1✔
123
                            pass
1✔
124
                        else:
125
                            m |= char_mask
1✔
126
                            v |= int(digit, base)
1✔
127
                    val = v
1✔
128
                    vld_mask = m
1✔
129
                else:
130
                    val = _val
×
131
            else:
132
                try:
1✔
133
                    val = int(val)
1✔
134
                except TypeError as e:
1✔
135
                    if isinstance(val, Enum):
1!
136
                        val = int(val.value)
×
137
                    else:
138
                        raise e
1✔
139

140
            if vld_mask is None:
1✔
141
                vld = all_mask
1✔
142
            else:
143
                if vld_mask > all_mask or vld_mask < 0:
1!
144
                    raise ValueError("Mask in incorrect format", vld_mask, w, all_mask)
×
145
                vld = vld_mask
1✔
146

147
            if val < 0:
1✔
148
                if not self.signed:
1✔
149
                    raise ValueError("Negative value for unsigned int")
1✔
150
                _val = to_signed(val & all_mask, w)
1✔
151
                if _val != val:
1✔
152
                    raise ValueError("Too large value", val, _val)
1✔
153
                val = _val
1✔
154
            else:
155
                if self.signed:
1✔
156
                    msb = 1 << (w - 1)
1✔
157
                    if msb & val:
1✔
158
                        if val > 0:
1!
159
                            raise ValueError(
1✔
160
                                "Value too large to fit in this type", val)
161

162
                if val & all_mask != val:
1✔
163
                    raise ValueError(
1✔
164
                        "Not enough bits to represent value",
165
                        val, "on", w, "bit" if w == 1 else "bits", val & all_mask)
166
                val = val & vld
1✔
167
        return val, vld
1✔
168

169
    def _from_py(self, val, vld_mask):
1✔
170
        """
171
        from_py without normalization
172
        """
173
        return Bits3val(self, val, vld_mask)
1✔
174

175
    def from_py(self, val: Union[int, bytes, str, Enum],
1✔
176
                vld_mask: Optional[int]=None) -> "Bits3val":
177
        """
178
        Construct value from pythonic value
179
        :note: str value has to start with base specifier (0b, 0h)
180
            and is much slower than the value specified
181
            by 'val' and 'vld_mask'. Does support x.
182
        """
183
        val, vld_mask = self._normalize_val_and_mask(val, vld_mask)
1✔
184
        return Bits3val(self, val, vld_mask)
1✔
185

186
    def __getitem__(self, i):
1✔
187
        ":return: an item from this array"
188
        return Array3t(self, i)
1✔
189

190
    def __hash__(self):
1✔
191
        return hash((
×
192
            self._bit_length,
193
            self.signed,
194
            self._all_mask,
195
            self.name,
196
            self.force_vector,
197
            self.strict_sign,
198
            self.strict_width
199
        ))
200

201
    def __repr__(self):
202
        """
203
        :param indent: number of indentation
204
        :param withAddr: if is not None is used as a additional
205
            information about on which address this type is stored
206
            (used only by HStruct)
207
        :param expandStructs: expand HStructTypes (used by HStruct and HArray)
208
        """
209
        constr = []
210
        if self.name is not None:
211
            constr.append(f'"{self.name:s}"')
212
        c = self.bit_length()
213

214
        if self.signed:
215
            sign = "i"
216
        elif self.signed is False:
217
            sign = "u"
218
        else:
219
            sign = "b"
220

221
        constr.append(f"{sign:s}{c:d}")
222
        if self.force_vector:
223
            constr.append("force_vector")
224

225
        if not self.strict_sign:
226
            constr.append("strict_sign=False")
227
        if not self.strict_width:
228
            constr.append("strict_width=False")
229

230
        return "<%s %s>" % (self.__class__.__name__,
231
                             ", ".join(constr))
232

233

234
class Bits3val():
1✔
235
    """
236
    Class for value of `Bits3t` type
237

238
    :ivar ~._dtype: reference on type of this value
239
    :ivar ~.val: always unsigned representation int value
240
    :ivar ~.vld_mask: always unsigned value of the mask, if bit in mask is '0'
241
            the corresponding bit in val is invalid
242
    """
243
    _BOOL = Bits3t(1)
1✔
244
    _SIGNED_FOR_SLICE_CONCAT_RESULT = False
1✔
245

246
    def __init__(self, t: Bits3t, val: int, vld_mask: int):
1✔
247
        if not isinstance(t, Bits3t):
1!
248
            raise TypeError(t)
×
249
        if type(val) != int:
1!
250
            raise TypeError(val)
×
251
        if type(vld_mask) != int:
1!
252
            raise TypeError(vld_mask)
×
253
        self._dtype = t
1✔
254
        self.val = val
1✔
255
        self.vld_mask = vld_mask
1✔
256

257
    def __copy__(self):
1✔
258
        return self.__class__(self._dtype, self.val, self.vld_mask)
1✔
259

260
    def to_py(self) -> int:
1✔
261
        return int(self)
×
262

263
    def _is_full_valid(self) -> bool:
1✔
264
        """
265
        :return: True if all bits in value are valid
266
        """
267
        return self.vld_mask == self._dtype.all_mask()
1✔
268

269
    def __int__(self) -> int:
1✔
270
        "int(self)"
271
        if not self._is_full_valid():
1✔
272
            raise ValidityError(self)
1✔
273
        if self._dtype.signed:
1✔
274
            return to_signed(self.val, self._dtype.bit_length())
1✔
275
        else:
276
            return self.val
1✔
277

278
    def __bool__(self) -> bool:
1✔
279
        "bool(self)"
280
        return bool(self.__int__())
1✔
281

282
    def _auto_cast(self, dtype):
1✔
283
        """
284
        Cast value to a compatible type
285
        """
286
        return dtype.from_py(self.val, self.vld_mask)
×
287

288
    def cast_sign(self, signed: Optional[bool]) -> "Bits3val":
1✔
289
        """
290
        Cast signed-unsigned value
291
        """
292
        t = self._dtype
1✔
293
        if t.signed == signed:
1!
294
            return self
×
295
        selfSign = t.signed
1✔
296
        v = self.__copy__()
1✔
297
        m = t._all_mask
1✔
298
        _v = v.val
1✔
299

300
        if selfSign and not signed:
1✔
301
            if _v < 0:
1!
302
                v.val = m + _v + 1
1✔
303
        elif not selfSign and signed:
1!
304
            w = t.bit_length()
1✔
305
            v.val = to_signed(_v, w)
1✔
306

307
        v._dtype = v._dtype.__copy__()
1✔
308
        v._dtype = self._dtype.__copy__()
1✔
309
        v._dtype.signed = signed
1✔
310
        return v
1✔
311

312
    def cast(self, t: Bits3t) -> "Bits3val":
1✔
313
        """
314
        C++: static_cast<t>(self)
315

316
        :note: no sign extension
317
        """
318
        v = self.__copy__()
1✔
319
        v._dtype = t
1✔
320
        m = t.all_mask()
1✔
321
        v.val &= m
1✔
322
        v.vld_mask &= m
1✔
323
        if t.signed:
1✔
324
            v.val = to_signed(v.val, t.bit_length())
1✔
325
        return v
1✔
326

327
    def _concat(self, other: "Bits3val") -> "Bits3val":
1✔
328
        """
329
        Concatenate two bit vectors together (self will be at MSB side)
330
        Verilog: {self, other}, VHDL: self & other
331
        """
332
        if not isinstance(other, Bits3val):
1✔
333
            raise TypeError(other)
1✔
334
        w = self._dtype.bit_length()
1✔
335
        other_w = other._dtype.bit_length()
1✔
336
        resWidth = w + other_w
1✔
337
        resT = self._dtype.__class__(resWidth, signed=self._SIGNED_FOR_SLICE_CONCAT_RESULT)
1✔
338
        other_val = other.val
1✔
339
        if other_val < 0:
1!
340
            other_val = to_unsigned(other_val, other_w)
×
341
        v = self.__copy__()
1✔
342
        if v.val < 0:
1!
343
            v.val = to_unsigned(v.val, w)
×
344
        v.val = (v.val << other_w) | other_val
1✔
345
        v.vld_mask = (v.vld_mask << other_w) | other.vld_mask
1✔
346
        v._dtype = resT
1✔
347
        return v
1✔
348

349
    def __getitem__(self, key: Union[int, slice, "Bits3val"]) -> "Bits3val":
1✔
350
        "self[key]"
351
        if isinstance(key, slice):
1✔
352
            firstBitNo, size = normalize_slice(key, self._dtype.bit_length())
1✔
353
            val = get_bit_range(self.val, firstBitNo, size)
1✔
354
            vld = get_bit_range(self.vld_mask, firstBitNo, size)
1✔
355
        elif isinstance(key, (int, Bits3val)):
1✔
356
            size = 1
1✔
357
            try:
1✔
358
                _i = int(key)
1✔
359
            except ValidityError:
×
360
                _i = None
×
361

362
            if _i is None:
1!
363
                val = 0
×
364
                vld = 0
×
365
            else:
366
                if _i < 0 or _i >= self._dtype.bit_length():
1✔
367
                    raise IndexError("Index out of range", _i)
1✔
368

369
                val = get_bit(self.val, _i)
1✔
370
                vld = get_bit(self.vld_mask, _i)
1✔
371
        else:
372
            raise TypeError(key)
1✔
373

374
        new_t = self._dtype.__class__(size, signed=self._SIGNED_FOR_SLICE_CONCAT_RESULT)
1✔
375
        return new_t._from_py(val, vld)
1✔
376

377
    def __setitem__(self, index: Union[slice, int, "Bits3val"],
1✔
378
                    value: Union["Bits3val", int]):
379
        "An item assignment operator self[index] = value."
380
        if isinstance(index, slice):
1✔
381
            firstBitNo, size = normalize_slice(index, self._dtype.bit_length())
1✔
382
            if isinstance(value, Bits3val):
1!
383
                v = value.val
×
384
                m = value.vld_mask
×
385
            else:
386
                v = value
1✔
387
                m = mask(size)
1✔
388

389
            self.val = set_bit_range(self.val, firstBitNo, size, v)
1✔
390
            self.vld_mask = set_bit_range(
1✔
391
                self.vld_mask, firstBitNo, size, m)
392
        else:
393
            if index is None:
1✔
394
                raise TypeError(index)
1✔
395
            try:
1✔
396
                _i = int(index)
1✔
397
            except ValidityError:
×
398
                _i = None
×
399

400
            if _i is None:
1!
401
                self.val = 0
×
402
                self.vld_mask = 0
×
403
            else:
404
                if value is None:
1✔
405
                    v = 0
1✔
406
                    m = 0
1✔
407
                elif isinstance(value, Bits3val):
1!
408
                    v = value.val
×
409
                    m = value.vld_mask
×
410
                else:
411
                    v = value
1✔
412
                    m = 0b1
1✔
413
                try:
1✔
414
                    index = int(index)
1✔
415
                except ValidityError:
×
416
                    index = None
×
417
                if index is None:
1!
418
                    self.val = 0
×
419
                    self.vld_mask = 0
×
420
                else:
421
                    self.val = bit_set_to(self.val, index, v)
1✔
422
                    self.vld_mask = bit_set_to(self.vld_mask, index, m)
1✔
423

424
    def __invert__(self) -> "Bits3val":
1✔
425
        "Operator ~x."
426
        v = self.__copy__()
1✔
427
        v.val = ~v.val
1✔
428
        w = v._dtype.bit_length()
1✔
429
        v.val &= mask(w)
1✔
430
        if self._dtype.signed:
1✔
431
            v.val = to_signed(v.val, w)
1✔
432
        return v
1✔
433

434
    def __neg__(self):
1✔
435
        "Operator -x."
436
        if not self._dtype.signed:
1✔
437
            raise TypeError("- operator is defined only for signed")
1✔
438

439
        v = self.__copy__()
1✔
440
        _v = -v.val
1✔
441
        _max = self._dtype.all_mask() >> 1
1✔
442
        _min = -_max - 1
1✔
443
        if _v > _max:
1✔
444
            _v = _min + (_v - _max - 1)
1✔
445
        elif _v < _min:
1!
446
            _v = _max - (_v - _min + 1)
×
447
        v.val = _v
1✔
448
        return v
1✔
449

450
    def __hash__(self):
1✔
451
        return hash((self._dtype, self.val, self.vld_mask))
×
452

453
    def _is(self, other):
1✔
454
        """check if other is object with same values"""
455
        return isinstance(other, Bits3val)\
×
456
            and self._dtype == other._dtype\
457
            and self.val == other.val\
458
            and self.vld_mask == other.vld_mask
459

460
    def _eq(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
461
        """
462
        Operator self._eq(other) as self == other
463
        == is not overridden in order to prevent tricky behavior if hashing partially valid values
464
        """
465
        return bitsCmp__val(self, other, eq)
1✔
466

467
    def __req__(self, other: int) -> "Bits3val":
1✔
468
        "Operator ==."
469
        return bitsCmp__val(self._dtype.from_py(other), self, eq)
×
470

471
    def __ne__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
472
        "Operator !=."
473
        return bitsCmp__val(self, other, ne)
1✔
474

475
    def __rne__(self, other: int) -> "Bits3val":
1✔
476
        "Operator !=."
477
        return bitsCmp__val(self._dtype.from_py(other), self, ne)
×
478

479
    def __lt__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
480
        "Operator <."
481
        return bitsCmp__val(self, other, lt)
1✔
482

483
    def __rlt__(self, other: int) -> "Bits3val":
1✔
484
        "Operator <."
485
        return bitsCmp__val(self._dtype.from_py(other), self, lt)
×
486

487
    def __gt__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
488
        "Operator >."
489
        return bitsCmp__val(self, other, gt)
1✔
490

491
    def __rgt__(self, other: int) -> "Bits3val":
1✔
492
        "Operator >."
493
        return bitsCmp__val(self._dtype.from_py(other), self, gt)
×
494

495
    def __ge__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
496
        "Operator >=."
497
        return bitsCmp__val(self, other, ge)
1✔
498

499
    def __rge__(self, other: int) -> "Bits3val":
1✔
500
        "Operator >=."
501
        return bitsCmp__val(self._dtype.from_py(other), self, ge)
×
502

503
    def __le__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
504
        "Operator <=."
505
        return bitsCmp__val(self, other, le)
1✔
506

507
    def __rle__(self, other: int) -> "Bits3val":
1✔
508
        "Operator <=."
509
        return bitsCmp__val(self._dtype.from_py(other), self, le)
×
510

511
    def __xor__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
512
        "Operator ^."
513
        return bitsBitOp__val(self, other, xor, vld_mask_for_xor)
1✔
514

515
    def __rxor__(self, other: int) -> "Bits3val":
1✔
516
        "Operator ^."
517
        return bitsBitOp__val(self._dtype.from_py(other), self, xor,
×
518
                              vld_mask_for_xor)
519

520
    def __and__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
521
        "Operator &."
522
        return bitsBitOp__val(self, other, and_, vld_mask_for_and)
1✔
523

524
    def __rand__(self, other: int) -> "Bits3val":
1✔
525
        "Operator &."
526
        return bitsBitOp__val(self._dtype.from_py(other), self, and_,
×
527
                              vld_mask_for_and)
528

529
    def __or__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
530
        "Operator |."
531
        return bitsBitOp__val(self, other, or_, vld_mask_for_or)
1✔
532

533
    def __ror__(self, other: int) -> "Bits3val":
1✔
534
        "Operator |."
535
        return bitsBitOp__val(self._dtype.from_py(other), self, or_,
×
536
                              vld_mask_for_or)
537

538
    def __sub__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
539
        "Operator -."
540
        return bitsArithOp__val(self, other, sub)
1✔
541

542
    def __rsub__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
543
        "Operator -."
544
        return bitsArithOp__val(self._dtype.from_py(other), self, sub)
×
545

546
    def __add__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
547
        "Operator +."
548
        return bitsArithOp__val(self, other, add)
1✔
549

550
    def __radd__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
551
        "Operator +."
552
        return bitsArithOp__val(self._dtype.from_py(other), self, add)
×
553

554
    def __rshift__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
555
        "Operator >> (arithmetic, shifts in MSB)."
556
        try:
1✔
557
            o = int(other)
1✔
558
        except ValidityError:
×
559
            o = None
×
560

561
        v = self.__copy__()
1✔
562
        if o is None:
1!
563
            v.vld_mask = 0
×
564
            v.val = 0
×
565
        elif o == 0:
1✔
566
            return v
1✔
567
        else:
568
            if o < 0:
1!
569
                raise ValueError("negative shift count")
×
570
            w = self._dtype.bit_length()
1✔
571
            if o < w:
1!
572
                v.vld_mask >>= o
1✔
573
                v.vld_mask |= bit_field(w - o, w)
1✔
574
                if v.val < 0:
1✔
575
                    assert self._dtype.signed
1✔
576
                    v.val = to_unsigned(v.val, w)
1✔
577
                v.val >>= o
1✔
578
            else:
579
                # completely shifted out
580
                v.val = 0
×
581
                v.vld_mask = mask(w)
×
582
        return v
1✔
583

584
    def __lshift__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
585
        "Operator <<. (shifts in 0)"
586
        try:
1✔
587
            o = int(other)
1✔
588
        except ValidityError:
×
589
            o = None
×
590

591
        v = self.__copy__()
1✔
592
        if o is None:
1!
593
            v.vld_mask = 0
×
594
            v.val = 0
×
595
        elif o == 0:
1✔
596
            return v
1✔
597
        else:
598
            if o < 0:
1!
599
                raise ValueError("negative shift count")
×
600
            t = self._dtype
1✔
601
            m = t.all_mask()
1✔
602
            v.vld_mask <<= o
1✔
603
            v.vld_mask |= mask(o)
1✔
604
            v.vld_mask &= m
1✔
605
            v.val <<= o
1✔
606
            v.val &= m
1✔
607
            assert v.val >= 0, v.val
1✔
608
        return v
1✔
609

610
    def __floordiv__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
611
        "Operator //."
612
        other_is_int = isinstance(other, int)
1✔
613
        if other_is_int:
1✔
614
            v = self.val // other
1✔
615
            m = self._dtype.all_mask()
1✔
616
        else:
617
            if self._is_full_valid() and other._is_full_valid():
1✔
618
                v = self.val // other.val
1✔
619
                m = self._dtype.all_mask()
1✔
620
            else:
621
                v = 0
1✔
622
                m = 0
1✔
623
        return self._dtype._from_py(v, m)
1✔
624

625
    def __mul__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
626
        "Operator *."
627
        # [TODO] resT should be wider
628
        resT = self._dtype
1✔
629
        other_is_int = isinstance(other, int)
1✔
630
        if other_is_int:
1!
UNCOV
631
            v = self.val * other
×
632
        elif isinstance(other, Bits3val):
1✔
633
            v = self.val * other.val
1✔
634
        else:
635
            raise TypeError(other)
1✔
636

637
        v &= resT.all_mask()
1✔
638
        if resT.signed:
1✔
639
            v = to_signed(v, resT.bit_length())
1✔
640

641
        if self._is_full_valid() and (other_is_int
1✔
642
                                      or other._is_full_valid()):
643
            vld_mask = resT._all_mask
1✔
644
        else:
645
            vld_mask = 0
1✔
646

647
        return resT._from_py(v, vld_mask)
1✔
648

649
    def _ternary(self, a, b):
1✔
650
        """
651
        Ternary operator (a if self else b).
652
        """
653
        try:
1✔
654
            if self:
1✔
655
                return a
1✔
656
            else:
657
                return b
1✔
UNCOV
658
        except ValidityError:
×
659
            pass
×
660
        res = copy(a)
×
661
        res.vld_mask = 0
×
662
        return res
×
663

664
    def __repr__(self):
665
        t = self._dtype
666
        if self.vld_mask != t.all_mask():
667
            m = ", mask {0:x}".format(self.vld_mask)
668
        else:
669
            m = ""
670
        typeDescrChar = 'b' if t.signed is None else 'i' if t.signed else 'u'
671
        return f"<{self.__class__.__name__:s} {typeDescrChar:s}{t.bit_length():d} {to_signed(self.val, t.bit_length()) if t.signed else self.val:d}{m:s}>"
672

673

674
def bitsBitOp__ror(self: Bits3val, shAmount: Union[Bits3val, int]):
1✔
675
    """
676
    rotate right by specified amount
677
    """
678
    t = self._dtype
×
679
    width = t.bit_length()
×
680
    try:
×
681
        shAmount = int(shAmount)
×
682
    except ValidityError:
×
UNCOV
683
        return t.from_py(None)
×
684
    assert shAmount >= 0
×
685

686
    if t.signed:
×
687
        v = to_unsigned(self.val, width)
×
688
    else:
689
        v = self.val
×
UNCOV
690
    v = rotate_right(v, width, shAmount)
×
UNCOV
691
    if t.signed:
×
UNCOV
692
        v = to_signed(v, width)
×
UNCOV
693
    return t.from_py(v, rotate_right(self.vld_mask, width, shAmount))
×
694

695

696
def bitsBitOp__rol(self: Bits3val, shAmount: Union[Bits3val, int]):
1✔
697
    """
698
    rotate left by specified amount
699
    """
UNCOV
700
    t = self._dtype
×
UNCOV
701
    width = t.bit_length()
×
UNCOV
702
    try:
×
UNCOV
703
        shAmount = int(shAmount)
×
UNCOV
704
    except ValidityError:
×
UNCOV
705
        return t.from_py(None)
×
UNCOV
706
    assert shAmount >= 0
×
UNCOV
707
    if t.signed:
×
UNCOV
708
        v = to_unsigned(self.val, width)
×
709
    else:
UNCOV
710
        v = self.val
×
UNCOV
711
    v = rotate_left(v, width, shAmount)
×
UNCOV
712
    if t.signed:
×
UNCOV
713
        v = to_signed(v, width)
×
UNCOV
714
    return t.from_py(v, rotate_left(self.vld_mask, width, shAmount))
×
715

716

717
def bitsBitOp__lshr(self: Bits3val, shAmount: Union[Bits3val, int]):
1✔
UNCOV
718
    t = self._dtype
×
UNCOV
719
    width = t.bit_length()
×
UNCOV
720
    try:
×
UNCOV
721
        shAmount = int(shAmount)
×
UNCOV
722
    except ValidityError:
×
UNCOV
723
        return t.from_py(None)
×
UNCOV
724
    assert shAmount >= 0
×
725

UNCOV
726
    if t.signed:
×
UNCOV
727
        v = to_unsigned(self.val, width)
×
728
    else:
UNCOV
729
        v = self.val
×
UNCOV
730
    v >>= shAmount
×
UNCOV
731
    if t.signed:
×
UNCOV
732
        v = to_signed(v, width)
×
UNCOV
733
    return t.from_py(v, self.vld_mask >> shAmount)
×
734

735

736
def bitsBitOp__val(self: Bits3val, other: Union[Bits3val, int],
1✔
737
                   evalFn, getVldFn) -> "Bits3val":
738
    """
739
    Apply bitwise operator
740
    """
741
    res_t = self._dtype
1✔
742
    if isinstance(other, int):
1✔
743
        other = res_t.from_py(other)
1✔
744
    w = res_t.bit_length()
1✔
745
    assert w == other._dtype.bit_length(), (res_t, other._dtype)
1✔
746
    vld = getVldFn(self, other)
1✔
747
    res = evalFn(self.val, other.val) & vld
1✔
748
    if res_t.signed:
1✔
749
        res = to_signed(res, w)
1✔
750

751
    return res_t._from_py(res, vld)
1✔
752

753

754
def bitsCmp__val(self: Bits3val, other: Union[Bits3val, int],
1✔
755
                 evalFn: Callable[[int, int], bool]) -> "Bits3val":
756
    """
757
    Apply comparative operator
758
    """
759
    t = self._dtype
1✔
760
    if isinstance(other, int):
1✔
761
        other = t.from_py(other)
1✔
762
        ot = other._dtype
1✔
763
        w = t.bit_length()
1✔
764
    else:
765
        ot = other._dtype
1✔
766
        w = t.bit_length()
1✔
767
        if bool(t.signed) != bool(ot.signed) or w != ot.bit_length():
1✔
768
            raise TypeError("Value compare supports only same width and sign type", t, ot)
1✔
769

770
    vld = self.vld_mask & other.vld_mask
1✔
771
    _vld = int(vld == t._all_mask)
1✔
772
    res = evalFn(self.val, other.val) & _vld
1✔
773

774
    return self._BOOL._from_py(int(res), int(_vld))
1✔
775

776

777
def bitsArithOp__val(self: Bits3val, other: Union[Bits3val, int],
1✔
778
                     evalFn: Callable[[int, int], int]) -> "Bits3val":
779
    """
780
    Apply arithmetic operator
781
    """
782
    if isinstance(other, int):
1!
783
        other = self._dtype.from_py(other)
1✔
784
    v = self.__copy__()
1✔
785
    self_vld = self._is_full_valid()
1✔
786
    other_vld = other._is_full_valid()
1✔
787

788
    v.val = evalFn(self.val, other.val)
1✔
789

790
    w = v._dtype.bit_length()
1✔
791
    if self._dtype.signed:
1✔
792
        _v = v.val
1✔
793
        _max = mask(w - 1)
1✔
794
        _min = -_max - 1
1✔
795
        if _v > _max:
1✔
796
            _v = _min + (_v - _max - 1)
1✔
797
        elif _v < _min:
1✔
798
            _v = _max - (_v - _min + 1)
1✔
799

800
        v.val = _v
1✔
801
    else:
802
        v.val &= mask(w)
1✔
803

804
    if self_vld and other_vld:
1!
805
        v.vld_mask = mask(w)
1✔
806
    else:
UNCOV
807
        v.vld_mask = 0
×
808

809
    return v
1✔
810

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc