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

Nic30 / pyMathBitPrecise / 4812b684-948f-4186-9369-246178a3729f

30 Oct 2026 10:05PM UTC coverage: 67.967% (-0.08%) from 68.05%
4812b684-948f-4186-9369-246178a3729f

push

circleci

Nic30
feat(bit_utils): apply_write_with_mask_int

241 of 406 branches covered (59.36%)

Branch coverage included in aggregate %.

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

909 of 1286 relevant lines covered (70.68%)

0.71 hits per line

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

52.07
/pyMathBitPrecise/bit_utils.py
1
#!/usr/bin/env python3
2
# -*- coding: UTF-8 -*-
3
import math
1 ✔
4
from typing import Generator, Union, Optional, Literal, Sequence
1 ✔
5

6
from pyMathBitPrecise.utils import grouper
1 ✔
7

8

9
def mask(bits: int) -> int:
1 ✔
10
    """
11
    Generate mask of specified size (sequence of '1')
12
    """
13
    return (1 << bits) - 1
1 ✔
14

15

16
def bit_field(_from: int, to: int) -> int:
1 ✔
17
    """
18
    Generate int which has bits '_from' to 'to' set to '1'
19

20
    :note: _from 0 to 1 -> '1'
21
    """
22
    w = to - _from
1 ✔
23
    return mask(w) << _from
1 ✔
24

25

26
def get_bit(val: int, bitNo: int) -> int:
1 ✔
27
    """
28
    Get bit from int
29
    """
30
    return (val >> bitNo) & 1
1 ✔
31

32

33
def get_bit_range(val: int, bitsStart: int, bitsLen: int) -> int:
1 ✔
34
    """
35
    Get sequence of bits from an int value
36
    """
37
    val >>= bitsStart
1 ✔
38
    return val & mask(bitsLen)
1 ✔
39

40

41
def get_single_1_at_position_of_least_significant_0(x: int):
1 ✔
42
    """
43
    Hacker's Delight: 2nd Edition, 2-1 Manipulating Rightmost Bits
44
    
45
    10100111 -> 00001000
46
    """
47
    assert x >= 0, x
1 ✔
48
    return ~x & (x + 1)
1 ✔
49

50

51
def get_single_0_at_position_of_least_significant_1(x: int, width: int):
1 ✔
52
    """
53
    Hacker's Delight: 2nd Edition, 2-1 Manipulating Rightmost Bits
54
    
55
    10101000 -> 11110111
56
    """
57
    assert x >= 0, x
1 ✔
58
    res = ~x | (x - 1)
1 ✔
59
    return to_unsigned(res, width)
1 ✔
60

61

62
def clean_bit(val: int, bitNo: int) -> int:
1 ✔
63
    """
64
    Set a specified bit to '0'
65
    """
66
    return val & ~(1 << bitNo)
1 ✔
67

68

69
def clear_least_significant_1(x: int) -> int:
1 ✔
70
    """
71
    Hacker's Delight: 2nd Edition, 2-1 Manipulating Rightmost Bits
72
    010110 -> 010100
73
    
74
    :note: can be used for 2**n test
75
    """
76
    # :note: this is equivalent to x - (x & -x)
77
    return x & (x - 1)
1 ✔
78

79

80
def clear_trailing_1s(x: int) -> int:
1 ✔
81
    """
82
    Hacker's Delight: 2nd Edition, 2-1 Manipulating Rightmost Bits
83
    10100111 -> 10100000
84
    
85
    :note: can be used for 2**n - 1 test
86
    """
87
    return x & (x + 1)
1 ✔
88

89

90
def set_bit(val: int, bitNo: int) -> int:
1 ✔
91
    """
92
    Set a specified bit to '1'
93
    """
94
    return val | (1 << bitNo)
1 ✔
95

96

97
def set_least_significant_0(x: int) -> int:
1 ✔
98
    """
99
    Hacker's Delight: 2nd Edition, 2-1 Manipulating Rightmost Bits
100

101
    101001 -> 101011
102
    """
103
    return x | (x + 1)
1 ✔
104

105

106
def set_trailing_0s(x: int) -> int:
1 ✔
107
    """
108
    Hacker's Delight: 2nd Edition, 2-1 Manipulating Rightmost Bits
109

110
    10101000 -> 10101111
111
    """
112
    return x | (x - 1)
1 ✔
113

114

115
def separate_least_significant_1(x: int):
1 ✔
116
    """
117
    1100 -> 0100
118
    """
119
    return x & -x
×
120

121

