From 7b4126b7c774531c8a40e291e66286ec61586fe1 Mon Sep 17 00:00:00 2001 From: Iustin Pop <iustin@google.com> Date: Tue, 1 Jul 2008 11:44:37 +0000 Subject: [PATCH] Add a FirstFree function to utils.py This function will return the first unused integer based on a list of used integers (e.g. [0, 1, 3] will return 2). Reviewed-by: imsnah --- lib/utils.py | 21 +++++++++++++++++++++ test/ganeti.utils_unittest.py | 12 +++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/lib/utils.py b/lib/utils.py index 4e8cfe7e7..ade6b9b54 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -1039,6 +1039,27 @@ def WriteFile(file_name, fn=None, data=None, return result +def FirstFree(seq, base=0): + """Returns the first non-existing integer from seq. + + The seq argument should be a sorted list of positive integers. The + first time the index of an element is smaller than the element + value, the index will be returned. + + The base argument is used to start at a different offset, + i.e. [3, 4, 6] with offset=3 will return 5. + + Example: [0, 1, 3] will return 2. + + """ + for idx, elem in enumerate(seq): + assert elem >= base, "Passed element is higher than base offset" + if elem > idx + base: + # idx is not used + return idx + base + return None + + def all(seq, pred=bool): "Returns True if pred(x) is True for every element in the iterable" for elem in itertools.ifilterfalse(pred, seq): diff --git a/test/ganeti.utils_unittest.py b/test/ganeti.utils_unittest.py index c5f8cfda6..1d9bd2f1a 100755 --- a/test/ganeti.utils_unittest.py +++ b/test/ganeti.utils_unittest.py @@ -41,7 +41,7 @@ from ganeti.utils import IsProcessAlive, Lock, Unlock, RunCmd, \ RemoveFile, CheckDict, MatchNameComponent, FormatUnit, \ ParseUnit, AddAuthorizedKey, RemoveAuthorizedKey, \ ShellQuote, ShellQuoteArgs, TcpPing, ListVisibleFiles, \ - SetEtcHostsEntry, RemoveEtcHostsEntry + SetEtcHostsEntry, RemoveEtcHostsEntry, FirstFree from ganeti.errors import LockError, UnitParseError def _ChildHandler(signal, stack): @@ -689,6 +689,16 @@ class TestUniqueSequence(unittest.TestCase): self._test(["a", "b"], ["a", "b"]) self._test(["a", "b", "a"], ["a", "b"]) +class TestFirstFree(unittest.TestCase): + """Test case for the FirstFree function""" + + def test(self): + """Test FirstFree""" + self.failUnlessEqual(FirstFree([0, 1, 3]), 2) + self.failUnlessEqual(FirstFree([]), None) + self.failUnlessEqual(FirstFree([3, 4, 6]), 0) + self.failUnlessEqual(FirstFree([3, 4, 6], base=3), 5) + self.failUnlessRaises(AssertionError, FirstFree, [0, 3, 4, 6], base=3) if __name__ == '__main__': unittest.main() -- GitLab