/
util.py
165 lines (119 loc) · 4.1 KB
/
util.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# -*- coding: utf-8 -*-
# Copyright (c) 2017-2022 Richard Hull and contributors
# See LICENSE.rst for details.
import sys
from time import perf_counter_ns
if sys.version_info.major == 3:
unicode = str
class mutable_string(object):
def __init__(self, value):
assert isinstance(value, str) or isinstance(value, unicode)
self.target = value
def __getattr__(self, attr):
return self.target.__getattribute__(attr)
def __getitem__(self, key):
return self.target[key]
def __setitem__(self, key, value):
assert isinstance(value, str) or isinstance(value, unicode)
tmp = list(self.target)
tmp[key] = value
self.target = ("" if isinstance(self.target, str) else u"").join(tmp)
def __delitem__(self, key):
tmp = list(self.target)
del tmp[key]
self.target = "".join(tmp)
def __len__(self):
return len(self.target)
def __iter__(self):
return iter(self.target)
def __str__(self):
return self.target
def __repr__(self):
return repr(self.target)
def __eq__(self, other):
if isinstance(self.target, unicode):
return self.target == unicode(other)
else:
return self.target == str(other)
def __hash__(self):
return hash(self.target)
class observable(object):
"""
Wraps any container object such that on inserting, updating or deleting,
an observer is notified with a payload of the target. All other special
name methods are passed through parameters unhindered.
"""
def __init__(self, target, observer):
self.target = target
self.observer = observer
self.observer(self.target)
def __getattr__(self, attr):
return self.target.__getattribute__(attr)
def __getitem__(self, key):
return self.target.__getitem__(key)
def __setitem__(self, key, value):
self.target.__setitem__(key, value)
self.observer(self.target)
def __delitem__(self, key):
self.target.__delitem__(key)
self.observer(self.target)
def __len__(self):
return self.target.__len__()
def __iter__(self):
return self.target.__iter__()
def __str__(self):
return self.target.__str__()
def __repr__(self):
return self.target.__repr__()
def from_16_to_8(data):
"""
Utility function to take a list of 16 bit values and turn it into
a list of 8 bit values
:param data: list of 16 bit values to convert
:type data: list
:return: a list of 8 bit values
:rtype: list
.. versionadded:: 1.16.0
"""
return [f(x) for x in data for f in (lambda x: (x & 0xFF00) >> 8, lambda x: 0xFF & x)]
def from_8_to_16(data):
"""
Utility function to take a list of 8 bit values and turn it into a list
of signed 16 bit integers
:param data: list of 8 bit values to convert
:type data: list
:return: a list of 16 bit values
:rtype: list
.. versionadded:: 1.16.0
"""
return [unsigned_16_to_signed(((data[i] & 0xFF) << 8) + (data[i + 1] & 0xFF))
for i in range(0, len(data), 2)] if data is not None else None
def unsigned_16_to_signed(value):
"""
Utility function to convert unsigned 16 bit value to a signed value
:param value: the 16 bit value that needs to be converted
:type value: int
:return: a signed integer
:rtype: int
.. versionadded:: 1.16.0
"""
return ((value) & 0x7FFF) - (0x8000 & (value))
def bytes_to_nibbles(data):
"""
Utility function to take a list of bytes (8 bit values) and turn it into
a list of nibbles (4 bit values)
:param data: a list of 8 bit values that will be converted
:type data: list
:return: a list of 4 bit values
:rtype: list
.. versionadded:: 1.16.0
"""
return [f(x) for x in data for f in (lambda x: x >> 4, lambda x: 0x0F & x)]
def perf_counter():
"""
:py:func:`time.perf_counter_ns` in seconds
:return: the value (in fractional seconds) of a performance counter
:rtype: float
.. versionadded:: 2.4.0
"""
return perf_counter_ns() / 1e9