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

Nic30 / pyMathBitPrecise / 0672557f-2e3a-4664-9ea9-e805b1cc4c06

23 Aug 2023 01:06PM UTC coverage: 83.124% (-0.2%) from 83.348%
0672557f-2e3a-4664-9ea9-e805b1cc4c06

push

circleci

Nic30
Bits3val._concat fix sign handling

200 of 254 branches covered (78.74%)

Branch coverage included in aggregate %.

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

726 of 860 relevant lines covered (84.42%)

0.84 hits per line

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

84.14
/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
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
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 anotation
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 comparision 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 bouth are not strict)
39
    """
40

41
    def __init__(self, bit_length: int, signed=False, name: Optional[str]=None,
1✔
42
                 force_vector=False,
43
                 strict_sign=True, strict_width=True):
44
        self._bit_length = bit_length
1✔
45
        self.signed = signed
1✔
46
        self._all_mask = mask(bit_length)
1✔
47
        self.name = name
1✔
48
        self.force_vector = force_vector
1✔
49
        self.strict_sign = strict_sign
1✔
50
        self.strict_width = strict_width
1✔
51

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

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

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

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

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

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

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

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

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

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

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

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

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

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

200
    def __repr__(self):
201
        """
202
        :param indent: number of indentation
203
        :param withAddr: if is not None is used as a additional
204
            information about on which address this type is stored
205
            (used only by HStruct)
206
        :param expandStructs: expand HStructTypes (used by HStruct and HArray)
207
        """
208
        constr = []
209
        if self.name is not None:
210
            constr.append(f'"{self.name:s}"')
211
        c = self.bit_length()
212
        constr.append(f"{c:d}bits")
213
        if self.force_vector:
214
            constr.append("force_vector")
215
        if self.signed:
216
            constr.append("signed")
217
        elif self.signed is False:
218
            constr.append("unsigned")
219
        if not self.strict_sign:
220
            constr.append("strict_sign=False")
221
        if not self.strict_width:
222
            constr.append("strict_width=False")
223

224
        return "<%s, %s>" % (self.__class__.__name__,
225
                             ", ".join(constr))
226

227

228
class Bits3val():
1✔
229
    """
230
    Class for value of `Bits3t` type
231

232
    :ivar ~._dtype: reference on type of this value
233
    :ivar ~.val: always unsigned representation int value
234
    :ivar ~.vld_mask: always unsigned value of the mask, if bit in mask is '0'
235
            the corresponding bit in val is invalid
236
    """
237
    _BOOL = Bits3t(1)
1✔
238

239
    def __init__(self, t: Bits3t, val: int, vld_mask: int):
1✔
240
        if not isinstance(t, Bits3t):
1!
241
            raise TypeError(t)
×
242
        if type(val) != int:
1!
243
            raise TypeError(val)
×
244
        if type(vld_mask) != int:
1!
245
            raise TypeError(vld_mask)
×
246
        self._dtype = t
1✔
247
        self.val = val
1✔
248
        self.vld_mask = vld_mask
1✔
249

250
    def __copy__(self):
1✔
251
        return self.__class__(self._dtype, self.val, self.vld_mask)
1✔
252

253
    def to_py(self) -> int:
1✔
254
        return int(self)
×
255

256
    def _is_full_valid(self) -> bool:
1✔
257
        """
258
        :return: True if all bits in value are valid
259
        """
260
        return self.vld_mask == self._dtype.all_mask()
1✔
261

262
    def __int__(self) -> int:
1✔
263
        "int(self)"
264
        if not self._is_full_valid():
1✔
265
            raise ValidityError()
1✔
266

267
        return self.val
1✔
268

269
    def __bool__(self) -> bool:
1✔
270
        "bool(self)"
271
        return bool(self.__int__())
1✔
272

273
    def _auto_cast(self, dtype):
1✔
274
        """
275
        Cast value to a compatible type
276
        """
277
        return dtype.from_py(self.val, self.vld_mask)
×
278

279
    def cast_sign(self, signed) -> "Bits3val":
1✔
280
        """
281
        Cast signed-unsigned value