122
def toggle_bit(val: int, bitNo: int) -> int:
1 ✔
123
    """
124
    Toggle specified bit in int
125
    """
126
    return val ^ (1 << bitNo)
1 ✔
127

128

129
def set_bit_range(val: int, bitStart: int, bitsLen: int, newBits: int) -> int:
1 ✔
130
    """
131
    Set specified range of bits in int to a specified value
132
    """
133
    _mask = mask(bitsLen)
1 ✔
134
    newBits &= _mask
1 ✔
135

136
    _mask <<= bitStart
1 ✔
137
    newBits <<= bitStart
1 ✔
138

139
    return (val & ~_mask) | newBits
1 ✔
140

141

142
def bit_set_to(val: int, bitNo: int, bitVal: int) -> int:
1 ✔
143
    """
144
    Set specified bit in int to a specified value
145
    """
146
    if bitVal == 0:
1 ✔
147
        return clean_bit(val, bitNo)
1 ✔
148
    elif bitVal == 1:
1 !
149
        return set_bit(val, bitNo)
1 ✔
150
    else:
151
        raise ValueError(("Invalid value of bit to set", bitVal))
×
152

153

154
def byte_mask_to_bit_mask_int(m: int, width: int, byte_width:int=8) -> int:
1 ✔
155
    """
156
    Expands each bit byte_width times to convert from byte mask to bit mask
157
    """
158
    res = 0
×
159
    mTmp = m
×
160
    byte_mask = mask(byte_width)
×
161
    for i in range(width):
×
162
        b = mTmp & 1
×
163
        if b:
×
164
            res |= byte_mask << (i * byte_width)
×
165
        mTmp >>= 1
×
166

167
    return res
×
168

169

170
def byte_mask_to_bit_mask(m: "Bits3Val", byte_width:int=8) -> "Bits3Val":
1 ✔
171
    """
172
    Replicate each bit byte_width times
173
    """
174
    res = None
×
175
    for b in m:
×
176
        if res is None:
×
177
            res = b._sext(byte_width)
×
178
        else:
179
            res = b._sext(byte_width)._concat(res)
×
180

181
    return res
×
182

183

184
def bit_mask_to_byte_mask_int(m: int, width: int, byte_width:int=8) -> int:
1 ✔
185
    """
186
    Compresses all bit in byte to 1 bit to convert from bit mask to byte mask
187
    """
188
    assert width % byte_width == 0
×
189
    mTmp = m
×
190
    res = 0
×
191
    byte_mask = mask(byte_width)
