--- /dev/null
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import native_bt, object, utils
+import collections.abc
+import bt2
+
+
+class _IntegerRange:
+ def __init__(self, lower, upper):
+ self._check_type(lower)
+ self._check_type(upper)
+
+ if lower > upper:
+ raise ValueError("range's lower bound ({}) is greater than its upper bound ({})".format(lower, upper))
+
+ self._lower = lower
+ self._upper = upper
+
+ @property
+ def lower(self):
+ return self._lower
+
+ @property
+ def upper(self):
+ return self._upper
+
+ def contains(self, value):
+ self._check_type(value)
+ return value >= self._lower and value <= self._upper
+
+ def __eq__(self, other):
+ if type(other) is not type(self):
+ return False
+
+ return self.lower == other.lower and self.upper == other.upper
+
+
+class SignedIntegerRange(_IntegerRange):
+ _check_type = staticmethod(utils._check_int64)
+
+
+class UnsignedIntegerRange(_IntegerRange):
+ _check_type = staticmethod(utils._check_uint64)
+
+
+class _IntegerRangeSet(object._SharedObject, collections.abc.MutableSet):
+ def __init__(self, ranges=None):
+ ptr = self._create_range_set()
+
+ if ptr is None:
+ raise bt2.CreationError('cannot create range set object')
+
+ super().__init__(ptr)
+
+ if ranges is not None:
+ # will raise if not iterable
+ for rg in ranges:
+ self.add(rg)
+
+ def __len__(self):
+ range_set_ptr = self._as_range_set_ptr(self._ptr)
+ count = native_bt.integer_range_set_get_range_count(range_set_ptr)
+ assert count >= 0
+ return count
+
+ def __contains__(self, other_range):
+ for rg in self:
+ if rg == other_range:
+ return True
+
+ return False
+
+ def __iter__(self):
+ for idx in range(len(self)):
+ rg_ptr = self._borrow_range_by_index_ptr(self._ptr, idx)
+ assert rg_ptr is not None
+ lower = self._range_get_lower(rg_ptr)
+ upper = self._range_get_upper(rg_ptr)
+ yield self._range_type(lower, upper)
+
+ def __eq__(self, other):
+ if type(other) is not type(self):
+ return False
+
+ return self._compare(self._ptr, other._ptr)
+
+ def contains_value(self, value):
+ for rg in self:
+ if rg.contains(value):
+ return True
+
+ return False
+
+ def add(self, rg):
+ if type(rg) is not self._range_type:
+ # assume it's a simple pair (will raise if it's not)
+ rg = self._range_type(rg[0], rg[1])
+
+ status = self._add_range(self._ptr, rg.lower, rg.upper)
+ utils._handle_func_status(status,
+ 'cannot add range to range set object')
+
+ def discard(self, rg):
+ raise NotImplementedError
+
+
+class SignedIntegerRangeSet(_IntegerRangeSet):
+ _get_ref = staticmethod(native_bt.integer_range_set_signed_get_ref)
+ _put_ref = staticmethod(native_bt.integer_range_set_signed_put_ref)
+ _as_range_set_ptr = staticmethod(native_bt.integer_range_set_signed_as_range_set_const)
+ _create_range_set = staticmethod(native_bt.integer_range_set_signed_create)
+ _borrow_range_by_index_ptr = staticmethod(native_bt.integer_range_set_signed_borrow_range_by_index_const)
+ _range_get_lower = staticmethod(native_bt.integer_range_signed_get_lower)
+ _range_get_upper = staticmethod(native_bt.integer_range_signed_get_upper)
+ _add_range = staticmethod(native_bt.integer_range_set_signed_add_range)
+ _compare = staticmethod(native_bt.integer_range_set_signed_compare)
+ _range_type = SignedIntegerRange
+
+
+class UnsignedIntegerRangeSet(_IntegerRangeSet):
+ _get_ref = staticmethod(native_bt.integer_range_set_unsigned_get_ref)
+ _put_ref = staticmethod(native_bt.integer_range_set_unsigned_put_ref)
+ _as_range_set_ptr = staticmethod(native_bt.integer_range_set_unsigned_as_range_set_const)
+ _create_range_set = staticmethod(native_bt.integer_range_set_unsigned_create)
+ _borrow_range_by_index_ptr = staticmethod(native_bt.integer_range_set_unsigned_borrow_range_by_index_const)
+ _range_get_lower = staticmethod(native_bt.integer_range_unsigned_get_lower)
+ _range_get_upper = staticmethod(native_bt.integer_range_unsigned_get_upper)
+ _add_range = staticmethod(native_bt.integer_range_set_unsigned_add_range)
+ _compare = staticmethod(native_bt.integer_range_set_unsigned_compare)
+ _range_type = UnsignedIntegerRange
--- /dev/null
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/*
+ * Typemap for the user data attached to (and owned by) a self component port.
+ * The pointer saved as the port's user data is directly the PyObject *.
+ *
+ * As per the CPython calling convention, we need to return a new reference to
+ * the returned object, which will be transferred to the caller.
+ */
+
+%include <babeltrace2/integer-range-set.h>
+%include <babeltrace2/integer-range-set-const.h>
--- /dev/null
+#
+# Copyright (C) 2019 EfficiOS Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; only version 2
+# of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+import bt2
+import unittest
+
+
+class _IntegerRangeTestCase:
+ def setUp(self):
+ self._rg = self._CLS(self._def_lower, self._def_upper)
+
+ def test_create(self):
+ self.assertEqual(self._rg.lower, self._def_lower)
+ self.assertEqual(self._rg.upper, self._def_upper)
+
+ def test_create_same(self):
+ rg = self._CLS(self._def_lower, self._def_lower)
+ self.assertEqual(rg.lower, self._def_lower)
+ self.assertEqual(rg.upper, self._def_lower)
+
+ def test_create_wrong_type_lower(self):
+ with self.assertRaises(TypeError):
+ rg = self._CLS(19.3, self._def_upper)
+
+ def test_create_wrong_type_lower(self):
+ with self.assertRaises(TypeError):
+ rg = self._CLS(self._def_lower, 19.3)
+
+ def test_create_out_of_bound_lower(self):
+ with self.assertRaises(ValueError):
+ rg = self._CLS(self._oob_lower, self._def_upper)
+
+ def test_create_out_of_bound_upper(self):
+ with self.assertRaises(ValueError):
+ rg = self._CLS(self._def_lower, self._oob_upper)
+
+ def test_create_lower_gt_upper(self):
+ with self.assertRaises(ValueError):
+ rg = self._CLS(self._def_lower, self._def_lower - 1)
+
+ def test_contains_lower(self):
+ self.assertTrue(self._rg.contains(self._def_lower))
+
+ def test_contains_upper(self):
+ self.assertTrue(self._rg.contains(self._def_upper))
+
+ def test_contains_avg(self):
+ avg = (self._def_lower + self._def_upper) // 2
+ self.assertTrue(self._rg.contains(avg))
+
+ def test_contains_wrong_type(self):
+ with self.assertRaises(TypeError):
+ self._rg.contains('allo')
+
+ def test_contains_out_of_bound(self):
+ with self.assertRaises(ValueError):
+ self._rg.contains(self._oob_upper)
+
+ def test_eq(self):
+ rg = self._CLS(self._def_lower, self._def_upper)
+ self.assertEqual(rg, self._rg)
+
+ def test_ne(self):
+ rg = self._CLS(self._def_lower, self._def_upper - 1)
+ self.assertNotEqual(rg, self._rg)
+
+ def test_ne_other_type(self):
+ self.assertNotEqual(self._rg, 48)
+
+
+class UnsignedIntegerRangeTestCase(_IntegerRangeTestCase, unittest.TestCase):
+ _CLS = bt2.UnsignedIntegerRange
+ _def_lower = 23
+ _def_upper = 18293
+ _oob_lower = -1
+ _oob_upper = 1 << 64
+
+
+class SignedIntegerRangeTestCase(_IntegerRangeTestCase, unittest.TestCase):
+ _CLS = bt2.SignedIntegerRange
+ _def_lower = -184
+ _def_upper = 11547
+ _oob_lower = -(1 << 63) - 1
+ _oob_upper = 1 << 63
+
+
+class _IntegerRangeSetTestCase:
+ def setUp(self):
+ self._rs = self._CLS((self._range1, self._range2, self._range3))
+
+ def test_create(self):
+ self.assertEqual(len(self._rs), 3)
+ self.assertIn(self._range1, self._rs)
+ self.assertIn(self._range2, self._rs)
+ self.assertIn(self._range3, self._rs)
+
+ def test_create_tuples(self):
+ rs = self._CLS((
+ (self._range1.lower, self._range1.upper),
+ (self._range2.lower, self._range2.upper),
+ (self._range3.lower, self._range3.upper),
+ ))
+ self.assertEqual(len(rs), 3)
+ self.assertIn(self._range1, rs)
+ self.assertIn(self._range2, rs)
+ self.assertIn(self._range3, rs)
+
+ def test_create_non_iter(self):
+ with self.assertRaises(TypeError):
+ self._rs = self._CLS(23)
+
+ def test_create_wrong_elem_type(self):
+ with self.assertRaises(TypeError):
+ self._rs = self._CLS((self._range1, self._range2, 17))
+
+ def test_len(self):
+ self.assertEqual(len(self._rs), 3)
+
+ def test_contains(self):
+ rs = self._CLS((self._range1, self._range2))
+ self.assertIn(self._range1, rs)
+ self.assertIn(self._range2, rs)
+ self.assertNotIn(self._range3, rs)
+
+ def test_contains_value(self):
+ rs = self._CLS((self._range1, self._range2))
+ self.assertTrue(rs.contains_value(self._range1.upper))
+ self.assertTrue(rs.contains_value(self._range2.lower))
+ self.assertFalse(rs.contains_value(self._range3.upper))
+
+ def test_contains_value_wrong_type(self):
+ with self.assertRaises(TypeError):
+ self._rs.contains_value('meow')
+
+ def test_iter(self):
+ range_list = list(self._rs)
+ self.assertIn(self._range1, range_list)
+ self.assertIn(self._range2, range_list)
+ self.assertIn(self._range3, range_list)
+
+ def test_empty(self):
+ rs = self._CLS()
+ self.assertEqual(len(rs), 0)
+ self.assertEqual(len(list(rs)), 0)
+
+ def test_add_range_obj(self):
+ rs = self._CLS((self._range1,))
+ self.assertEqual(len(rs), 1)
+ rs.add(self._range2)
+ self.assertEqual(len(rs), 2)
+ self.assertIn(self._range2, rs)
+
+ def test_discard_not_implemented(self):
+ with self.assertRaises(NotImplementedError):
+ self._rs.discard(self._range2)
+
+ def test_eq_same_order(self):
+ rs = self._CLS((self._range1, self._range2, self._range3))
+ self.assertEqual(self._rs, rs)
+
+ def test_eq_diff_order(self):
+ rs = self._CLS((self._range1, self._range3, self._range2))
+ self.assertEqual(self._rs, rs)
+
+ def test_eq_same_addr(self):
+ self.assertEqual(self._rs, self._rs)
+
+ def test_ne_diff_len(self):
+ rs = self._CLS((self._range1, self._range2))
+ self.assertNotEqual(self._rs, rs)
+
+ def test_ne_diff_values(self):
+ rs1 = self._CLS((self._range1, self._range2))
+ rs2 = self._CLS((self._range1, self._range3))
+ self.assertNotEqual(rs1, rs2)
+
+ def test_ne_incompatible_type(self):
+ self.assertNotEqual(self._rs, object())
+
+
+class UnsignedIntegerRangeSetTestCase(_IntegerRangeSetTestCase, unittest.TestCase):
+ _CLS = bt2.UnsignedIntegerRangeSet
+
+ def setUp(self):
+ self._range1 = bt2.UnsignedIntegerRange(4, 192)
+ self._range2 = bt2.UnsignedIntegerRange(17, 228)
+ self._range3 = bt2.UnsignedIntegerRange(1000, 2000)
+ super().setUp()
+
+
+class SignedIntegerRangeSetTestCase(_IntegerRangeSetTestCase, unittest.TestCase):
+ _CLS = bt2.SignedIntegerRangeSet
+
+ def setUp(self):
+ self._range1 = bt2.SignedIntegerRange(-1484, -17)
+ self._range2 = bt2.SignedIntegerRange(-101, 1500)
+ self._range3 = bt2.SignedIntegerRange(1948, 2019)
+ super().setUp()