282
        """
283
        t = self._dtype
1✔
284
        if t.signed == signed:
1!
285
            return self
×
286
        selfSign = t.signed
1✔
287
        v = self.__copy__()
1✔
288
        m = t._all_mask
1✔
289
        _v = v.val
1✔
290

291
        if selfSign and not signed:
1✔
292
            if _v < 0:
1!
293
                v.val = m + _v + 1
1✔
294
        elif not selfSign and signed:
1!
295
            w = t.bit_length()
1✔
296
            v.val = to_signed(_v, w)
1✔
297

298
        v._dtype = v._dtype.__copy__()
1✔
299
        v._dtype = self._dtype.__copy__()
1✔
300
        v._dtype.signed = signed
1✔
301
        return v
1✔
302

303
    def cast(self, t: Bits3t) -> "Bits3val":
1✔
304
        """
305
        C++: static_cast<t>(self)
306

307
        :note: no sign extension
308
        """
309
        v = self.__copy__()
1✔
310
        v._dtype = t
1✔
311
        m = t.all_mask()
1✔
312
        v.val &= m
1✔
313
        v.vld_mask &= m
1✔
314
        if t.signed:
1✔
315
            v.val = to_signed(v.val, t.bit_length())
1✔
316
        return v
1✔
317

318
    def _concat(self, other: "Bits3val") -> "Bits3val":
1✔
319
        """
320
        Concatenate two bit vectors together
321
        Verilog: {self, other}, VHDL: self & other
322
        """
323
        if not isinstance(other, Bits3val):
1✔
324
            raise TypeError(other)
1✔
325
        w = self._dtype.bit_length()
1✔
326
        other_w = other._dtype.bit_length()
1✔
327
        resWidth = w + other_w
1✔
328
        resT = self._dtype.__class__(resWidth, signed=False)
1✔
329
        other_val = other.val
1✔
330
        if other_val < 0:
1!
331
            other_val = to_unsigned(other_val, other_w)
×
332
        v = self.__copy__()
1✔
333
        if v.val < 0:
1!
334
            v.val = to_unsigned(v.val, w)
×
335
        v.val = (v.val << other_w) | other_val
1✔
336
        v.vld_mask = (v.vld_mask << other_w) | other.vld_mask
1✔
337
        v._dtype = resT
1✔
338
        return v
1✔
339

340
    def __getitem__(self, key: Union[int, slice, "Bits3val"]) -> "Bits3val":
1✔
341
        "self[key]"
342
        if isinstance(key, slice):
1✔
343
            firstBitNo, size = normalize_slice(key, self._dtype.bit_length())
1✔
344
            val = get_bit_range(self.val, firstBitNo, size)
1✔
345
            vld = get_bit_range(self.vld_mask, firstBitNo, size)
1✔
346
        elif isinstance(key, (int, Bits3val)):
1✔
347
            size = 1
1✔
348
            try:
1✔
349
                _i = int(key)
1✔
350
            except ValidityError:
×
351
                _i = None
×
352

353
            if _i is None:
1!
354
                val = 0
×
355
                vld = 0
×
356
            else:
357
                if _i < 0 or _i >= self._dtype.bit_length():
1✔
358
                    raise IndexError("Index out of range", _i)
1✔
359

360
                val = get_bit(self.val, _i)
1✔
361
                vld = get_bit(self.vld_mask, _i)
1✔
362
        else:
363
            raise TypeError(key)
1✔
364

365
        new_t = self._dtype.__class__(size, signed=False)
1✔
366
        return new_t._from_py(val, vld)
1✔
367

368
    def __setitem__(self, index: Union[slice, int, "Bits3val"],
1✔
369
                    value: Union["Bits3val", int]):
370
        "An item assignment operator self[index] = value."
371
        if isinstance(index, slice):
1✔
372
            firstBitNo, size = normalize_slice(index, self._dtype.bit_length())
1✔
373
            if isinstance(value, Bits3val):
1!
374
                v = value.val
×
375
                m = value.vld_mask
×
376
            else:
377
                v = value
1✔
378
                m = mask(size)
1✔
379

380
            self.val = set_bit_range(self.val, firstBitNo, size, v)
1✔
381
            self.vld_mask = set_bit_range(
1✔
382
                self.vld_mask, firstBitNo, size, m)
383
        else:
384
            if index is None:
1✔
385
                raise TypeError(index)
1✔
386
            try:
1✔
387
                _i = int(index)
1✔
388
            except ValidityError:
×
389
                _i = None
×
390

391
            if _i is None:
1!
392
                self.val = 0
×
393
                self.vld_mask = 0
×
394
            else:
395
                if value is None:
1✔
396
                    v = 0
1✔
397
                    m = 0
1✔
398
                elif isinstance(value, Bits3val):
1!
399
                    v = value.val
×
400
                    m = value.vld_mask
×
401
                else:
402
                    v = value
1✔
403
                    m = 0b1
1✔
404
                try:
1✔
405
                    index = int(index)
1✔
406
                except ValidityError:
×
407
                    index = None
×
408
                if index is None:
1!
409
                    self.val = 0
×
410
                    self.vld_mask = 0
×
411
                else:
412
                    self.val = bit_set_to(self.val, index, v)
1✔
413
                    self.vld_mask = bit_set_to(self.vld_mask, index, m)
1✔
414

415
    def __invert__(self) -> "Bits3val":
1✔
416
        "Operator ~x."
417
        v = self.__copy__()
1✔
418
        v.val = ~v.val
1✔
419
        w = v._dtype.bit_length()
1✔
420
        v.val &= mask(w)
1✔
421
        if self._dtype.signed:
1✔
422
            v.val = to_signed(v.val, w)
1✔
423
        return v
1✔
424

425
    def __neg__(self):
1✔
426
        "Operator -x."
427
        if not self._dtype.signed:
1✔
428
            raise TypeError("- operator is defined only for signed")
1✔
429

430
        v = self.__copy__()
1✔
431
        _v = -v.val
1✔
432
        _max = self._dtype.all_mask() >> 1
1✔
433
        _min = -_max - 1
1✔
434
        if _v > _max:
1✔
435
            _v = _min + (_v - _max - 1)
1✔
436
        elif _v < _min:
1!
437
            _v = _max - (_v - _min + 1)
×
438
        v.val = _v
1✔
439
        return v
1✔
440

441
    def __hash__(self):
1✔
442
        return hash((self._dtype, self.val, self.vld_mask))
×
443

444
    def _is(self, other):
1✔
445
        """check if other is object with same values"""
446
        return isinstance(other, Bits3val)\
×
447
            and self._dtype == other._dtype\
448
            and self.val == other.val\
449
            and self.vld_mask == other.vld_mask
450

451
    def _eq(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
452
        """
