bt2: add bit array field class and field support
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Tue, 13 Aug 2019 23:35:12 +0000 (19:35 -0400)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Thu, 15 Aug 2019 15:41:44 +0000 (11:41 -0400)
This patch adds bit array field class and field support to the Python
bindings.

A bit array field class has a `length` property (number of bits in the
array).

As of this patch, a bit array field is not a Python sequence. It could
become in the future however. The way to access a bit array field's
value is the `value_as_integer` property which simply wraps the
corresponding library functions.

A bit array field is not considered a numeric field. Its _spec_eq()
method only compares if the other object is also a bit array fields.

I did not implement the __bool__() operator because it will need to
satisfy the Python sequence protocol (length is not 0, which in fact is
always the case with a bit array field), should we decide as such in the
future. I implemented the __len__() operator however which is
straightforward.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Change-Id: I2e90e1444151bf5169a8df70c53664096cceb6c4
Reviewed-on: https://review.lttng.org/c/babeltrace/+/1918
Tested-by: jenkins <jenkins@lttng.org>
src/bindings/python/bt2/bt2/__init__.py
src/bindings/python/bt2/bt2/field.py
src/bindings/python/bt2/bt2/field_class.py
src/bindings/python/bt2/bt2/trace_class.py
tests/bindings/python/bt2/test_field.py
tests/bindings/python/bt2/test_field_class.py
tests/bindings/python/bt2/test_package.py

index 410ad4459a81c2b99faf2169cf541feb0ada7562..137fc423507ea7030c4b3b47970de8ade99c7f8e 100644 (file)
@@ -42,6 +42,7 @@ from bt2.error import _MessageIteratorErrorCause
 from bt2.error import _Error
 from bt2.event_class import EventClassLogLevel
 from bt2.field import _BoolField
+from bt2.field import _BitArrayField
 from bt2.field import _IntegerField
 from bt2.field import _UnsignedIntegerField
 from bt2.field import _SignedIntegerField
@@ -58,6 +59,7 @@ from bt2.field import _StaticArrayField
 from bt2.field import _DynamicArrayField
 from bt2.field_class import IntegerDisplayBase
 from bt2.field_class import _BoolFieldClass
+from bt2.field_class import _BitArrayFieldClass
 from bt2.field_class import _IntegerFieldClass
 from bt2.field_class import _UnsignedIntegerFieldClass
 from bt2.field_class import _SignedIntegerFieldClass
index f674a465d5d773a4770d5037a77f8fcccc5dc108..512271bd95c9a055f6b6108be2035cb5344f043a 100644 (file)
@@ -71,6 +71,34 @@ class _Field(object._UniqueObject):
         return self._repr()
 
 
+class _BitArrayField(_Field):
+    _NAME = 'Bit array'
+
+    @property
+    def value_as_integer(self):
+        return native_bt.field_bit_array_get_value_as_integer(self._ptr)
+
+    @value_as_integer.setter
+    def value_as_integer(self, value):
+        utils._check_uint64(value)
+        native_bt.field_bit_array_set_value_as_integer(self._ptr, value)
+
+    def _spec_eq(self, other):
+        if type(other) is not type(self):
+            return False
+
+        return self.value_as_integer == other.value_as_integer
+
+    def _repr(self):
+        return repr(self.value_as_integer)
+
+    def __str__(self):
+        return str(self.value_as_integer)
+
+    def __len__(self):
+        return self.field_class.length
+
+
 @functools.total_ordering
 class _NumericField(_Field):
     @staticmethod
