Welcome, guest | Sign In | My Account | Store | Cart

library to store n bits data (n > 0) in a python array

Python, 127 lines
  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
class nBitArray() :
	
	m = 32
	f = 'I'
	
	_default_type = None
	
	def __init__(self, n_bit) :
		
		if not (isinstance(n_bit, int) and n_bit > 0) :
			raise ValueError
		
		self.n_bit = n_bit
		self.n_item = 0
		
		self.b_mask = (2 ** self.n_bit) - 1
		self.i_mask = ((0x1 << self.m) - 1)
		
	def _normalize_index(self, index) :
		if (-1 * self.n_item) <= index < 0 :
				index += self.n_item
		if 0 <= index < self.n_item :
			return index
		raise IndexError
			
	def __getitem__(self, index):
		if isinstance(index, int) :
			return self._get_at(self._normalize_index(index))
		elif isinstance(index, slice) :
			return (self._get_at(i) for i in range(* index.indices(self.n_item)))
		else:
			raise TypeError("index must be int or slice")
			
	def __str__(self) :
		u = io.StringIO()
		for n, i in enumerate(self._data) :
			u.write("{0:08X}".format(i))
			u.write('\n' if (n + 1) % 6 == 0 else ' ')
		return u.getvalue()
	
	def load_data(self, value_lst) :
		""" load a list of n_bit words """
		w_curs = 0 # position in the word
		word = 0
		stack = list()
		for n, value in enumerate(value_lst) :
			value = value & self.b_mask			
			v_curs = 0 # position in the value
			v_count = self.n_bit - v_curs # number of remaining bits to be written
			w_count = self.m - w_curs # number of bits available in the word			
			while v_count > 0 :
				if w_count <= v_count :
					p = value >> (v_count - w_count)
					word |= p & self.i_mask
					v_curs += w_count
					w_curs += w_count
				else :
					p = value << (w_count - v_count) 
					word |= p & self.i_mask
					v_curs += v_count
					w_curs += v_count
				if w_curs == self.m :
					stack.append(word)
					word = 0
					w_curs = 0 
				v_count = self.n_bit - v_curs
				w_count = self.m - w_curs
		if word :
			stack.append(word)			
		self.n_item = len(value_lst)
		self._data = array.array(self.f, stack)
		return self
		
	def _get_at(self, v_index) :
		if not 0 <= v_index < self.n_item :
			raise IndexError
			
		b = v_index * self.n_bit
		i_index = b // self.m # index of the word
		
		#print(v_index, b, i_index)
		
		v_curs = 0 # position in the value
		w_curs = b % self.m # position in the word
		
		v_count = self.n_bit - v_curs # number of remaining bits to append to the value
		w_count = self.m - w_curs # number of remaining bits to be read from the word
		
		value = 0
		while v_count > 0 :
			#print("v curs={0}, count={1}  -  w curs={2}, count={3}".format(v_curs, v_count, w_curs, w_count)) 
			if w_count <= v_count :
				value = (value << self.m) | self._data[i_index]
				#print("IF -> value = {0:05X}".format(value & self.b_mask))
				v_curs += w_count
				w_curs += w_count
			else :
				value = (value << v_count) | (self._data[i_index] >> (w_count - v_count))
				#print("ELSE -> value = {0:05X}".format(value & self.b_mask))
				v_curs += v_count
				w_curs += v_count
				
			if w_curs == self.m :
				i_index += 1
				w_curs = 0
				
			v_count = self.n_bit - v_curs
			w_count = self.m - w_curs
		
		return value & self.b_mask
			
if __name__ == '__main__' :

	high_res_sinus = [int(math.sin(i) * 0x3FFFFF) & 0x3FFFFF for i in range(10000)]
	low_res_sinus = [int(math.sin(i) * 0x3) & 0x3FFFFF for i in range(10000)]

	def do(array, name, size) :
		data = nBitArray(size).load_data(array)._data.tobytes()
		compressed = gzip.compress(data)
		print("{3}:{4} bits: {0} -> {1} ({2:0.1f} %)".format(
			len(data), len(compressed), 100 * len(compressed) / len(data), name, size)
		)

	do(high_res_sinus, "high_res_sinus", 22)
	do(high_res_sinus, "high_res_sinus", 24)
	do(low_res_sinus, "low_res_sinus", 22)
	do(low_res_sinus, "low_res_sinus", 24)

1 comment

Martin Miller 5 years, 7 months ago  # | flag

Your code is indented with tab characters which is interpreted as every eight columns on many systems. For this reason it better to always use space characters and tab by 4 as PEP 8 - Style Guide for Python Code recommends.

So I suggest you edit your recipe and fix the indenting.

Created by yota on Thu, 21 Apr 2016 (GPL3)
Python recipes (4591)
yota's recipes (13)

Required Modules

  • (none specified)

Other Information and Tasks