Coverage for /home/runner/work/zserio/zserio/compiler/extensions/python/runtime/tests/test_array.py: 100%
555 statements
« prev ^ index » next coverage.py v6.5.0, created at 2024-10-29 13:10 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2024-10-29 13:10 +0000
1import unittest
3from test_object.api import ArrayObject, ArrayEnum, ArrayBitmask
5from zserio.array import (
6 Array,
7 BitFieldArrayTraits,
8 SignedBitFieldArrayTraits,
9 VarUInt16ArrayTraits,
10 VarUInt32ArrayTraits,
11 VarUInt64ArrayTraits,
12 VarUIntArrayTraits,
13 VarSizeArrayTraits,
14 VarInt16ArrayTraits,
15 VarInt32ArrayTraits,
16 VarInt64ArrayTraits,
17 VarIntArrayTraits,
18 Float16ArrayTraits,
19 Float32ArrayTraits,
20 Float64ArrayTraits,
21 BytesArrayTraits,
22 StringArrayTraits,
23 BoolArrayTraits,
24 BitBufferArrayTraits,
25 ObjectArrayTraits,
26 DeltaContext,
27)
28from zserio.bitposition import alignto
29from zserio.bitbuffer import BitBuffer
30from zserio.bitreader import BitStreamReader
31from zserio.bitsizeof import bitsizeof_varsize
32from zserio.bitwriter import BitStreamWriter
33from zserio import PythonRuntimeException
34from zserio.limits import (
35 UINT64_MIN,
36 UINT64_MAX,
37 INT64_MIN,
38 INT64_MAX,
39 UINT8_MAX,
40 INT16_MIN,
41)
44class ArrayTest(unittest.TestCase):
46 def test_bitfield_array(self):
47 array_traits = BitFieldArrayTraits(5)
48 array1_values = [1, 2]
49 array1_bitsizeof = 2 * 5
50 array1_aligned_bitsizeof = 5 + 3 + 5
51 array2_values = [3, 4]
52 self._test_array(
53 array_traits,
54 array1_values,
55 array1_bitsizeof,
56 array1_aligned_bitsizeof,
57 array2_values,
58 )
60 def test_signed_bitfield_array(self):
61 array_traits = SignedBitFieldArrayTraits(5)
62 array1_values = [-1, 1]
63 array1_bitsizeof = 2 * 5
64 array1_aligned_bitsizeof = 5 + 3 + 5
65 array2_values = [-2, 2]
66 self._test_array(
67 array_traits,
68 array1_values,
69 array1_bitsizeof,
70 array1_aligned_bitsizeof,
71 array2_values,
72 )
74 def test_varuint16_array(self):
75 array_traits = VarUInt16ArrayTraits()
76 array1_values = [1, 1024]
77 array1_bitsizeof = 8 + 16
78 array1_aligned_bitsizeof = array1_bitsizeof
79 array2_values = [1, 8192]
80 self._test_array(
81 array_traits,
82 array1_values,
83 array1_bitsizeof,
84 array1_aligned_bitsizeof,
85 array2_values,
86 )
88 def test_varuint32_array(self):
89 array_traits = VarUInt32ArrayTraits()
90 array1_values = [1, 16384]
91 array1_bitsizeof = 8 + 24
92 array1_aligned_bitsizeof = array1_bitsizeof
93 array2_values = [1, 32768]
94 self._test_array(
95 array_traits,
96 array1_values,
97 array1_bitsizeof,
98 array1_aligned_bitsizeof,
99 array2_values,
100 )
102 def test_varuint64_array(self):
103 array_traits = VarUInt64ArrayTraits()
104 array1_values = [1, 16384]
105 array1_bitsizeof = 8 + 24
106 array1_aligned_bitsizeof = array1_bitsizeof
107 array2_values = [1, 65536]
108 self._test_array(
109 array_traits,
110 array1_values,
111 array1_bitsizeof,
112 array1_aligned_bitsizeof,
113 array2_values,
114 )
116 def test_varuint_array(self):
117 array_traits = VarUIntArrayTraits()
118 array1_values = [1, 1024]
119 array1_bitsizeof = 8 + 16
120 array1_aligned_bitsizeof = array1_bitsizeof
121 array2_values = [1, 8192]
122 self._test_array(
123 array_traits,
124 array1_values,
125 array1_bitsizeof,
126 array1_aligned_bitsizeof,
127 array2_values,
128 )
130 def test_varsize_array(self):
131 array_traits = VarSizeArrayTraits()
132 array1_values = [1, 16384]
133 array1_bitsizeof = 8 + 24
134 array1_aligned_bitsizeof = array1_bitsizeof
135 array2_values = [1, 32768]
136 self._test_array(
137 array_traits,
138 array1_values,
139 array1_bitsizeof,
140 array1_aligned_bitsizeof,
141 array2_values,
142 )
144 def test_varint16_array(self):
145 array_traits = VarInt16ArrayTraits()
146 array1_values = [-1, 1024]
147 array1_bitsizeof = 8 + 16
148 array1_aligned_bitsizeof = array1_bitsizeof
149 array2_values = [-1, 8192]
150 self._test_array(
151 array_traits,
152 array1_values,
153 array1_bitsizeof,
154 array1_aligned_bitsizeof,
155 array2_values,
156 )
158 def test_varint32_array(self):
159 array_traits = VarInt32ArrayTraits()
160 array1_values = [-1, 16384]
161 array1_bitsizeof = 8 + 24
162 array1_aligned_bitsizeof = array1_bitsizeof
163 array2_values = [-1, 32768]
164 self._test_array(
165 array_traits,
166 array1_values,
167 array1_bitsizeof,
168 array1_aligned_bitsizeof,
169 array2_values,
170 )
172 def test_varint64_array(self):
173 array_traits = VarInt64ArrayTraits()
174 array1_values = [-1, 16384]
175 array1_bitsizeof = 8 + 24
176 array1_aligned_bitsizeof = array1_bitsizeof
177 array2_values = [-1, 65536]
178 self._test_array(
179 array_traits,
180 array1_values,
181 array1_bitsizeof,
182 array1_aligned_bitsizeof,
183 array2_values,
184 )
186 def test_varint_array(self):
187 array_traits = VarIntArrayTraits()
188 array1_values = [-1, 1024]
189 array1_bitsizeof = 8 + 16
190 array1_aligned_bitsizeof = array1_bitsizeof
191 array2_values = [-1, 8192]
192 self._test_array(
193 array_traits,
194 array1_values,
195 array1_bitsizeof,
196 array1_aligned_bitsizeof,
197 array2_values,
198 )
200 def test_float16_array(self):
201 array_traits = Float16ArrayTraits()
202 array1_values = [-1.0, 1.0]
203 array1_bitsizeof = 2 * 16
204 array1_aligned_bitsizeof = array1_bitsizeof
205 array2_values = [-3.5, 3.5]
206 self._test_array(
207 array_traits,
208 array1_values,
209 array1_bitsizeof,
210 array1_aligned_bitsizeof,
211 array2_values,
212 )
214 def test_float32_array(self):
215 array_traits = Float32ArrayTraits()
216 array1_values = [-1.0, 1.0]
217 array1_bitsizeof = 2 * 32
218 array1_aligned_bitsizeof = array1_bitsizeof
219 array2_values = [-3.5, 3.5]
220 self._test_array(
221 array_traits,
222 array1_values,
223 array1_bitsizeof,
224 array1_aligned_bitsizeof,
225 array2_values,
226 )
228 def test_float64_array(self):
229 array_traits = Float64ArrayTraits()
230 array1_values = [-1.0, 1.0]
231 array1_bitsizeof = 2 * 64
232 array1_aligned_bitsizeof = array1_bitsizeof
233 array2_values = [-3.5, 3.5]
234 self._test_array(
235 array_traits,
236 array1_values,
237 array1_bitsizeof,
238 array1_aligned_bitsizeof,
239 array2_values,
240 )
242 def test_bytes_array(self):
243 array_traits = BytesArrayTraits()
244 array1_values = [bytearray([1, 255]), bytearray([127, 128])]
245 array1_bitsizeof = 2 * (1 + 2) * 8
246 array1_aligned_bitsizeof = array1_bitsizeof
247 array2_values = [bytearray([0, 0]), bytearray([255, 255])]
248 self._test_array(
249 array_traits,
250 array1_values,
251 array1_bitsizeof,
252 array1_aligned_bitsizeof,
253 array2_values,
254 )
256 def test_string_array(self):
257 array_traits = StringArrayTraits()
258 array1_values = ["Text1", "Text2"]
259 array1_bitsizeof = 2 * (1 + len("TextN")) * 8
260 array1_aligned_bitsizeof = array1_bitsizeof
261 array2_values = ["Text3", "Text4"]
262 self._test_array(
263 array_traits,
264 array1_values,
265 array1_bitsizeof,
266 array1_aligned_bitsizeof,
267 array2_values,
268 )
270 def test_bool_array(self):
271 array_traits = BoolArrayTraits()
272 array1_values = [True, False]
273 array1_bitsizeof = 2 * 1
274 array1_aligned_bitsizeof = 1 + 7 + 1
275 array2_values = [True, True]
276 self._test_array(
277 array_traits,
278 array1_values,
279 array1_bitsizeof,
280 array1_aligned_bitsizeof,
281 array2_values,
282 )
284 def test_bitbuffer_array(self):
285 array_traits = BitBufferArrayTraits()
286 array1_values = [
287 BitBuffer(bytes([0xAB, 0xE0]), 11),
288 BitBuffer(bytes([0xAB, 0xCD, 0xFE]), 23),
289 ]
290 array1_bitsizeof = 8 + 11 + 8 + 23
291 array1_aligned_bitsizeof = 8 + 11 + 5 + 8 + 23
292 array2_values = [
293 BitBuffer(bytes([0xBA, 0xE0]), 11),
294 BitBuffer(bytes([0xBA, 0xDC, 0xFE]), 23),
295 ]
296 self._test_array(
297 array_traits,
298 array1_values,
299 array1_bitsizeof,
300 array1_aligned_bitsizeof,
301 array2_values,
302 )
304 class ArrayEnumElementFactory:
305 IS_OBJECT_PACKABLE = True
307 @staticmethod
308 def create(reader, _index):
309 return ArrayEnum.from_reader(reader)
311 @staticmethod
312 def create_packing_context():
313 return DeltaContext()
315 @staticmethod
316 def create_packed(context, reader, _index):
317 return ArrayEnum.from_reader_packed(context, reader)
319 def test_enum_array(self):
320 array_traits = ObjectArrayTraits(ArrayTest.ArrayEnumElementFactory)
321 array1_values = [ArrayEnum.VALUE1, ArrayEnum.VALUE2, ArrayEnum.VALUE3]
322 array1_bitsizeof = 3 * 8
323 array1_aligned_bitsizeof = array1_bitsizeof
324 array2_values = [ArrayEnum.VALUE1, ArrayEnum.VALUE1, ArrayEnum.VALUE1]
325 self._test_array(
326 array_traits,
327 array1_values,
328 array1_bitsizeof,
329 array1_aligned_bitsizeof,
330 array2_values,
331 )
333 class ArrayBitmaskElementFactory:
334 IS_OBJECT_PACKABLE = True
336 @staticmethod
337 def create(reader, _index):
338 return ArrayBitmask.from_reader(reader)
340 @staticmethod
341 def create_packing_context():
342 return DeltaContext()
344 @staticmethod
345 def create_packed(context, reader, _index):
346 return ArrayBitmask.from_reader_packed(context, reader)
348 def test_bitmask_array(self):
349 array_traits = ObjectArrayTraits(ArrayTest.ArrayBitmaskElementFactory)
350 array1_values = [
351 ArrayBitmask.Values.READ,
352 ArrayBitmask.Values.WRITE,
353 ArrayBitmask.Values.CREATE,
354 ]
355 array1_bitsizeof = 3 * 8
356 array1_aligned_bitsizeof = array1_bitsizeof
357 array2_values = [
358 ArrayBitmask.Values.READ,
359 ArrayBitmask.Values.READ,
360 ArrayBitmask.Values.READ,
361 ]
362 self._test_array(
363 array_traits,
364 array1_values,
365 array1_bitsizeof,
366 array1_aligned_bitsizeof,
367 array2_values,
368 )
370 class ArrayObjectElementFactory:
371 IS_OBJECT_PACKABLE = True
373 @staticmethod
374 def create(reader, _index):
375 return ArrayObject.from_reader(reader)
377 @staticmethod
378 def create_packing_context():
379 return ArrayObject.ZserioPackingContext()
381 @staticmethod
382 def create_packed(context, reader, _index):
383 return ArrayObject.from_reader_packed(context, reader)
385 def test_object_array(self):
386 array_traits = ObjectArrayTraits(ArrayTest.ArrayObjectElementFactory)
387 array1_values = [ArrayObject(0xAB), ArrayObject(0xCD), ArrayObject(0xEF)]
388 array1_bitsizeof = 3 * 31
389 array1_aligned_bitsizeof = 31 + 1 + 31 + 1 + 31
390 array2_values = [ArrayObject(0x01), ArrayObject(0x02), ArrayObject(0x03)]
391 self._test_array(
392 array_traits,
393 array1_values,
394 array1_bitsizeof,
395 array1_aligned_bitsizeof,
396 array2_values,
397 )
399 def test_bitfield_packed_array(self):
400 array_traits64 = BitFieldArrayTraits(64)
402 # none-zero delta
403 array1_values = [10, 11, 12]
404 array1_max_delta_bit_size = 1
405 array1_bitsizeof = self._calc_packed_bit_size(64, len(array1_values), array1_max_delta_bit_size)
406 array1_aligned_bitsizeof = self._calc_aligned_packed_bit_size(
407 64, len(array1_values), array1_max_delta_bit_size
408 )
409 self._test_packed_array(array_traits64, array1_values, array1_bitsizeof, array1_aligned_bitsizeof)
411 # zero delta
412 array2_values = [10, 10, 10]
413 array2_bitsizeof = self.PACKING_DESCRIPTOR_BITSIZE + 64
414 array2_aligned_bitsizeof = self.PACKING_DESCRIPTOR_BITSIZE + 64 + 1
415 self._test_packed_array(array_traits64, array2_values, array2_bitsizeof, array2_aligned_bitsizeof)
417 # one-element array
418 array3_values = [10]
419 array3_bitsizeof = 1 + 64
420 array3_aligned_bitsizeof = 1 + 64
421 self._test_packed_array(array_traits64, array3_values, array3_bitsizeof, array3_aligned_bitsizeof)
423 # empty array
424 array4_values = []
425 array4_bitsizeof = 0
426 array4_aligned_bitsizeof = 0
427 self._test_packed_array(array_traits64, array4_values, array4_bitsizeof, array4_aligned_bitsizeof)
429 # packing not applied, delta is too big
430 self._test_packed_array(array_traits64, [UINT64_MIN, UINT64_MAX])
431 self._test_packed_array(array_traits64, [UINT64_MAX, UINT64_MAX // 2, UINT64_MIN])
433 # will have maxBitNumber 62 bits
434 self._test_packed_array(array_traits64, [0, INT64_MAX // 2, 100, 200, 300, 400, 500, 600, 700])
436 # will not be packed because unpacked 8bit values will be more efficient
437 array_traits8 = BitFieldArrayTraits(8)
438 array5_values = [
439 UINT8_MAX,
440 0,
441 10,
442 20,
443 30,
444 40,
445 ] # max_bit_number 8, delta needs 9 bits
446 array5_bitsizeof = 1 + 6 * 8
447 array5_aligned_bitsizeof = 1 + 8 + 7 + 5 * 8
448 self._test_packed_array(array_traits8, array5_values, array5_bitsizeof, array5_aligned_bitsizeof)
450 # will not be packed because unpacked 8bit values will be more efficient
451 # (6 bits more are needed to store max_bit_number in descriptor if packing was enabled)
452 array6_values = [
453 UINT8_MAX,
454 UINT8_MAX // 2 + 1,
455 10,
456 20,
457 30,
458 40,
459 ] # max_bit_number 7, delta needs 8 bits
460 array6_bitsizeof = 1 + 6 * 8
461 array6_aligned_bitsizeof = 1 + 8 + 7 + 5 * 8
462 self._test_packed_array(array_traits8, array6_values, array6_bitsizeof, array6_aligned_bitsizeof)
464 def test_signed_bitfield_packed_array(self):
465 array_traits64 = SignedBitFieldArrayTraits(64)
466 self._test_packed_array(array_traits64, [-10, 11, -12])
467 self._test_packed_array(array_traits64, [-10, -10, -10]) # zero delta
469 self._test_packed_array(array_traits64, []) # empty
470 self._test_packed_array(array_traits64, [-10]) # single element
472 # packing not applied, delta is too big
473 self._test_packed_array(array_traits64, [INT64_MIN, INT64_MAX])
474 self._test_packed_array(array_traits64, [INT64_MIN, 0, INT64_MAX])
476 # will not be packed because unpacked 16bit values will be more efficient
477 # (6 bits more are needed to store max_bit_number in descriptor if packing was enabled)
478 array_traits16 = SignedBitFieldArrayTraits(16)
479 array16_values = [
480 INT16_MIN,
481 -1,
482 10,
483 20,
484 30,
485 40,
486 ] # max_bit_number 15, delta needs 16 bits
487 array16_bitsizeof = 1 + 6 * 16
488 array16_aligned_bitsizeof = 1 + 16 + 7 + 5 * 16
489 self._test_packed_array(array_traits16, array16_values, array16_bitsizeof, array16_aligned_bitsizeof)
491 def test_varuint_packed_array(self):
492 array_traits = VarUIntArrayTraits()
493 self._test_packed_array(array_traits, [100, 200, 300])
494 self._test_packed_array(array_traits, [300, 200, 100])
496 # won't be packed because unpacked varuint values will be more efficient
497 unpacked_array = [5000000, 0, 0, 0, 0, 0, 0]
498 unpacked_bitsizeof = 1 + 32 + 6 * 8
499 unpacked_aligned_bitsizeof = 1 + 32 + 7 + 6 * 8
500 self._test_packed_array(array_traits, unpacked_array, unpacked_bitsizeof, unpacked_aligned_bitsizeof)
502 self._test_packed_array(array_traits, [UINT64_MIN, UINT64_MAX])
503 self._test_packed_array(array_traits, [UINT64_MAX, UINT64_MAX // 2, UINT64_MIN])
505 def test_enum_packed_array(self):
506 array_traits = ObjectArrayTraits(ArrayTest.ArrayEnumElementFactory)
507 self._test_packed_array(array_traits, [ArrayEnum.VALUE1, ArrayEnum.VALUE2, ArrayEnum.VALUE3])
509 def test_bitmask_packed_array(self):
510 array_traits = ObjectArrayTraits(ArrayTest.ArrayBitmaskElementFactory)
511 self._test_packed_array(
512 array_traits,
513 [
514 ArrayBitmask.Values.READ,
515 ArrayBitmask.Values.WRITE,
516 ArrayBitmask.Values.CREATE,
517 ],
518 )
520 def test_object_packed_array(self):
521 array_traits = ObjectArrayTraits(ArrayTest.ArrayObjectElementFactory)
522 self._test_packed_array(array_traits, [ArrayObject(0xAB), ArrayObject(0xCD), ArrayObject(0xEF)])
523 self._test_packed_array(array_traits, [ArrayObject(0x01), ArrayObject(0x02), ArrayObject(0x03)])
525 @staticmethod
526 def _set_offset_method(_index, _bitoffset):
527 pass
529 @staticmethod
530 def _check_offset_method(_index, _bitoffset):
531 pass
533 def _test_array(
534 self,
535 array_traits,
536 array1_values,
537 array1_bitsizeof,
538 array1_aligned_bitsizeof,
539 array2_values,
540 ):
541 self._test_eq(array_traits, array1_values, array2_values)
542 self._test_hashcode(array_traits, array1_values, array2_values)
543 self._test_len(array_traits, array1_values)
544 self._test_get_item(array_traits, array1_values)
545 self._test_set_item(array_traits, array1_values)
546 self._test_raw_array(array_traits, array1_values, array2_values)
548 auto_bitsize = bitsizeof_varsize(len(array1_values))
550 self._test_array_normal(array_traits, array1_values, array1_bitsizeof)
551 self._test_array_auto(array_traits, array1_values, auto_bitsize + array1_bitsizeof)
552 self._test_array_aligned(array_traits, array1_values, array1_aligned_bitsizeof)
553 self._test_array_aligned_auto(array_traits, array1_values, auto_bitsize + array1_aligned_bitsizeof)
554 self._test_array_implicit(array_traits, array1_values, array1_bitsizeof)
556 def _test_packed_array(
557 self,
558 array_traits,
559 array_values,
560 array_bitsizeof=None,
561 array_aligned_bitsizeof=None,
562 ):
564 self._test_packed_array_normal(array_traits, array_values, array_bitsizeof)
566 auto_size_bitsize = bitsizeof_varsize(len(array_values))
567 auto_bitsize = auto_size_bitsize + array_bitsizeof if array_bitsizeof is not None else None
568 self._test_packed_array_auto(array_traits, array_values, auto_bitsize)
570 self._test_packed_array_aligned(array_traits, array_values, array_aligned_bitsizeof)
572 auto_aligned_bitsize = (
573 auto_size_bitsize + array_aligned_bitsizeof if array_aligned_bitsizeof is not None else None
574 )
575 self._test_packed_array_aligned_auto(array_traits, array_values, auto_aligned_bitsize)
577 self._test_packed_array_implicit(array_traits, array_values, array_bitsizeof)
579 def _test_eq(self, array_traits, array1_values, array2_values):
580 array1 = Array(array_traits, array1_values)
581 array2 = Array(array_traits, array2_values)
582 array3 = Array(array_traits, array1_values)
583 self.assertNotEqual(array1, None)
584 self.assertNotEqual(array1, array2)
585 self.assertEqual(array1, array3)
587 def _test_hashcode(self, array_traits, array1_values, array2_values):
588 array1 = Array(array_traits, array1_values)
589 array2 = Array(array_traits, array2_values)
590 array3 = Array(array_traits, array1_values)
591 self.assertNotEqual(hash(array1), hash(array2))
592 self.assertEqual(hash(array1), hash(array3))
594 def _test_len(self, array_traits, array_values):
595 array = Array(array_traits, array_values)
596 raw_array = array.raw_array
597 self.assertEqual(len(raw_array), len(array))
599 def _test_get_item(self, array_traits, array_values):
600 array = Array(array_traits, array_values)
601 raw_array = array.raw_array
602 for value, raw_value in zip(array, raw_array):
603 self.assertEqual(value, raw_value)
605 def _test_set_item(self, array_traits, array_values):
606 array = Array(array_traits, array_values)
607 raw_array = array.raw_array
608 self.assertTrue(len(array) > 1)
609 first_value = array[0]
610 second_value = array[1]
611 array[0] = second_value
612 self.assertEqual(array[0], raw_array[0])
613 raw_array[0] = first_value # return the original value for other tests
614 self.assertEqual(array[0], raw_array[0])
616 def _test_raw_array(self, array_traits, array1_values, array2_values):
617 array1 = Array(array_traits, array1_values)
618 array2 = Array(array_traits, array2_values)
619 array3 = Array(array_traits, array1_values)
620 self.assertNotEqual(array1.raw_array, array2.raw_array)
621 self.assertEqual(array1.raw_array, array3.raw_array)
623 def _test_array_normal(self, array_traits, array_values, expected_bitsize):
624 for i in range(8):
625 array = Array(array_traits, array_values)
627 bitsize = array.bitsizeof(i)
628 self.assertEqual(expected_bitsize, bitsize)
629 self.assertEqual(i + bitsize, array.initialize_offsets(i), i)
631 writer = BitStreamWriter()
632 if i > 0:
633 writer.write_bits(0, i)
634 array.write(writer)
635 self.assertEqual(i + bitsize, writer.bitposition, i)
637 from_reader = BitStreamReader(writer.byte_array, writer.bitposition)
638 if i > 0:
639 self.assertEqual(0, from_reader.read_bits(i))
640 read_array_from_reader = Array.from_reader(array_traits, from_reader, len(array_values))
641 self.assertEqual(array, read_array_from_reader, i)
643 reader = BitStreamReader(writer.byte_array, writer.bitposition)
644 if i > 0:
645 self.assertEqual(0, reader.read_bits(i))
646 read_array = Array(array_traits)
647 read_array.read(reader, len(array_values))
648 self.assertEqual(array, read_array, i)
650 def _test_array_auto(self, array_traits, array_values, expected_bitsize):
651 for i in range(8):
652 array = Array(array_traits, array_values, is_auto=True)
654 bitsize = array.bitsizeof(i)
655 self.assertEqual(expected_bitsize, bitsize, i)
656 self.assertEqual(i + bitsize, array.initialize_offsets(i), i)
658 writer = BitStreamWriter()
659 if i > 0:
660 writer.write_bits(0, i)
661 array.write(writer)
662 self.assertEqual(i + bitsize, writer.bitposition, i)
664 from_reader = BitStreamReader(writer.byte_array, writer.bitposition)
665 if i > 0:
666 self.assertEqual(0, from_reader.read_bits(i))
667 read_array_from_reader = Array.from_reader(array_traits, from_reader, is_auto=True)
668 self.assertEqual(array, read_array_from_reader, i)
670 reader = BitStreamReader(writer.byte_array, writer.bitposition)
671 if i > 0:
672 self.assertEqual(0, reader.read_bits(i))
673 read_array = Array(array_traits, is_auto=True)
674 read_array.read(reader)
675 self.assertEqual(array, read_array, i)
677 def _test_array_aligned(self, array_traits, array_values, expected_bitsize):
678 for i in range(8):
679 array = Array(
680 array_traits,
681 array_values,
682 set_offset_method=ArrayTest._set_offset_method,
683 check_offset_method=ArrayTest._check_offset_method,
684 )
686 bitsize = array.bitsizeof(i)
687 self.assertEqual(alignto(8, i) - i + expected_bitsize, bitsize, i)
688 self.assertEqual(i + bitsize, array.initialize_offsets(i), i)
690 writer = BitStreamWriter()
691 if i > 0:
692 writer.write_bits(0, i)
693 array.write(writer)
694 self.assertEqual(i + bitsize, writer.bitposition, i)
696 from_reader = BitStreamReader(writer.byte_array, writer.bitposition)
697 if i > 0:
698 self.assertEqual(0, from_reader.read_bits(i))
699 read_array_from_reader = Array.from_reader(
700 array_traits,
701 from_reader,
702 len(array_values),
703 set_offset_method=ArrayTest._set_offset_method,
704 check_offset_method=ArrayTest._check_offset_method,
705 )
706 self.assertEqual(array, read_array_from_reader, i)
708 reader = BitStreamReader(writer.byte_array, writer.bitposition)
709 if i > 0:
710 self.assertEqual(0, reader.read_bits(i))
711 read_array = Array(
712 array_traits,
713 set_offset_method=ArrayTest._set_offset_method,
714 check_offset_method=ArrayTest._check_offset_method,
715 )
716 read_array.read(reader, len(array_values))
717 self.assertEqual(array, read_array, i)
719 def _test_array_aligned_auto(self, array_traits, array_values, expected_bitsize):
720 for i in range(8):
721 array = Array(
722 array_traits,
723 array_values,
724 is_auto=True,
725 set_offset_method=ArrayTest._set_offset_method,
726 check_offset_method=ArrayTest._check_offset_method,
727 )
729 bitsize = array.bitsizeof(i)
730 self.assertEqual(alignto(8, i) - i + expected_bitsize, bitsize, i)
731 self.assertEqual(i + bitsize, array.initialize_offsets(i), i)
733 writer = BitStreamWriter()
734 if i > 0:
735 writer.write_bits(0, i)
736 array.write(writer)
737 self.assertEqual(i + bitsize, writer.bitposition, i)
739 from_reader = BitStreamReader(writer.byte_array, writer.bitposition)
740 if i > 0:
741 self.assertEqual(0, from_reader.read_bits(i))
742 read_array_from_reader = Array.from_reader(
743 array_traits,
744 from_reader,
745 is_auto=True,
746 set_offset_method=ArrayTest._set_offset_method,
747 check_offset_method=ArrayTest._check_offset_method,
748 )
749 self.assertEqual(array, read_array_from_reader, i)
751 reader = BitStreamReader(writer.byte_array, writer.bitposition)
752 if i > 0:
753 self.assertEqual(0, reader.read_bits(i))
754 read_array = Array(
755 array_traits,
756 is_auto=True,
757 set_offset_method=ArrayTest._set_offset_method,
758 check_offset_method=ArrayTest._check_offset_method,
759 )
760 read_array.read(reader)
761 self.assertEqual(array, read_array, i)
763 def _test_array_implicit(self, array_traits, array_values, expected_bitsize):
764 for i in range(8):
765 array = Array(array_traits, array_values, is_implicit=True)
767 bitsize = array.bitsizeof(i)
768 self.assertEqual(expected_bitsize, bitsize, i)
769 self.assertEqual(i + bitsize, array.initialize_offsets(i), i)
771 writer = BitStreamWriter()
772 if i > 0:
773 writer.write_bits(0, i)
774 array.write(writer)
775 self.assertEqual(i + bitsize, writer.bitposition, i)
777 from_reader = BitStreamReader(writer.byte_array, writer.bitposition)
778 if i > 0:
779 self.assertEqual(0, from_reader.read_bits(i))
780 if array_traits.HAS_BITSIZEOF_CONSTANT:
781 read_array_from_reader = Array.from_reader(array_traits, from_reader, is_implicit=True)
782 self.assertEqual(array, read_array_from_reader, i)
783 else:
784 with self.assertRaises(PythonRuntimeException):
785 Array.from_reader(array_traits, from_reader, is_implicit=True)
787 reader = BitStreamReader(writer.byte_array, writer.bitposition)
788 if i > 0:
789 self.assertEqual(0, reader.read_bits(i))
790 read_array = Array(array_traits, is_implicit=True)
791 if array_traits.HAS_BITSIZEOF_CONSTANT:
792 read_array.read(reader)
793 self.assertEqual(array, read_array, i)
794 else:
795 with self.assertRaises(PythonRuntimeException):
796 read_array.read(reader)
798 def _test_packed_array_normal(self, array_traits, array_values, expected_bitsize):
799 for i in range(8):
800 array = Array(array_traits, array_values)
802 bitsize = array.bitsizeof_packed(i)
803 if expected_bitsize is not None:
804 self.assertEqual(expected_bitsize, bitsize)
805 self.assertEqual(i + bitsize, array.initialize_offsets_packed(i), i)
807 writer = BitStreamWriter()
808 if i > 0:
809 writer.write_bits(0, i)
810 array.write_packed(writer)
811 self.assertEqual(i + bitsize, writer.bitposition, i)
813 from_reader = BitStreamReader(writer.byte_array, writer.bitposition)
814 if i > 0:
815 self.assertEqual(0, from_reader.read_bits(i))
816 read_array_from_reader = Array.from_reader_packed(array_traits, from_reader, len(array_values))
817 self.assertEqual(array, read_array_from_reader, i)
819 reader = BitStreamReader(writer.byte_array, writer.bitposition)
820 if i > 0:
821 self.assertEqual(0, reader.read_bits(i))
822 read_array = Array(array_traits)
823 read_array.read_packed(reader, len(array_values))
824 self.assertEqual(array, read_array, i)
826 def _test_packed_array_auto(self, array_traits, array_values, expected_bitsize):
827 for i in range(8):
828 array = Array(array_traits, array_values, is_auto=True)
830 bitsize = array.bitsizeof_packed(i)
831 if expected_bitsize is not None:
832 self.assertEqual(expected_bitsize, bitsize)
833 self.assertEqual(i + bitsize, array.initialize_offsets_packed(i), i)
835 writer = BitStreamWriter()
836 if i > 0:
837 writer.write_bits(0, i)
838 array.write_packed(writer)
839 self.assertEqual(i + bitsize, writer.bitposition, i)
841 from_reader = BitStreamReader(writer.byte_array, writer.bitposition)
842 if i > 0:
843 self.assertEqual(0, from_reader.read_bits(i))
844 read_array_from_reader = Array.from_reader_packed(array_traits, from_reader, is_auto=True)
845 self.assertEqual(array, read_array_from_reader, i)
847 reader = BitStreamReader(writer.byte_array, writer.bitposition)
848 if i > 0:
849 self.assertEqual(0, reader.read_bits(i))
850 read_array = Array(array_traits, is_auto=True)
851 read_array.read_packed(reader)
852 self.assertEqual(array, read_array, i)
854 def _test_packed_array_aligned(self, array_traits, array_values, expected_bitsize):
855 for i in range(8):
856 array = Array(
857 array_traits,
858 array_values,
859 set_offset_method=ArrayTest._set_offset_method,
860 check_offset_method=ArrayTest._check_offset_method,
861 )
863 bitsize = array.bitsizeof_packed(i)
864 if expected_bitsize is not None and i == 0:
865 self.assertEqual(expected_bitsize, bitsize)
866 self.assertEqual(i + bitsize, array.initialize_offsets_packed(i), i)
868 writer = BitStreamWriter()
869 if i > 0:
870 writer.write_bits(0, i)
871 array.write_packed(writer)
872 self.assertEqual(i + bitsize, writer.bitposition, i)
874 from_reader = BitStreamReader(writer.byte_array, writer.bitposition)
875 if i > 0:
876 self.assertEqual(0, from_reader.read_bits(i))
877 read_array_from_reader = Array.from_reader_packed(
878 array_traits,
879 from_reader,
880 len(array_values),
881 set_offset_method=ArrayTest._set_offset_method,
882 check_offset_method=ArrayTest._check_offset_method,
883 )
884 self.assertEqual(array, read_array_from_reader, i)
886 reader = BitStreamReader(writer.byte_array, writer.bitposition)
887 if i > 0:
888 self.assertEqual(0, reader.read_bits(i))
889 read_array = Array(
890 array_traits,
891 set_offset_method=ArrayTest._set_offset_method,
892 check_offset_method=ArrayTest._check_offset_method,
893 )
894 read_array.read_packed(reader, len(array_values))
895 self.assertEqual(array, read_array, i)
897 def _test_packed_array_aligned_auto(self, array_traits, array_values, expected_bitsize):
898 for i in range(8):
899 array = Array(
900 array_traits,
901 array_values,
902 is_auto=True,
903 set_offset_method=ArrayTest._set_offset_method,
904 check_offset_method=ArrayTest._check_offset_method,
905 )
907 bitsize = array.bitsizeof_packed(i)
908 if expected_bitsize is not None and i == 0:
909 self.assertEqual(expected_bitsize, bitsize)
910 self.assertEqual(i + bitsize, array.initialize_offsets_packed(i), i)
912 writer = BitStreamWriter()
913 if i > 0:
914 writer.write_bits(0, i)
915 array.write_packed(writer)
916 self.assertEqual(i + bitsize, writer.bitposition, i)
918 from_reader = BitStreamReader(writer.byte_array, writer.bitposition)
919 if i > 0:
920 self.assertEqual(0, from_reader.read_bits(i))
921 read_array_from_reader = Array.from_reader_packed(
922 array_traits,
923 from_reader,
924 is_auto=True,
925 set_offset_method=ArrayTest._set_offset_method,
926 check_offset_method=ArrayTest._check_offset_method,
927 )
928 self.assertEqual(array, read_array_from_reader, i)
930 reader = BitStreamReader(writer.byte_array, writer.bitposition)
931 if i > 0:
932 self.assertEqual(0, reader.read_bits(i))
933 read_array = Array(
934 array_traits,
935 is_auto=True,
936 set_offset_method=ArrayTest._set_offset_method,
937 check_offset_method=ArrayTest._check_offset_method,
938 )
939 read_array.read_packed(reader)
940 self.assertEqual(array, read_array, i)
942 def _test_packed_array_implicit(self, array_traits, array_values, expected_bitsize):
943 for i in range(8):
944 array = Array(array_traits, array_values, is_implicit=True)
946 bitsize = array.bitsizeof_packed(i)
947 if expected_bitsize is not None:
948 self.assertEqual(expected_bitsize, bitsize)
949 self.assertEqual(i + bitsize, array.initialize_offsets_packed(i), i)
951 writer = BitStreamWriter()
952 if i > 0:
953 writer.write_bits(0, i)
954 array.write_packed(writer)
955 self.assertEqual(i + bitsize, writer.bitposition, i)
957 reader = BitStreamReader(writer.byte_array, writer.bitposition)
958 if i > 0:
959 self.assertEqual(0, reader.read_bits(i))
960 read_array = Array(array_traits, is_implicit=True)
961 with self.assertRaises(PythonRuntimeException):
962 read_array.read_packed(reader)
964 def _calc_packed_bit_size(self, element_bit_size, array_size, max_delta_bit_size):
965 return self.PACKING_DESCRIPTOR_BITSIZE + element_bit_size + (array_size - 1) * (max_delta_bit_size + 1)
967 def _calc_aligned_packed_bit_size(self, element_bit_size, array_size, max_delta_bit_size):
968 first_element_with_descriptor_bit_size = self.PACKING_DESCRIPTOR_BITSIZE + element_bit_size
969 aligned_first_element_with_descriptor_bit_size = (first_element_with_descriptor_bit_size + 7) // 8 * 8
970 aligned_max_delta_bit_size = (max_delta_bit_size + 1 + 7) // 8 * 8
972 return (
973 aligned_first_element_with_descriptor_bit_size
974 + (array_size - 2) * aligned_max_delta_bit_size
975 + (max_delta_bit_size + 1)
976 )
978 PACKING_DESCRIPTOR_BITSIZE = 1 + 6