453
        Operator self._eq(other) as self == other
454
        == is not overriden in order to prevent tricky behavior if hashing partially valid values
455
        """
456
        return bitsCmp__val(self, other, eq)
1✔
457

458
    def __req__(self, other: int) -> "Bits3val":
1✔
459
        "Operator ==."
460
        return bitsCmp__val(self._dtype.from_py(other), self, eq)
×
461

462
    def __ne__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
463
        "Operator !=."
464
        return bitsCmp__val(self, other, ne)
1✔
465

466
    def __rne__(self, other: int) -> "Bits3val":
1✔
467
        "Operator !=."
468
        return bitsCmp__val(self._dtype.from_py(other), self, ne)
×
469

470
    def __lt__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
471
        "Operator <."
472
        return bitsCmp__val(self, other, lt)
1✔
473

474
    def __rlt__(self, other: int) -> "Bits3val":
1✔
475
        "Operator <."
476
        return bitsCmp__val(self._dtype.from_py(other), self, lt)
×
477

478
    def __gt__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
479
        "Operator >."
480
        return bitsCmp__val(self, other, gt)
1✔
481

482
    def __rgt__(self, other: int) -> "Bits3val":
1✔
483
        "Operator >."
484
        return bitsCmp__val(self._dtype.from_py(other), self, gt)
×
485

486
    def __ge__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
487
        "Operator >=."
488
        return bitsCmp__val(self, other, ge)
1✔
489

490
    def __rge__(self, other: int) -> "Bits3val":
1✔
491
        "Operator >=."
492
        return bitsCmp__val(self._dtype.from_py(other), self, ge)
×
493

494
    def __le__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
495
        "Operator <=."
496
        return bitsCmp__val(self, other, le)
1✔
497

498
    def __rle__(self, other: int) -> "Bits3val":
1✔
499
        "Operator <=."
500
        return bitsCmp__val(self._dtype.from_py(other), self, le)
×
501

502
    def __xor__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
503
        "Operator ^."
504
        return bitsBitOp__val(self, other, xor, vld_mask_for_xor)
1✔
505

506
    def __rxor__(self, other: int) -> "Bits3val":
1✔
507
        "Operator ^."
508
        return bitsBitOp__val(self._dtype.from_py(other), self, xor,
×
509
                              vld_mask_for_xor)
510

511
    def __and__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
512
        "Operator &."
513
        return bitsBitOp__val(self, other, and_, vld_mask_for_and)
1✔
514

515
    def __rand__(self, other: int) -> "Bits3val":
1✔
516
        "Operator &."
517
        return bitsBitOp__val(self._dtype.from_py(other), self, and_,
×
518
                              vld_mask_for_and)
519

520
    def __or__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
521
        "Operator |."
522
        return bitsBitOp__val(self, other, or_, vld_mask_for_or)
1✔
523

524
    def __ror__(self, other: int) -> "Bits3val":
1✔
525
        "Operator |."
526
        return bitsBitOp__val(self._dtype.from_py(other), self, or_,
×
527
                              vld_mask_for_or)
528

529
    def __sub__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
530
        "Operator -."
531
        return bitsArithOp__val(self, other, sub)
1✔
532

533
    def __rsub__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
534
        "Operator -."
535
        return bitsArithOp__val(self._dtype.from_py(other), self, sub)
×
536

537
    def __add__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
538
        "Operator +."
539
        return bitsArithOp__val(self, other, add)
1✔
540

541
    def __radd__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
542
        "Operator +."
543
        return bitsArithOp__val(self._dtype.from_py(other), self, add)
×
544

545
    def __rshift__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
546
        "Operator >>."
547
        try:
1✔
548
            o = int(other)
1✔
549
        except ValidityError:
×
550
            o = None
×
551
        v = self.__copy__()
1✔
552
        if o is None:
1!
553
            v.vld_mask = 0
×
554
            v.val = 0
×
555
        elif o == 0:
1✔
556
            return v
1✔
557
        else:
558
            if o < 0:
1!
559
                raise ValueError("negative shift count")
×
560
            w = self._dtype.bit_length()
1✔
561
            v.vld_mask >>= o
1✔
562
            v.vld_mask |= bit_field(w - o, w)
1✔
563
            if v.val < 0:
1✔
564
                assert self._dtype.signed
1✔
565
                v.val = to_unsigned(v.val, w)
1✔
566
            v.val >>= o
1✔
567

568
        return v
1✔
569

570
    def __lshift__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
571
        "Operator <<."
572
        try:
1✔
573
            o = int(other)
1✔
574
        except ValidityError:
×
575
            o = None
×
576

577
        v = self.__copy__()
1✔
578
        if o is None:
1!
579
            v.vld_mask = 0
×
580
            v.val = 0
×
581
        elif o == 0:
1✔
582
            return v
1✔
583
        else:
584
            if o < 0:
1!
585
                raise ValueError("negative shift count")
×
586
            t = self._dtype
1✔
587
            m = t.all_mask()
1✔
588
            v.vld_mask <<= o
1✔
589
            v.vld_mask |= mask(o)
1✔
590
            v.vld_mask &= m
1✔
591
            v.val <<= o
1✔
592
            v.val &= m
1✔
593
            if t.signed:
1✔
594
                v.val = to_signed(v.val, t.bit_length())
1✔
595
        return v
1✔
596

597
    def __floordiv__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
598
        "Operator //."
599
        other_is_int = isinstance(other, int)
1✔
600
        if other_is_int:
1✔
601
            v = self.val // other
1✔
602
            m = self._dtype.all_mask()
1✔
603
        else:
604
            if self._is_full_valid() and other._is_full_valid():
1✔
605
                v = self.val // other.val
1✔
606
                m = self._dtype.all_mask()
1✔
607
            else:
608
                v = 0
1✔
609
                m = 0
1✔
610
        return self._dtype._from_py(v, m)
1✔
611

612
    def __mul__(self, other: Union[int, "Bits3val"]) -> "Bits3val":
1✔
613
        "Operator *."
614
        # [TODO] resT should be wider
615
        resT = self._dtype
1✔
616
        other_is_int = isinstance(other, int)
1✔
617
        if other_is_int:
1!
618
            v = self.val * other
×
619
        elif isinstance(other, Bits3val):
1✔
620
            v = self.val * other.val
1✔
621
        else:
622
            raise TypeError(other)
1✔
623

624
        v &= resT.all_mask()
1✔
625
        if resT.signed:
1✔
626
            v = to_signed(v, resT.bit_length())
1✔
627

628
        if self._is_full_valid() and (other_is_int
1✔
629
                                      or other._is_full_valid()):
630
            vld_mask = resT._all_mask
1✔
631
        else:
632
            vld_mask = 0
1✔
633

634
        return resT._from_py(v, vld_mask)
1✔
635

636
    def _ternary(self, a, b):
1✔
637
        """
