golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/quic/rangeset.go (about)

     1  // Copyright 2023 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build go1.21
     6  
     7  package quic
     8  
     9  // A rangeset is a set of int64s, stored as an ordered list of non-overlapping,
    10  // non-empty ranges.
    11  //
    12  // Rangesets are efficient for small numbers of ranges,
    13  // which is expected to be the common case.
    14  type rangeset[T ~int64] []i64range[T]
    15  
    16  type i64range[T ~int64] struct {
    17  	start, end T // [start, end)
    18  }
    19  
    20  // size returns the size of the range.
    21  func (r i64range[T]) size() T {
    22  	return r.end - r.start
    23  }
    24  
    25  // contains reports whether v is in the range.
    26  func (r i64range[T]) contains(v T) bool {
    27  	return r.start <= v && v < r.end
    28  }
    29  
    30  // add adds [start, end) to the set, combining it with existing ranges if necessary.
    31  func (s *rangeset[T]) add(start, end T) {
    32  	if start == end {
    33  		return
    34  	}
    35  	for i := range *s {
    36  		r := &(*s)[i]
    37  		if r.start > end {
    38  			// The new range comes before range i.
    39  			s.insertrange(i, start, end)
    40  			return
    41  		}
    42  		if start > r.end {
    43  			// The new range comes after range i.
    44  			continue
    45  		}
    46  		// The new range is adjacent to or overlapping range i.
    47  		if start < r.start {
    48  			r.start = start
    49  		}
    50  		if end <= r.end {
    51  			return
    52  		}
    53  		// Possibly coalesce subsequent ranges into range i.
    54  		r.end = end
    55  		j := i + 1
    56  		for ; j < len(*s) && r.end >= (*s)[j].start; j++ {
    57  			if e := (*s)[j].end; e > r.end {
    58  				// Range j ends after the new range.
    59  				r.end = e
    60  			}
    61  		}
    62  		s.removeranges(i+1, j)
    63  		return
    64  	}
    65  	*s = append(*s, i64range[T]{start, end})
    66  }
    67  
    68  // sub removes [start, end) from the set.
    69  func (s *rangeset[T]) sub(start, end T) {
    70  	removefrom, removeto := -1, -1
    71  	for i := range *s {
    72  		r := &(*s)[i]
    73  		if end < r.start {
    74  			break
    75  		}
    76  		if r.end < start {
    77  			continue
    78  		}
    79  		switch {
    80  		case start <= r.start && end >= r.end:
    81  			// Remove the entire range.
    82  			if removefrom == -1 {
    83  				removefrom = i
    84  			}
    85  			removeto = i + 1
    86  		case start <= r.start:
    87  			// Remove a prefix.
    88  			r.start = end
    89  		case end >= r.end:
    90  			// Remove a suffix.
    91  			r.end = start
    92  		default:
    93  			// Remove the middle, leaving two new ranges.
    94  			rend := r.end
    95  			r.end = start
    96  			s.insertrange(i+1, end, rend)
    97  			return
    98  		}
    99  	}
   100  	if removefrom != -1 {
   101  		s.removeranges(removefrom, removeto)
   102  	}
   103  }
   104  
   105  // contains reports whether s contains v.
   106  func (s rangeset[T]) contains(v T) bool {
   107  	for _, r := range s {
   108  		if v >= r.end {
   109  			continue
   110  		}
   111  		if r.start <= v {
   112  			return true
   113  		}
   114  		return false
   115  	}
   116  	return false
   117  }
   118  
   119  // rangeContaining returns the range containing v, or the range [0,0) if v is not in s.
   120  func (s rangeset[T]) rangeContaining(v T) i64range[T] {
   121  	for _, r := range s {
   122  		if v >= r.end {
   123  			continue
   124  		}
   125  		if r.start <= v {
   126  			return r
   127  		}
   128  		break
   129  	}
   130  	return i64range[T]{0, 0}
   131  }
   132  
   133  // min returns the minimum value in the set, or 0 if empty.
   134  func (s rangeset[T]) min() T {
   135  	if len(s) == 0 {
   136  		return 0
   137  	}
   138  	return s[0].start
   139  }
   140  
   141  // max returns the maximum value in the set, or 0 if empty.
   142  func (s rangeset[T]) max() T {
   143  	if len(s) == 0 {
   144  		return 0
   145  	}
   146  	return s[len(s)-1].end - 1
   147  }
   148  
   149  // end returns the end of the last range in the set, or 0 if empty.
   150  func (s rangeset[T]) end() T {
   151  	if len(s) == 0 {
   152  		return 0
   153  	}
   154  	return s[len(s)-1].end
   155  }
   156  
   157  // numRanges returns the number of ranges in the rangeset.
   158  func (s rangeset[T]) numRanges() int {
   159  	return len(s)
   160  }
   161  
   162  // isrange reports if the rangeset covers exactly the range [start, end).
   163  func (s rangeset[T]) isrange(start, end T) bool {
   164  	switch len(s) {
   165  	case 0:
   166  		return start == 0 && end == 0
   167  	case 1:
   168  		return s[0].start == start && s[0].end == end
   169  	}
   170  	return false
   171  }
   172  
   173  // removeranges removes ranges [i,j).
   174  func (s *rangeset[T]) removeranges(i, j int) {
   175  	if i == j {
   176  		return
   177  	}
   178  	copy((*s)[i:], (*s)[j:])
   179  	*s = (*s)[:len(*s)-(j-i)]
   180  }
   181  
   182  // insert adds a new range at index i.
   183  func (s *rangeset[T]) insertrange(i int, start, end T) {
   184  	*s = append(*s, i64range[T]{})
   185  	copy((*s)[i+1:], (*s)[i:])
   186  	(*s)[i] = i64range[T]{start, end}
   187  }