aboutsummaryrefslogtreecommitdiff
path: root/src/vendor/golang.org/x/net/quic/rangeset.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/vendor/golang.org/x/net/quic/rangeset.go')
-rw-r--r--src/vendor/golang.org/x/net/quic/rangeset.go193
1 files changed, 193 insertions, 0 deletions
diff --git a/src/vendor/golang.org/x/net/quic/rangeset.go b/src/vendor/golang.org/x/net/quic/rangeset.go
new file mode 100644
index 0000000000..3d6f5f9799
--- /dev/null
+++ b/src/vendor/golang.org/x/net/quic/rangeset.go
@@ -0,0 +1,193 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quic
+
+// A rangeset is a set of int64s, stored as an ordered list of non-overlapping,
+// non-empty ranges.
+//
+// Rangesets are efficient for small numbers of ranges,
+// which is expected to be the common case.
+type rangeset[T ~int64] []i64range[T]
+
+type i64range[T ~int64] struct {
+ start, end T // [start, end)
+}
+
+// size returns the size of the range.
+func (r i64range[T]) size() T {
+ return r.end - r.start
+}
+
+// contains reports whether v is in the range.
+func (r i64range[T]) contains(v T) bool {
+ return r.start <= v && v < r.end
+}
+
+// add adds [start, end) to the set, combining it with existing ranges if necessary.
+func (s *rangeset[T]) add(start, end T) {
+ if start == end {
+ return
+ }
+ for i := range *s {
+ r := &(*s)[i]
+ if r.start > end {
+ // The new range comes before range i.
+ s.insertrange(i, start, end)
+ return
+ }
+ if start > r.end {
+ // The new range comes after range i.
+ continue
+ }
+ // The new range is adjacent to or overlapping range i.
+ if start < r.start {
+ r.start = start
+ }
+ if end <= r.end {
+ return
+ }
+ // Possibly coalesce subsequent ranges into range i.
+ r.end = end
+ j := i + 1
+ for ; j < len(*s) && r.end >= (*s)[j].start; j++ {
+ if e := (*s)[j].end; e > r.end {
+ // Range j ends after the new range.
+ r.end = e
+ }
+ }
+ s.removeranges(i+1, j)
+ return
+ }
+ *s = append(*s, i64range[T]{start, end})
+}
+
+// sub removes [start, end) from the set.
+func (s *rangeset[T]) sub(start, end T) {
+ removefrom, removeto := -1, -1
+ for i := range *s {
+ r := &(*s)[i]
+ if end < r.start {
+ break
+ }
+ if r.end < start {
+ continue
+ }
+ switch {
+ case start <= r.start && end >= r.end:
+ // Remove the entire range.
+ if removefrom == -1 {
+ removefrom = i
+ }
+ removeto = i + 1
+ case start <= r.start:
+ // Remove a prefix.
+ r.start = end
+ case end >= r.end:
+ // Remove a suffix.
+ r.end = start
+ default:
+ // Remove the middle, leaving two new ranges.
+ rend := r.end
+ r.end = start
+ s.insertrange(i+1, end, rend)
+ return
+ }
+ }
+ if removefrom != -1 {
+ s.removeranges(removefrom, removeto)
+ }
+}
+
+// contains reports whether s contains v.
+func (s rangeset[T]) contains(v T) bool {
+ for _, r := range s {
+ if v >= r.end {
+ continue
+ }
+ if r.start <= v {
+ return true
+ }
+ return false
+ }
+ return false
+}
+
+// rangeContaining returns the range containing v, or the range [0,0) if v is not in s.
+func (s rangeset[T]) rangeContaining(v T) i64range[T] {
+ for _, r := range s {
+ if v >= r.end {
+ continue
+ }
+ if r.start <= v {
+ return r
+ }
+ break
+ }
+ return i64range[T]{0, 0}
+}
+
+// min returns the minimum value in the set, or 0 if empty.
+func (s rangeset[T]) min() T {
+ if len(s) == 0 {
+ return 0
+ }
+ return s[0].start
+}
+
+// max returns the maximum value in the set, or 0 if empty.
+func (s rangeset[T]) max() T {
+ if len(s) == 0 {
+ return 0
+ }
+ return s[len(s)-1].end - 1
+}
+
+// end returns the end of the last range in the set, or 0 if empty.
+func (s rangeset[T]) end() T {
+ if len(s) == 0 {
+ return 0
+ }
+ return s[len(s)-1].end
+}
+
+// numRanges returns the number of ranges in the rangeset.
+func (s rangeset[T]) numRanges() int {
+ return len(s)
+}
+
+// size returns the size of all ranges in the rangeset.
+func (s rangeset[T]) size() (total T) {
+ for _, r := range s {
+ total += r.size()
+ }
+ return total
+}
+
+// isrange reports if the rangeset covers exactly the range [start, end).
+func (s rangeset[T]) isrange(start, end T) bool {
+ switch len(s) {
+ case 0:
+ return start == 0 && end == 0
+ case 1:
+ return s[0].start == start && s[0].end == end
+ }
+ return false
+}
+
+// removeranges removes ranges [i,j).
+func (s *rangeset[T]) removeranges(i, j int) {
+ if i == j {
+ return
+ }
+ copy((*s)[i:], (*s)[j:])
+ *s = (*s)[:len(*s)-(j-i)]
+}
+
+// insert adds a new range at index i.
+func (s *rangeset[T]) insertrange(i int, start, end T) {
+ *s = append(*s, i64range[T]{})
+ copy((*s)[i+1:], (*s)[i:])
+ (*s)[i] = i64range[T]{start, end}
+}