13 the future. Use these functions to work with those binary blobs of data. |
13 the future. Use these functions to work with those binary blobs of data. |
14 |
14 |
15 """ |
15 """ |
16 import json |
16 import json |
17 |
17 |
18 from coverage import env |
18 from itertools import zip_longest |
19 from coverage.backward import byte_to_int, bytes_to_ints, binary_bytes, zip_longest |
19 |
20 from coverage.misc import contract, new_contract |
20 from coverage.misc import contract, new_contract |
21 |
21 |
22 if env.PY3: |
22 def _to_blob(b): |
23 def _to_blob(b): |
23 """Convert a bytestring into a type SQLite will accept for a blob.""" |
24 """Convert a bytestring into a type SQLite will accept for a blob.""" |
24 return b |
25 return b |
|
26 |
25 |
27 new_contract('blob', lambda v: isinstance(v, bytes)) |
26 new_contract('blob', lambda v: isinstance(v, bytes)) |
28 else: |
|
29 def _to_blob(b): |
|
30 """Convert a bytestring into a type SQLite will accept for a blob.""" |
|
31 return buffer(b) # pylint: disable=undefined-variable |
|
32 |
|
33 new_contract('blob', lambda v: isinstance(v, buffer)) # pylint: disable=undefined-variable |
|
34 |
27 |
35 |
28 |
36 @contract(nums='Iterable', returns='blob') |
29 @contract(nums='Iterable', returns='blob') |
37 def nums_to_numbits(nums): |
30 def nums_to_numbits(nums): |
38 """Convert `nums` into a numbits. |
31 """Convert `nums` into a numbits. |
67 When registered as a SQLite function by :func:`register_sqlite_functions`, |
60 When registered as a SQLite function by :func:`register_sqlite_functions`, |
68 this returns a string, a JSON-encoded list of ints. |
61 this returns a string, a JSON-encoded list of ints. |
69 |
62 |
70 """ |
63 """ |
71 nums = [] |
64 nums = [] |
72 for byte_i, byte in enumerate(bytes_to_ints(numbits)): |
65 for byte_i, byte in enumerate(numbits): |
73 for bit_i in range(8): |
66 for bit_i in range(8): |
74 if (byte & (1 << bit_i)): |
67 if (byte & (1 << bit_i)): |
75 nums.append(byte_i * 8 + bit_i) |
68 nums.append(byte_i * 8 + bit_i) |
76 return nums |
69 return nums |
77 |
70 |
81 """Compute the union of two numbits. |
74 """Compute the union of two numbits. |
82 |
75 |
83 Returns: |
76 Returns: |
84 A new numbits, the union of `numbits1` and `numbits2`. |
77 A new numbits, the union of `numbits1` and `numbits2`. |
85 """ |
78 """ |
86 byte_pairs = zip_longest(bytes_to_ints(numbits1), bytes_to_ints(numbits2), fillvalue=0) |
79 byte_pairs = zip_longest(numbits1, numbits2, fillvalue=0) |
87 return _to_blob(binary_bytes(b1 | b2 for b1, b2 in byte_pairs)) |
80 return _to_blob(bytes(b1 | b2 for b1, b2 in byte_pairs)) |
88 |
81 |
89 |
82 |
90 @contract(numbits1='blob', numbits2='blob', returns='blob') |
83 @contract(numbits1='blob', numbits2='blob', returns='blob') |
91 def numbits_intersection(numbits1, numbits2): |
84 def numbits_intersection(numbits1, numbits2): |
92 """Compute the intersection of two numbits. |
85 """Compute the intersection of two numbits. |
93 |
86 |
94 Returns: |
87 Returns: |
95 A new numbits, the intersection `numbits1` and `numbits2`. |
88 A new numbits, the intersection `numbits1` and `numbits2`. |
96 """ |
89 """ |
97 byte_pairs = zip_longest(bytes_to_ints(numbits1), bytes_to_ints(numbits2), fillvalue=0) |
90 byte_pairs = zip_longest(numbits1, numbits2, fillvalue=0) |
98 intersection_bytes = binary_bytes(b1 & b2 for b1, b2 in byte_pairs) |
91 intersection_bytes = bytes(b1 & b2 for b1, b2 in byte_pairs) |
99 return _to_blob(intersection_bytes.rstrip(b'\0')) |
92 return _to_blob(intersection_bytes.rstrip(b'\0')) |
100 |
93 |
101 |
94 |
102 @contract(numbits1='blob', numbits2='blob', returns='bool') |
95 @contract(numbits1='blob', numbits2='blob', returns='bool') |
103 def numbits_any_intersection(numbits1, numbits2): |
96 def numbits_any_intersection(numbits1, numbits2): |
107 faster than computing the intersection. |
100 faster than computing the intersection. |
108 |
101 |
109 Returns: |
102 Returns: |
110 A bool, True if there is any number in both `numbits1` and `numbits2`. |
103 A bool, True if there is any number in both `numbits1` and `numbits2`. |
111 """ |
104 """ |
112 byte_pairs = zip_longest(bytes_to_ints(numbits1), bytes_to_ints(numbits2), fillvalue=0) |
105 byte_pairs = zip_longest(numbits1, numbits2, fillvalue=0) |
113 return any(b1 & b2 for b1, b2 in byte_pairs) |
106 return any(b1 & b2 for b1, b2 in byte_pairs) |
114 |
107 |
115 |
108 |
116 @contract(num='int', numbits='blob', returns='bool') |
109 @contract(num='int', numbits='blob', returns='bool') |
117 def num_in_numbits(num, numbits): |
110 def num_in_numbits(num, numbits): |
121 A bool, True if `num` is a member of `numbits`. |
114 A bool, True if `num` is a member of `numbits`. |
122 """ |
115 """ |
123 nbyte, nbit = divmod(num, 8) |
116 nbyte, nbit = divmod(num, 8) |
124 if nbyte >= len(numbits): |
117 if nbyte >= len(numbits): |
125 return False |
118 return False |
126 return bool(byte_to_int(numbits[nbyte]) & (1 << nbit)) |
119 return bool(numbits[nbyte] & (1 << nbit)) |
127 |
120 |
128 |
121 |
129 def register_sqlite_functions(connection): |
122 def register_sqlite_functions(connection): |
130 """ |
123 """ |
131 Define numbits functions in a SQLite connection. |
124 Define numbits functions in a SQLite connection. |