638
        Ternary operator (a if self else b).
639
        """
640
        try:
1✔
641
            if self:
1✔
642
                return a
1✔
643
            else:
644
                return b
1✔
645
        except ValidityError:
×
646
            pass
×
647
        res = copy(a)
×
648
        res.vld_mask = 0
×
649
        return res
×
650

651
    def __repr__(self):
652
        if self.vld_mask != self._dtype.all_mask():
653
            m = ", mask {0:x}".format(self.vld_mask)
654
        else:
655
            m = ""
656
        return "<{0:s} {1:s}{2:s}>".format(
657
            self.__class__.__name__, repr(self.val), m)
658

659

660
def bitsBitOp__val(self: Bits3val, other: Union[Bits3val, int],
1✔
661
                   evalFn, getVldFn) -> "Bits3val":
662
    """
663
    Apply bitwise operator
664
    """
665
    res_t = self._dtype
1✔
666
    if isinstance(other, int):
1✔
667
        other = res_t.from_py(other)
1✔
668
    w = res_t.bit_length()
1✔
669
    assert w == other._dtype.bit_length(), (res_t, other._dtype)
1✔
670
    vld = getVldFn(self, other)
1✔
671
    res = evalFn(self.val, other.val) & vld
1✔
672
    if res_t.signed:
1✔
673
        res = to_signed(res, w)
1✔
674

675
    return res_t._from_py(res, vld)
1✔
676

677

678
def bitsCmp__val(self: Bits3val, other: Union[Bits3val, int],
1✔
679
                 evalFn) -> "Bits3val":
680
    """
