123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 |
- # coding=utf-8
- #
- # This file is part of Hypothesis, which may be found at
- # https://github.com/HypothesisWorks/hypothesis-python
- #
- # Most of this work is copyright (C) 2013-2018 David R. MacIver
- # (david@drmaciver.com), but it contains contributions by others. See
- # CONTRIBUTING.rst for a full list of people who may hold copyright, and
- # consult the git log if you need to determine who owns an individual
- # contribution.
- #
- # This Source Code Form is subject to the terms of the Mozilla Public License,
- # v. 2.0. If a copy of the MPL was not distributed with this file, You can
- # obtain one at http://mozilla.org/MPL/2.0/.
- #
- # END HEADER
- from __future__ import division, print_function, absolute_import
- class IntervalSet(object):
- def __init__(self, intervals):
- self.intervals = tuple(intervals)
- self.offsets = [0]
- for u, v in self.intervals:
- self.offsets.append(
- self.offsets[-1] + v - u + 1
- )
- self.size = self.offsets.pop()
- def __len__(self):
- return self.size
- def __iter__(self):
- for u, v in self.intervals:
- for i in range(u, v + 1):
- yield i
- def __getitem__(self, i):
- if i < 0:
- i = self.size + i
- if i < 0 or i >= self.size:
- raise IndexError('Invalid index %d for [0, %d)' % (i, self.size))
- # Want j = maximal such that offsets[j] <= i
- j = len(self.intervals) - 1
- if self.offsets[j] > i:
- hi = j
- lo = 0
- # Invariant: offsets[lo] <= i < offsets[hi]
- while lo + 1 < hi:
- mid = (lo + hi) // 2
- if self.offsets[mid] <= i:
- lo = mid
- else:
- hi = mid
- j = lo
- t = i - self.offsets[j]
- u, v = self.intervals[j]
- r = u + t
- assert r <= v
- return r
- def __repr__(self):
- return 'IntervalSet(%r)' % (self.intervals,)
- def index(self, value):
- for offset, (u, v) in zip(self.offsets, self.intervals):
- if u == value:
- return offset
- elif u > value:
- raise ValueError('%d is not in list' % (value,))
- if value <= v:
- return offset + (value - u)
- raise ValueError('%d is not in list' % (value,))
- def index_above(self, value):
- for offset, (u, v) in zip(self.offsets, self.intervals):
- if u >= value:
- return offset
- if value <= v:
- return offset + (value - u)
- return self.size
|