summaryrefslogtreecommitdiff
path: root/perfprofd/scripts/sorted_collection.py
diff options
context:
space:
mode:
Diffstat (limited to 'perfprofd/scripts/sorted_collection.py')
-rw-r--r--perfprofd/scripts/sorted_collection.py146
1 files changed, 146 insertions, 0 deletions
diff --git a/perfprofd/scripts/sorted_collection.py b/perfprofd/scripts/sorted_collection.py
new file mode 100644
index 00000000..315f7c89
--- /dev/null
+++ b/perfprofd/scripts/sorted_collection.py
@@ -0,0 +1,146 @@
+# Note: Taken from https://code.activestate.com/recipes/577197-sortedcollection/.
+#
+# Copyright 2010 Raymond Hettinger
+#
+# 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 bisect import bisect_left, bisect_right
+
+class SortedCollection(object):
+ def __init__(self, iterable=(), key=None):
+ self._given_key = key
+ key = (lambda x: x) if key is None else key
+ decorated = sorted((key(item), item) for item in iterable)
+ self._keys = [k for k, item in decorated]
+ self._items = [item for k, item in decorated]
+ self._key = key
+
+ def _getkey(self):
+ return self._key
+
+ def _setkey(self, key):
+ if key is not self._key:
+ self.__init__(self._items, key=key)
+
+ def _delkey(self):
+ self._setkey(None)
+
+ key = property(_getkey, _setkey, _delkey, 'key function')
+
+ def clear(self):
+ self.__init__([], self._key)
+
+ def copy(self):
+ return self.__class__(self, self._key)
+
+ def __len__(self):
+ return len(self._items)
+
+ def __getitem__(self, i):
+ return self._items[i]
+
+ def __iter__(self):
+ return iter(self._items)
+
+ def __reversed__(self):
+ return reversed(self._items)
+
+ def __repr__(self):
+ return '%s(%r, key=%s)' % (
+ self.__class__.__name__,
+ self._items,
+ getattr(self._given_key, '__name__', repr(self._given_key))
+ )
+
+ def __reduce__(self):
+ return self.__class__, (self._items, self._given_key)
+
+ def __contains__(self, item):
+ k = self._key(item)
+ i = bisect_left(self._keys, k)
+ j = bisect_right(self._keys, k)
+ return item in self._items[i:j]
+
+ def index(self, item):
+ 'Find the position of an item. Raise ValueError if not found.'
+ k = self._key(item)
+ i = bisect_left(self._keys, k)
+ j = bisect_right(self._keys, k)
+ return self._items[i:j].index(item) + i
+
+ def count(self, item):
+ 'Return number of occurrences of item'
+ k = self._key(item)
+ i = bisect_left(self._keys, k)
+ j = bisect_right(self._keys, k)
+ return self._items[i:j].count(item)
+
+ def insert(self, item):
+ 'Insert a new item. If equal keys are found, add to the left'
+ k = self._key(item)
+ i = bisect_left(self._keys, k)
+ self._keys.insert(i, k)
+ self._items.insert(i, item)
+
+ def insert_right(self, item):
+ 'Insert a new item. If equal keys are found, add to the right'
+ k = self._key(item)
+ i = bisect_right(self._keys, k)
+ self._keys.insert(i, k)
+ self._items.insert(i, item)
+
+ def remove(self, item):
+ 'Remove first occurence of item. Raise ValueError if not found'
+ i = self.index(item)
+ del self._keys[i]
+ del self._items[i]
+
+ def find(self, k):
+ 'Return first item with a key == k. Raise ValueError if not found.'
+ i = bisect_left(self._keys, k)
+ if i != len(self) and self._keys[i] == k:
+ return self._items[i]
+ raise ValueError('No item found with key equal to: %r' % (k,))
+
+ def find_le(self, k):
+ 'Return last item with a key <= k. Raise ValueError if not found.'
+ i = bisect_right(self._keys, k)
+ if i:
+ return self._items[i-1]
+ raise ValueError('No item found with key at or below: %r' % (k,))
+
+ def find_lt(self, k):
+ 'Return last item with a key < k. Raise ValueError if not found.'
+ i = bisect_left(self._keys, k)
+ if i:
+ return self._items[i-1]
+ raise ValueError('No item found with key below: %r' % (k,))
+
+ def find_ge(self, k):
+ 'Return first item with a key >= equal to k. Raise ValueError if not found'
+ i = bisect_left(self._keys, k)
+ if i != len(self):
+ return self._items[i]
+ raise ValueError('No item found with key at or above: %r' % (k,))
+
+ def find_gt(self, k):
+ 'Return first item with a key > k. Raise ValueError if not found'
+ i = bisect_right(self._keys, k)
+ if i != len(self):
+ return self._items[i]
+ raise ValueError('No item found with key above: %r' % (k,))