681
    Apply comparative operator
682
    """
683
    t = self._dtype
1✔
684
    if isinstance(other, int):
1✔
685
        other = t.from_py(other)
1✔
686
        ot = other._dtype
1✔
687
        w = t.bit_length()
1✔
688
    else:
689
        ot = other._dtype
1✔
690
        w = t.bit_length()
1✔
691
        if t.signed != ot.signed or w != ot.bit_length():
1✔
692
            raise TypeError(t, ot)
1✔
693

694
    vld = self.vld_mask & other.vld_mask
1✔
695
    _vld = int(vld == t._all_mask)
1✔
696
    res = evalFn(self.val, other.val) & _vld
1✔
697

698
    return self._BOOL._from_py(int(res), int(_vld))
1✔
699

700

701
def bitsArithOp__val(self: Bits3val, other: Union[Bits3val, int],
1✔
702
                     evalFn) -> "Bits3val":
703
    """
704
    Apply arithmetic operator
705
    """
706
    if isinstance(other, int):
1!
707
        other = self._dtype.from_py(other)
1✔
708
    v = self.__copy__()
1✔
709
    self_vld = self._is_full_valid()
1✔
710
    other_vld = other._is_full_valid()
1✔
711

712
    v.val = evalFn(self.val, other.val)
1✔
713

714
    w = v._dtype.bit_length()
1✔
715
    if self._dtype.signed:
1✔
716
        _v = v.val
1✔
717
        _max = mask(w - 1)
1✔
718
        _min = -_max - 1
1✔
719
        if _v > _max:
1✔
720
            _v = _min + (_v - _max - 1)
1✔
721
        elif _v < _min:
1✔
722
            _v = _max - (_v - _min + 1)
1✔
723

724
        v.val = _v
1✔
725
    else:
726
        v.val &= mask(w)
1✔
727

728
    if self_vld and other_vld:
1!
729
        v.vld_mask = mask(w)
1✔
730
    else:
731
        v.vld_mask = 0
×
732

733
    return v
1✔
734

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