@@ -670,6 +698,7 @@ class _DynamicArrayField(_ArrayField, _Field):
 
 _TYPE_ID_TO_OBJ = {
     native_bt.FIELD_CLASS_TYPE_BOOL: _BoolField,
+    native_bt.FIELD_CLASS_TYPE_BIT_ARRAY: _BitArrayField,
     native_bt.FIELD_CLASS_TYPE_UNSIGNED_INTEGER: _UnsignedIntegerField,
     native_bt.FIELD_CLASS_TYPE_SIGNED_INTEGER: _SignedIntegerField,
     native_bt.FIELD_CLASS_TYPE_REAL: _RealField,
index 9974a29203c96146108c134bf0f3177c9c59b2f9..75d7cc5a785bf3f75c3119e153d3fb2c73f7e370 100644 (file)
@@ -54,6 +54,16 @@ class _BoolFieldClass(_FieldClass):
     _NAME = 'Boolean'
 
 
+class _BitArrayFieldClass(_FieldClass):
+    _NAME = 'Bit array'
+
+    @property
+    def length(self):
+        length = native_bt.field_class_bit_array_get_length(self._ptr)
+        assert length >= 1
+        return length
+
+
 class _IntegerFieldClass(_FieldClass):
     @property
     def field_value_range(self):
@@ -603,6 +613,7 @@ class _DynamicArrayFieldClass(_ArrayFieldClass):
 
 _FIELD_CLASS_TYPE_TO_OBJ = {
     native_bt.FIELD_CLASS_TYPE_BOOL: _BoolFieldClass,
+    native_bt.FIELD_CLASS_TYPE_BIT_ARRAY: _BitArrayFieldClass,
     native_bt.FIELD_CLASS_TYPE_UNSIGNED_INTEGER: _UnsignedIntegerFieldClass,
     native_bt.FIELD_CLASS_TYPE_SIGNED_INTEGER: _SignedIntegerFieldClass,
     native_bt.FIELD_CLASS_TYPE_REAL: _RealFieldClass,
index 3ae3addefbcb3126ee21d4baed643632d791e0f7..b9ac172fc0a19de3bd6268e485e4d8313cc73038 100644 (file)
@@ -194,6 +194,21 @@ class _TraceClass(object._SharedObject, collections.abc.Mapping):
 
         return bt2_field_class._BoolFieldClass._create_from_ptr(field_class_ptr)
 
+    def create_bit_array_field_class(self, length):
+        utils._check_uint64(length)
+
+        if length < 1 or length > 64:
+            raise ValueError(
+                'invalid length {}: expecting a value in the [1, 64] range'.format(
+                    length
+                )
+            )
+
+        field_class_ptr = native_bt.field_class_bit_array_create(self._ptr, length)
+        self._check_field_class_create_status(field_class_ptr, 'bit array')
+
+        return bt2_field_class._BitArrayFieldClass._create_from_ptr(field_class_ptr)
+
     def _create_integer_field_class(
         self, create_func, py_cls, type_name, field_value_range, preferred_display_base
     ):
index 429fe2eea37089444eefd1e38b8e4778f99f25a1..5c8d82870dbfff0961ee82b9b2e29036fa22a0a3 100644 (file)
@@ -126,6 +126,52 @@ def _create_struct_array_field(tc, length):
     return packet.context_field[field_name]
 
 
+class BitArrayFieldTestCase(unittest.TestCase):
+    def _create_field(self):
+        return _create_field(self._tc, self._tc.create_bit_array_field_class(24))
+
+    def setUp(self):
+        self._tc = get_default_trace_class()
+        self._def_value = 15497
+        self._def = self._create_field()
+        self._def.value_as_integer = self._def_value
+        self._def_new_value = 101542
+
+    def test_assign_invalid_type(self):
+        with self.assertRaises(TypeError):
+            self._def.value_as_integer = 'onze'
+
+    def test_assign(self):
+        self._def.value_as_integer = 199
+        self.assertEqual(self._def.value_as_integer, 199)
+
+    def test_assign_masked(self):
+        self._def.value_as_integer = 0xE1549BB
+        self.assertEqual(self._def.value_as_integer, 0xE1549BB & ((1 << 24) - 1))
+
+    def test_eq(self):
+        other = self._create_field()
+        other.value_as_integer = self._def_value
+        self.assertEqual(self._def, other)
+
+    def test_ne_same_type(self):
+        other = self._create_field()
+        other.value_as_integer = self._def_value - 1
+        self.assertNotEqual(self._def, other)
+
+    def test_ne_diff_type(self):
+        self.assertNotEqual(self._def, self._def_value)
+
+    def test_len(self):
+        self.assertEqual(len(self._def), 24)
+
+    def test_str(self):
+        self.assertEqual(str(self._def), str(self._def_value))
+
+    def test_repr(self):
+        self.assertEqual(repr(self._def), repr(self._def_value))
+
+
 # Base class for numeric field test cases.
 #
 # To be compatible with this base class, a derived class must, in its
index af9565070405e54644919ca4478bff1bff34d1eb..e564cac5f2a9c8a6533b1360c6a057186fa40de5 100644 (file)
@@ -30,6 +30,30 @@ class BoolFieldClassTestCase(unittest.TestCase):
         self.assertIsNotNone(self._fc)
 
 
+class BitArrayFieldClassTestCase(unittest.TestCase):
+    def setUp(self):
+        self._tc = get_default_trace_class()
+        self._fc = self._tc.create_bit_array_field_class(17)
+
+    def test_create_default(self):
+        self.assertIsNotNone(self._fc)
+
+    def test_create_length_out_of_range(self):
+        with self.assertRaises(ValueError):
+            self._tc.create_bit_array_field_class(65)
+
+    def test_create_length_zero(self):
+        with self.assertRaises(ValueError):
+            self._tc.create_bit_array_field_class(0)
+
+    def test_create_length_invalid_type(self):
+        with self.assertRaises(TypeError):
+            self._tc.create_bit_array_field_class('lel')
+
+    def test_length_prop(self):
+        self.assertEqual(self._fc.length, 17)
+
+
 class _TestIntegerFieldClassProps:
     def test_create_default(self):
         fc = self._create_func()
index bcf30fed5808e0beab311d43d933153644c6631e..71e792a4fe33ca1405e1e6d2273054c45e1e8b83 100644 (file)
@@ -84,6 +84,9 @@ class PackageTestCase(unittest.TestCase):
     def test_has__BoolField(self):
         self._assert_in_bt2('_BoolField')
 
+    def test_has__BitArrayField(self):
+        self._assert_in_bt2('_BitArrayField')
+
     def test_has__IntegerField(self):
         self._assert_in_bt2('_IntegerField')
 
@@ -132,6 +135,9 @@ class PackageTestCase(unittest.TestCase):
     def test_has__BoolFieldClass(self):
         self._assert_in_bt2('_BoolFieldClass')
 
+    def test_has__BitArrayFieldClass(self):
+        self._assert_in_bt2('_BitArrayFieldClass')
+
     def test_has__IntegerFieldClass(self):
         self._assert_in_bt2('_IntegerFieldClass')
 
This page took 0.028545 seconds and 4 git commands to generate.