×
192
    for i in range(width // byte_width):
×
193
        B = mTmp & byte_mask
×
194
        if B == byte_mask:
×
195
            res |= 1 << i
×
196
        else:
197
            assert B == 0, "Each byte must be entirely set or entirely unset"
×
198
        mTmp >>= byte_width
×
199

200
    return res
×
201

202

203
def apply_set_and_clear(val: "Bits3val", set_flag: "Bits3val", clear_flag: "Bits3val") -> "Bits3val":
1 ✔
204
    """
205
    :param val: an input value of the flag(s)
206
    :param set_flag: a mask of bits to set to 1
207
    :param clear_flag: a mask of bits to set to 0
208
    :note: set has higher priority
209

210
    :return: new value of the flag
211
    """
212
    return (val & ~clear_flag) | set_flag
1 ✔
213

214

215
def apply_set_and_clear_int(val: int, set_flag: int, clear_flag: int, width: int) -> int:
1 ✔
216
    """
217
    same as :func:`apply_set_and_clear` just for int
218
    """
NEW
219
    return (val & to_unsigned(~clear_flag, width)) | set_flag
×
220

221

222
def apply_write_with_mask(current_data: "Bits3val", new_data: "Bits3val", write_mask: "Bits3val", byte_width:int=8) -> "Bits3val":
1 ✔
223
    """
224
    :return: an updated value current_data which has bytes defined by write_mask updated from new_data
225
    """
NEW
226
    m = byte_mask_to_bit_mask(write_mask, byte_width=byte_width)
×
227
    return apply_set_and_clear(current_data, new_data & m, m)
×
228

229

230
def apply_write_with_mask_int(current_data: Union["Bits3val", int], new_data: Union["Bits3val", int], write_mask: int, width:int, byte_width=8) -> Union["Bits3val", int]:
1 ✔
231
    """
232
    same as :func:`apply_write_with_mask` just for int
233
    """
NEW
234
    m = byte_mask_to_bit_mask_int(write_mask, width, byte_width=byte_width)
×
NEW
235
    return apply_set_and_clear_int(current_data, new_data & m, m, width)
×
236

237

238
def extend_to_width_multiple_of_8(v: "Bits3val") -> "Bits3val":
1 ✔
239
    """
240
    make width of signal modulo 8 equal to 0
241
    """
242
    w = v._dtype.bit_length()
×
243
    cosest_multiple_of_8 = math.ceil((w // 8) / 8) * 8
×
244
    if cosest_multiple_of_8 == w:
×
245
        return v
×
246
    else:
247
        return v._ext(cosest_multiple_of_8)
×
248

249

250
def align(val: int, lowerBitCntToAlign: int) -> int:
1 ✔
251
    """
252
    Cut off lower bits to align a int value.
253
    """
254
    val = val >> lowerBitCntToAlign
1 ✔
255
    return val << lowerBitCntToAlign
1 ✔
256

257

258
def align_with_known_width(val, width: int, lowerBitCntToAlign: int):
1 ✔
259
    """
260
    Does same as :func:`~.align` just with the known width of val
261
    """
262
    return val & (mask(width - lowerBitCntToAlign) << lowerBitCntToAlign)
×
263

264

265
def iter_bits(val: int, length: int) -> Generator[Literal[0, 1], None, None]:
1 ✔
266
    """
267
    Iterate bits in int. LSB first.
268
    """
269
    for _ in range(length):
1 ✔
270
        yield val & 1
1 ✔
271
        val >>= 1
1 ✔
272

273

274
def iter_bits_sequences(val: int, length: int) -> Generator[tuple[Literal[0, 1], int], None, None]:
1 ✔
275
    """
276
    Iter tuples (bitVal, number of same bits), lsb first
277
    """
278
    assert length > 0, length
×
279
    assert val >= 0
×
280
    # start of new bit seqence
281
    w = 1
×
282
    valBit = val & 1
×
283
    val >>= 1
×
284
    foundBit = valBit
×
285
    for _ in range(length - 1):
×
286
        # extract single bit from val
287
        valBit = val & 1
×
288
        val >>= 1
×
289
        # check if it fits into current bit sequence
290
        if valBit == foundBit:
×
291
            w += 1
×
292
        else:
293
            # end of sequence of same bits
294
            yield (foundBit, w)
×
295
            foundBit = valBit
×
296
            w = 1
×
297

298
    if w != 0:
×
299
        yield (foundBit, w)
×
300

301

302
def to_signed(val: int, width: int) -> int:
1 ✔
303
    """
304
    Convert unsigned int to negative int which has same bits set (emulate sign overflow).
305

306
    :note: bits in value are not changed, just python int object
307
        has signed flag set properly. And number is in expected range.
308
    """
309
    if val > 0:
1 ✔
310
        msb = 1 << (width - 1)
1 ✔
311
        if val & msb:
1 ✔
312
            val -= mask(width) + 1
1 ✔
313
    return val
1 ✔
314

315

316
def to_unsigned(val, width) -> int:
1 ✔
317
    if val < 0:
1 ✔
318
        return val & mask(width)
1 ✔
319
    else:
320
        return val
1 ✔
321

322

323
def mask_bytes(val: int, byte_mask: int, mask_bit_length: int) -> int:
1 ✔
324
    """
325
    Use each bit in byte_mask as a mask for each byte in val.
326

327
    :note: Useful for masking of value for HW interfaces where mask
328
        is represented by a vector of bits where each bit is mask
329
        for byte in data vector.
330
    """
331
    res = 0
1 ✔
332
    for i, m in enumerate(iter_bits(byte_mask, mask_bit_length)):
1 ✔
333
        if m:
1 ✔
334
            res |= (val & 0xff) << (i * 8)
1 ✔
335
        val >>= 8
1 ✔
336
    return res
1 ✔
337

338

339
INT_BASES = {
1 ✔
340
    "b": 2,
341
    "o": 8,
342
    "d": 10,
343
    "h": 16,
344
}
345

346

347
class ValidityError(ValueError):
1 ✔
348
    """
349
    Value is not fully defined and thus can not be used
350
    """
351

352

353
def normalize_slice(s: slice, obj_width: int) -> tuple[int, int]:
1 ✔
354
    start, stop, step = s.start, s.stop, s.step
1 ✔
355
    if step is not None and step != -1:
1 ✔
356
        raise NotImplementedError(s.step)
357
    else:
358
        step = -1
1 ✔
359
    if stop is None:
1 ✔
360
        stop = 0
1 ✔
361
    else:
362
        stop = int(stop)
1 ✔
363

364
    if start is None:
1 ✔
365
        start = int(obj_width)
1 ✔
366
    else:
367
        start = int(start)
1 ✔
368
    # n...0
369
    if start <= stop:
1 ✔
370
        raise IndexError(s)
1 ✔
371
    firstBitNo = stop
1 ✔
372
    size = start - stop
1 ✔
373
    if start < 0 or stop < 0 or size < 0 or start > obj_width:
1 ✔
374
        raise IndexError(s)
1 ✔
375

376
    return firstBitNo, size
1 ✔
377

378

379
def reverse_bits(val: int, width: int):
1 ✔
380
    """
381
    Reverse bits in integer value of specified width
382
    """
383
    v = 0
1 ✔
384
    for i in range(width):
1 ✔
385
        v |= (get_bit(val, width - i - 1) << i)
1 ✔
386
    return v
1 ✔
387

388

389
def extend_to_size(collection: Sequence, items: int, pad=0):
1 ✔
390
    toAdd = items - len(collection)
1 ✔
391
    assert toAdd >= 0
1 ✔
392
    for _ in range(toAdd):
1 ✔
393
        collection.append(pad)
1 ✔
394

395
    return collection
1 ✔
396

397

398
def rotate_right(v: int, width: int, shAmount:int):
1 ✔
399
    # https://www.geeksforgeeks.org/rotate-bits-of-an-integer/
400
    assert v >= 0, v
×
401
    assert width > 0, width
×
402
    assert shAmount >= 0, shAmount
×
403
    return (v >> shAmount) | ((v << (width - shAmount)) & mask(width))
×
404

405

406
def rotate_left(v: int, width: int, shAmount:int):
1 ✔
407
    # https://www.geeksforgeeks.org/rotate-bits-of-an-integer/
408
    assert v >= 0, v
×
409
    assert width > 0, width
×
410
    assert shAmount >= 0, shAmount
×
411
    return ((v << shAmount) & mask(width)) | (v >> (width - shAmount))
×
412

413

414
def bit_list_reversed_endianity(bitList: list[Literal[0, 1]], extend=True):
1 ✔
415
    w = len(bitList)
1 ✔
416
    i = w
1 ✔
417

418
    items: list[Literal[0, 1]] = []
1 ✔
419
    while i > 0:
1 ✔
420
        # take last 8 bits or rest
421
        lower = max(i - 8, 0)
1 ✔
422
        b = bitList[lower:i]
1 ✔
423
        if extend:
1 !
424
            extend_to_size(b, 8)
1 ✔
425
        items.extend(b)
1 ✔
426
        i -= 8
1 ✔
427

428
    return items
1 ✔
429

430

431
def bit_list_reversed_bits_in_bytes(bitList: list[Literal[0, 1]], extend=None):
1 ✔
432
    "Byte reflection  (0x0f -> 0xf0)"
433
    w = len(bitList)
1 ✔
434
    if extend is None:
1 !
435
        assert w % 8 == 0
1 ✔
436

437
    tmp: list[Literal[0, 1]] = []
1 ✔
438
    for db in grouper(8, bitList, padvalue=0):
1 ✔
439
        tmp.extend(reversed(db))
1 ✔
440

441
    if not extend and len(tmp) != w:
1 !
442
        rem = w % 8
×
443
        # rm zeros from [0, 0, 0, 0, 0, d[2], d[1], d[0]] like
444
        tmp = tmp[:w - rem] + tmp[-rem:]
×
445

446
    return tmp
1 ✔
447

448

449
def bytes_to_bit_list_lower_bit_first(bytes_: bytes) -> list[Literal[0, 1]]:
1 ✔
450
    """
451
    b'\x01' to [1, 0, 0, 0, 0, 0, 0, 0]
452
    """
453
    result: list[Literal[0, 1]] = []
×
454
    for byte in bytes_:
×
455
        for _ in range(8):
×
456
            result.append(byte & 0b1)
×
457
            byte >>= 1
×
458
    return result
×
459

460

461
def bytes_to_bit_list_upper_bit_first(bytes_: bytes) -> list[Literal[0, 1]]:
1 ✔
462
    """
463
    b'\x01' to [0, 0, 0, 0, 0, 0, 0, 1]
464
    """
465
    result: list[Literal[0, 1]] = []
×
466
    for byte in bytes_:
×
467
        for _ in range(8):
×
468
            result.append((byte & 0x80) >> 7)
×
469
            byte <<= 1
×
470
    return result
×
471

472

473
def byte_list_to_be_int(_bytes: list[Literal[0, 1, 2, 3, 4, 5, 6, 7]]):
1 ✔
474
    """
475
    In input list LSB first, in result little endian ([1, 0] -> 0x0001)
476
    """
477
    return int_list_to_int(_bytes, 8)
×
478

479

480
def bit_list_to_int(bitList: list[Literal[0, 1]]):
1 ✔
481
    """
482
    In input list LSB first, in result little endian ([0, 1] -> 0b10)
483
    """
484
    res = 0
1 ✔
485
    for i, r in enumerate(bitList):
1 ✔
486
        res |= (r & 0x1) << i
1 ✔
487
    return res
1 ✔
488

489

490
def bit_list_to_bytes(bitList: list[Literal[0, 1]]) -> bytes:
1 ✔
491
    byteCnt = len(bitList) // 8
×
492
    if len(bitList) % 8:
×
493
        byteCnt += 1
×
494
    return bit_list_to_int(bitList).to_bytes(byteCnt, 'big')
×
495

496

497
def int_list_to_int(il: list[int], item_width: int):
1 ✔
498
    """
499
    [0x0201, 0x0403] -> 0x04030201
500
    """
501
    v = 0
1 ✔
502
    for i, b in enumerate(il):
1 ✔
503
        v |= b << (i * item_width)
1 ✔
504

505
    return v
1 ✔
506

507

508
def int_to_int_list(v: int, item_width: int, number_of_items: int):
1 ✔
509
    """
510
    opposite of :func:`~.int_list_to_int`
511
    """
512
    item_mask = mask(item_width)
1 ✔
513
    res = []
1 ✔
514
    for _ in range(number_of_items):
1 ✔
515
        res.append(v & item_mask)
1 ✔
516
        v >>= item_width
1 ✔
517

518
    assert int(v) == 0, ("there should be nothing left, the value is larger", v)
1 ✔
519
    return res
1 ✔
520

521

522
def int_list_to_int_list(v: list[int], in_item_width: int, out_item_width: int, padvalue:Optional[int]=None):
1 ✔
523
    """
524
    [0x0100, 0x0302, ] (width=16) <-> [0x00, 0x01, 0x02, 0x03] (width=8)
525
    """
526

527
    if in_item_width == out_item_width or not v:
1 !
528
        return v
×
529
    res: list[int] = []
1 ✔
530
    if in_item_width < out_item_width:
1 ✔
531
        if out_item_width % in_item_width != 0:
1 ✔
532
            raise NotImplementedError(in_item_width, out_item_width)
533
        number_of_items_per_out = out_item_width // in_item_width
1 ✔
534
        if padvalue is None:
1 !
535
            assert len(v) % number_of_items_per_out == 0, ("Padding is disabled and the value is not sufficietly long",
1 ✔
536
                                                           in_item_width, out_item_width, len(v))
537
        for items in grouper(number_of_items_per_out, v, padvalue=padvalue):
1 ✔
538
            res.append(int_list_to_int(items, in_item_width))
1 ✔
539

540
    else:
541
        if in_item_width % out_item_width != 0:
1 ✔
542
            raise NotImplementedError(in_item_width, out_item_width)
543
        number_of_items_per_in = in_item_width // out_item_width
1 ✔
544
        for item in v:
1 ✔
545
            res.extend(int_to_int_list(item, out_item_width, number_of_items_per_in))
1 ✔
546
    return res
1 ✔
547

548

549
def reverse_byte_order(val: "Bits3val"):
1 ✔
550
    """
551
    Reverse byteorder (littleendian/bigendian) of signal or value
552
    """
553
    w = val._dtype.bit_length()
1 ✔
554
    i = w
1 ✔
555
    items = []
1 ✔
556

557
    while i > 0:
1 ✔
558
        # take last 8 bytes or rest
559
        lower = max(i - 8, 0)
1 ✔
560
        items.append(val[i:lower])
1 ✔
561
        i -= 8
1 ✔
562

563
    # Concat(*items)
564
    top = None
1 ✔
565
    for s in items:
1 ✔
566
        if top is None:
1 ✔
567
            top = s
1 ✔
568
        else:
569
            top = s._concat(top)
1 ✔
570
    return top
1 ✔
571

572

573
def reverse_byte_order_int(val: int, width: int):
1 ✔
574
    assert width % 8 == 0, width
1 ✔
575
    return int.from_bytes(val.to_bytes(width // 8, "big"), "little")
1 ✔
576

577

578
def is_power_of_2(v: Union["Bits3val", int]):
1 ✔
579
    if isinstance(v, int):
×
580
        assert v > 0
×
581
        return (v != 0) & (clear_least_significant_1(v) == 0)
×
582
    else:
583
        return (v != 0) & (clear_least_significant_1(v)._eq(0))
×
584

585

586
def next_power_of_2(v: Union["Bits3val", int], width:Optional[int]=None):
1 ✔
587
    # depend on the fact that v < 2^width
588
    v = v - 1
×
589
    if isinstance(v, int):
×
590
        if v < 0:
×
591
            assert width is not None
×
592
            v = to_unsigned(v, width)
×
593
        elif width is None:
×
594
            width = v.bit_length() + 1
×
595
    else:
596
        width = v._dtype.bit_length()
×
597

598
    i = 1
×
599
    while True:
×
600
        v |= (v >> i)  # 1, 2, 4, 8, 16 for 32b
×
601
        i <<= 1
×
602
        if i > (width // 2):
×
603
            break
×
604

605
    v = v + 1
×
606

607
    if isinstance(v, int):
×
608
        v &= mask(width)
×
609

610
    return v
×
611

612

613
def round_up_to_multiple_of(v: int, divider:int):
1 ✔
614
    """
615
    Round up the v to be the multiple of divider
616
    """
617
    _v = (v // divider) * divider
×
618
    if _v < v:
×
619
        return _v + divider
×
620
    else:
621
        return _v
×
622

623

624
def round_up_to_power_of_2(x: int):
1 ✔
625
    assert x >= 0, x
×
626
    if x == 0:
×
627
        return 0
×
628
    return int(2 ** math.ceil(math.log2(x)))
×
629

630

631
def ctlz(val: int, width: int) -> int:
1 ✔
632
    """
633
    Count leading zeros
634
    """
635
    if val == 0:
×
636
        return width
×
637

638
    # Bisection method.
639
    ZeroBits = 0
×
640
    if not is_power_of_2(width):
×
641
        # because alg. works only for pow2 width
642
        _w = next_power_of_2(width, 64)
×
643
        paddingBits = _w - width
×
644
        width = _w
×
645
    else:
646
        paddingBits = 0
×
647

648
    Shift = width >> 1
×
649
    while Shift:
×
650
        Tmp = val >> Shift
×
651
        if Tmp:
×
652
            val = Tmp
×
653
        else:
654
            ZeroBits |= Shift
×
655
        Shift >>= 1
×
656
    return ZeroBits - paddingBits
×
657

658

659
def ctlo(val: int, width: int) -> int:
1 ✔
660
    """
661
    Count leading ones
662
    """
663
    return ctlz(~val, width)
×
664

665

666
def _ctpop_u64(v: int) -> int:
1 ✔
667
    v = v - ((v >> 1) & 0x5555555555555555)
×
668
    v = (v & 0x3333333333333333) + ((v >> 2) & 0x3333333333333333)
×
669
    v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0F
×
670
    return (v * 0x0101010101010101) >> 56
×
671

672

673
def ctpop(val: int, width: int):
1 ✔
674
    """
675
    count number of 1 in val (population count)
676
    """
677
    res = 0
×
678
    mask_u64 = mask(64)
×
679
    while True:
×
680
        res += _ctpop_u64(val & mask_u64)
×
681
        width -= 64
×
682
        if width <= 0:
×
683
            break
×
684
        val >>= 64
×
685
    return res
×
686

687

688
def cttz(val: int, width: int):
1 ✔
689
    """
690
    Count trailing zeros
691
    """
692
    if val == 0:
×
693
        return width
×
694
    if val & 0x1:
×
695
        return 0
×
696

697
    # ctpop method: (x & -x).bit_length() - 1
698
    # Bisection method.
699
    ZeroBits = 0
×
700
    if not is_power_of_2(width):
×
701
        width = next_power_of_2(width, 64)  # because alg. works only for pow2  width
×
702
    Shift = width >> 1
×
703
    Mask = mask(width) >> Shift
×
704
    while Shift:
×
705
        if (val & Mask) == 0:
×
706
            val >>= Shift
×
707
            ZeroBits |= Shift
×
708

709
        Shift >>= 1
×
710
        Mask >>= Shift
×
711

712
    return ZeroBits
×
713

714

715
def ctto(val: int):
1 ✔
716
    """
717
    Count trailing ones
718
    """
719
    return cttz(~val, val.bit_length())
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc