// Copyright 2025 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // The go-ethereum library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . package common import ( "io" "iter" "github.com/ethereum/go-ethereum/rlp" ) // Range represents a range of integers. type Range[T uint32 | uint64] struct { first, afterLast T } // NewRange creates a new range based of first element and number of elements. func NewRange[T uint32 | uint64](first, count T) Range[T] { return Range[T]{first, first + count} } // EncodeRLP implements rlp.Encoder. func (r *Range[T]) EncodeRLP(w io.Writer) error { if err := rlp.Encode(w, &r.first); err != nil { return err } return rlp.Encode(w, &r.afterLast) } // DecodeRLP implements rlp.Decoder. func (r *Range[T]) DecodeRLP(s *rlp.Stream) error { if err := s.Decode(&r.first); err != nil { return err } return s.Decode(&r.afterLast) } // First returns the first element of the range. func (r Range[T]) First() T { return r.first } // Last returns the last element of the range. The function panics if the range // is empty. func (r Range[T]) Last() T { if r.first == r.afterLast { panic("last item of zero length range is not allowed") } return r.afterLast - 1 } // AfterLast returns the first element after the range. This allows obtaining // information about the end part of zero length ranges. func (r Range[T]) AfterLast() T { return r.afterLast } // Count returns the number of elements in the range. func (r Range[T]) Count() T { return r.afterLast - r.first } // IsEmpty returns true if the range is empty. func (r Range[T]) IsEmpty() bool { return r.first == r.afterLast } // Includes returns true if the given element is inside the range. func (r Range[T]) Includes(v T) bool { return v >= r.first && v < r.afterLast } // SetFirst updates the first element of the list. func (r *Range[T]) SetFirst(v T) { r.first = v if r.afterLast < r.first { r.afterLast = r.first } } // SetAfterLast updates the end of the range by specifying the first element // after the range. This allows setting zero length ranges. func (r *Range[T]) SetAfterLast(v T) { r.afterLast = v if r.afterLast < r.first { r.first = r.afterLast } } // SetLast updates last element of the range. func (r *Range[T]) SetLast(v T) { r.SetAfterLast(v + 1) } // Intersection returns the intersection of two ranges. func (r Range[T]) Intersection(q Range[T]) Range[T] { i := Range[T]{first: max(r.first, q.first), afterLast: min(r.afterLast, q.afterLast)} if i.first > i.afterLast { return Range[T]{} } return i } // Union returns the union of two ranges. The function panics if there is a gap // between the ranges. func (r Range[T]) Union(q Range[T]) Range[T] { if max(r.first, q.first) > min(r.afterLast, q.afterLast) { panic("cannot create union; gap between ranges") } return Range[T]{first: min(r.first, q.first), afterLast: max(r.afterLast, q.afterLast)} } // Iter iterates all integers in the range. func (r Range[T]) Iter() iter.Seq[T] { return func(yield func(T) bool) { for i := r.first; i < r.afterLast; i++ { if !yield(i) { break } } } }