mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2026-04-23 00:27:17 +08:00
104 lines
2.1 KiB
Go
104 lines
2.1 KiB
Go
package utils
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"golang.org/x/exp/constraints"
|
|
)
|
|
|
|
type Range[T constraints.Ordered] struct {
|
|
start T
|
|
end T
|
|
}
|
|
|
|
func NewRange[T constraints.Ordered](start, end T) Range[T] {
|
|
if start > end {
|
|
return Range[T]{
|
|
start: end,
|
|
end: start,
|
|
}
|
|
}
|
|
|
|
return Range[T]{
|
|
start: start,
|
|
end: end,
|
|
}
|
|
}
|
|
|
|
func (r Range[T]) Contains(t T) bool {
|
|
return t >= r.start && t <= r.end
|
|
}
|
|
|
|
func (r Range[T]) LeftContains(t T) bool {
|
|
return t >= r.start && t < r.end
|
|
}
|
|
|
|
func (r Range[T]) RightContains(t T) bool {
|
|
return t > r.start && t <= r.end
|
|
}
|
|
|
|
func (r Range[T]) Start() T {
|
|
return r.start
|
|
}
|
|
|
|
func (r Range[T]) End() T {
|
|
return r.end
|
|
}
|
|
|
|
func (r Range[T]) String() string {
|
|
if r.start == r.end {
|
|
return fmt.Sprintf("%v", r.start)
|
|
}
|
|
return fmt.Sprintf("%v-%v", r.start, r.end)
|
|
}
|
|
|
|
func NewUnsignedRange[T constraints.Unsigned](expected string) (Range[T], error) {
|
|
return newIntRange(expected, parseUnsigned[T])
|
|
}
|
|
|
|
func NewSignedRange[T constraints.Signed](expected string) (Range[T], error) {
|
|
return newIntRange(expected, parseSigned[T])
|
|
}
|
|
|
|
func newIntRange[T constraints.Integer](s string, parseFn func(string) (T, error)) (Range[T], error) {
|
|
s = strings.TrimSpace(s)
|
|
if len(s) == 0 {
|
|
return NewRange[T](0, 0), nil
|
|
}
|
|
status := strings.Split(s, "-")
|
|
start, err := parseFn(strings.Trim(status[0], "[ ]"))
|
|
if err != nil {
|
|
return Range[T]{}, fmt.Errorf("invalid range: %s", s)
|
|
}
|
|
switch len(status) {
|
|
case 1: // Port range
|
|
return NewRange(start, start), nil
|
|
case 2: // Single port
|
|
end, err := parseFn(strings.Trim(status[1], "[ ]"))
|
|
if err != nil {
|
|
return Range[T]{}, fmt.Errorf("invalid range: %s", s)
|
|
}
|
|
return NewRange(start, end), nil
|
|
default:
|
|
return Range[T]{}, fmt.Errorf("invalid range: %s", s)
|
|
}
|
|
}
|
|
|
|
func parseUnsigned[T constraints.Unsigned](s string) (T, error) {
|
|
if val, err := strconv.ParseUint(s, 10, 64); err == nil {
|
|
return T(val), nil
|
|
} else {
|
|
return 0, err
|
|
}
|
|
}
|
|
|
|
func parseSigned[T constraints.Signed](s string) (T, error) {
|
|
if val, err := strconv.ParseInt(s, 10, 64); err == nil {
|
|
return T(val), nil
|
|
} else {
|
|
return 0, err
|
|
}
|
|
}
|