<commit_before>from bisect import bisect_left
from collections import deque
from Ranger.src.Range.Range import Range

class RangeSet(object):
    """ Class used to represent a set of non-overlapping ranges of the
    same type. If a range is added that is connected to another range
    already in the set, those ranges are merged. Otherwise, it is added as
    a new range in the set
    """
    def __init__(self, ranges = None):
        """ Instantiates the RangeSet

        Parameters
        ----------
        ranges : List of Range objects
            Ranges to add to the Set
        """
        ## Holds lower and upper cut points of ranges
        self.lower_cuts = []
        self.upper_cuts = []
        ## Holds the range objects in the set
        self.ranges = []
        if ranges is not None:
            for aRange in ranges:
                self.add(aRange)
    def __repr__(self):
        return "RangeSet(%s)" % ", ".join(map(str, self.ranges))
    def __len__(self):
        return len(self.ranges)
    def __eq__(self, other):
        if not isinstance(other, RangeSet):
            return False
        elif len(self) != len(other):
            return False
        else:
            for r1,r2 in zip(self.ranges, other.ranges):
                if r1 != r2: return False
            return True
    def __ne__(self, other):
        return not self.__eq__(other)
    def add(self, aRange):
        """ Adds a range to the range set. If this range is not connected
        to any current ranges, it will place the new range on its own. If
        there is a connection, any connected ranges will be merged into a single
        range

        Parameters
        ----------
        aRange : A Range object
            The Range to add to the RangeSet

        Raises
        ------
        ValueError
            If adding range of type not compatible with previously
            added ranges
        """
        # Check for compatibility of types if necessary
        if len(self) > 0:
            if not (issubclass(aRange.lowerCut.theType,
                               self.ranges[0].lowerCut.theType) or \
                    issubclass(self.ranges[0].lowerCut.theType,
                               aRange.lowerCut.theType)):
                raise ValueError("Range not compatible with previously added ranges")
        # Get the insertion point (where the lower bound should go), should
        # this range be added on its own
        lower_ind = bisect_left(self.lower_cuts, aRange.lowerCut)
        if len(self) == 0:
            # Add on its own if there is nothing in the list
            self.ranges.append(aRange)
            self.lower_cuts.append(aRange.lowerCut)
            self.upper_cuts.append(aRange.upperCut)
        elif len(self) == lower_ind:
            if not aRange.isConnected(self.ranges[max(lower_ind-1,0)]):
                # Add on its own if not connected to previous and last
                self.ranges.insert(lower_ind,aRange)
                self.lower_cuts.insert(lower_ind,aRange.lowerCut)
                self.upper_cuts.insert(lower_ind,aRange.upperCut)<commit_msg>Allowing skipping of empty ranges in RangeSet.add<commit_after>from bisect import bisect_left
from collections import deque
from Ranger.src.Range.Range import Range

class RangeSet(object):
    """ Class used to represent a set of non-overlapping ranges of the
    same type. If a range is added that is connected to another range
    already in the set, those ranges are merged. Otherwise, it is added as
    a new range in the set
    """
    def __init__(self, ranges = None):
        """ Instantiates the RangeSet

        Parameters
        ----------
        ranges : List of Range objects
            Ranges to add to the Set
        """
        ## Holds lower and upper cut points of ranges
        self.lower_cuts = []
        self.upper_cuts = []
        ## Holds the range objects in the set
        self.ranges = []
        if ranges is not None:
            for aRange in ranges:
                self.add(aRange)
    def __repr__(self):
        return "RangeSet(%s)" % ", ".join(map(str, self.ranges))
    def __len__(self):
        return len(self.ranges)
    def __eq__(self, other):
        if not isinstance(other, RangeSet):
            return False
        elif len(self) != len(other):
            return False
        else:
            for r1,r2 in zip(self.ranges, other.ranges):
                if r1 != r2: return False
            return True
    def __ne__(self, other):
        return not self.__eq__(other)
    def add(self, aRange):
        """ Adds a range to the range set. If this range is not connected
        to any current ranges, it will place the new range on its own. If
        there is a connection, any connected ranges will be merged into a single
        range

        Parameters
        ----------
        aRange : A Range object
            The Range to add to the RangeSet

        Raises
        ------
        ValueError
            If adding range of type not compatible with previously
            added ranges
        TypeError:
            If not adding a Range
        """
        if not isinstance(aRange, Range):
            raise TypeError("aRange is not a Range")
        elif aRange.isEmpty():
            # Skip if this is an empty range
            return
        # Check for compatibility of types if necessary
        if len(self) > 0:
            if not (issubclass(aRange.lowerCut.theType,
                               self.ranges[0].lowerCut.theType) or \
                    issubclass(self.ranges[0].lowerCut.theType,
                               aRange.lowerCut.theType)):
                raise ValueError("Range not compatible with previously added ranges")
        # Get the insertion point (where the lower bound should go), should
        # this range be added on its own
        lower_ind = bisect_left(self.lower_cuts, aRange.lowerCut)
        if len(self) == 0:
            # Add on its own if there is nothing in the list
            self.ranges.append(aRange)
            self.lower_cuts.append(aRange.lowerCut)
            self.upper_cuts.append(aRange.upperCut)
        elif len(self) == lower_ind:
            if not aRange.isConnected(self.ranges[max(lower_ind-1,0)]):
                # Add on its own if not connected to previous and last
                self.ranges.insert(lower_ind,aRange)
                self.lower_cuts.insert(lower_ind,aRange.lowerCut)
                self.upper_cuts.insert(lower_ind,aRange.upperCut)
{'fraction_non_alphanumeric': 0.07871007183249273, 'fraction_numerical': 0.0030567018187375823, 'mean_word_length': 1.8109965635738832, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '909007', 'n_tokens_mistral': 1751, 'n_tokens_neox': 1708, 'n_words': 629}