Feat: set light and group effect (disable/enable colorloop)
This commit is contained in:
parent
f525b859ed
commit
edfa970e26
4
go.mod
4
go.mod
|
@ -17,9 +17,9 @@ require (
|
|||
github.com/muesli/termenv v0.12.0
|
||||
github.com/rs/zerolog v1.27.0
|
||||
github.com/spf13/viper v1.12.0
|
||||
go4.org/netipx v0.0.0-20230125063823-8449b0a6169f
|
||||
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d
|
||||
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b
|
||||
inet.af/netaddr v0.0.0-20220811202034-502d2d690317
|
||||
)
|
||||
|
||||
require (
|
||||
|
@ -50,8 +50,6 @@ require (
|
|||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/subosito/gotenv v1.3.0 // indirect
|
||||
go4.org/intern v0.0.0-20211027215823-ae77deb06f29 // indirect
|
||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 // indirect
|
||||
golang.org/x/exp v0.0.0-20200228211341-fcea875c7e85 // indirect
|
||||
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
|
|
10
go.sum
10
go.sum
|
@ -96,7 +96,6 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
|
|||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/dhamith93/systats v0.2.0 h1:NG6AJTRU6I5ELFPt7/W5Anv53Nv94zhhBwX3AcOmgQg=
|
||||
github.com/dhamith93/systats v0.2.0/go.mod h1:NBgEXSlRZa45urXVKwl9Wp0cfOHKgWNT/dIMWS2pu8M=
|
||||
github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
|
@ -409,11 +408,8 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/
|
|||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
go4.org/intern v0.0.0-20211027215823-ae77deb06f29 h1:UXLjNohABv4S58tHmeuIZDO6e3mHpW2Dx33gaNt03LE=
|
||||
go4.org/intern v0.0.0-20211027215823-ae77deb06f29/go.mod h1:cS2ma+47FKrLPdXFpr7CuxiTW3eyJbWew4qx0qtQWDA=
|
||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20211027215541-db492cf91b37/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E=
|
||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 h1:FyBZqvoA/jbNzuAWLQE2kG820zMAkcilx6BMjGbL/E4=
|
||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E=
|
||||
go4.org/netipx v0.0.0-20230125063823-8449b0a6169f h1:ketMxHg+vWm3yccyYiq+uK8D3fRmna2Fcj+awpQp84s=
|
||||
go4.org/netipx v0.0.0-20230125063823-8449b0a6169f/go.mod h1:tgPU4N2u9RByaTN3NC2p9xOzyFpte4jYwsIIRF7XlSc=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
|
@ -799,8 +795,6 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
|||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
inet.af/netaddr v0.0.0-20220811202034-502d2d690317 h1:U2fwK6P2EqmopP/hFLTOAjWTki0qgd4GMJn5X8wOleU=
|
||||
inet.af/netaddr v0.0.0-20220811202034-502d2d690317/go.mod h1:OIezDfdzOgFhuw4HuWapWq2e9l0H9tK4F1j+ETRtF3k=
|
||||
nullprogram.com/x/rng v1.1.0 h1:SMU7DHaQSWtKJNTpNFIFt8Wd/KSmOuSDPXrMFp/UMro=
|
||||
nullprogram.com/x/rng v1.1.0/go.mod h1:glGw6V87vyfawxCzqOABL3WfL95G65az9Z2JZCylCkg=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
|
|
|
@ -24,6 +24,7 @@ type cmdTarget interface {
|
|||
SetState(huego.State) error
|
||||
Alert(string) error
|
||||
Scene(string) error
|
||||
Effect(string) error
|
||||
}
|
||||
|
||||
func cmdSet(bridge *ziggy.Bridge, args []string) error {
|
||||
|
@ -170,6 +171,19 @@ func cmdSet(bridge *ziggy.Bridge, args []string) error {
|
|||
}
|
||||
return err
|
||||
})
|
||||
case "effect", "e":
|
||||
if len(args) == argHead-1 {
|
||||
return errors.New("not enough arguments")
|
||||
}
|
||||
argHead++
|
||||
newEffect := strings.TrimSpace(args[argHead])
|
||||
actions = append(actions, func() error {
|
||||
err := target.Effect(newEffect)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to set effect: %w", err)
|
||||
}
|
||||
return err
|
||||
})
|
||||
case "temperature", "temp":
|
||||
if len(args) == argHead-1 {
|
||||
return errors.New("not enough arguments")
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
@ -13,9 +14,7 @@ import (
|
|||
|
||||
"github.com/amimof/huego"
|
||||
tui "github.com/manifoldco/promptui"
|
||||
"inet.af/netaddr"
|
||||
|
||||
"git.tcp.direct/kayos/common/network"
|
||||
"go4.org/netipx"
|
||||
|
||||
"git.tcp.direct/kayos/ziggs/internal/common"
|
||||
)
|
||||
|
@ -52,7 +51,7 @@ addrIter:
|
|||
return candidates
|
||||
}
|
||||
|
||||
func enumerateBridge(a net.Addr, ctx context.Context) interface{} {
|
||||
func enumerateBridge(a netip.Addr, ctx context.Context) interface{} {
|
||||
var err error
|
||||
if _, err = net.DialTimeout("tcp", a.String()+":80", 2*time.Second); err != nil {
|
||||
select {
|
||||
|
@ -112,8 +111,8 @@ func checkAddrs(ctx context.Context, addrs []net.Addr, working *int32, resChan c
|
|||
log.Trace().Msg("checking addresses")
|
||||
for _, a := range addrs {
|
||||
log.Trace().Msgf("checking %s", a.String())
|
||||
ips := network.IterateNetRange(netaddr.MustParseIPPrefix(a.String()))
|
||||
for ipa := range ips {
|
||||
rng := netipx.MustParseIPRange(a.String())
|
||||
for ipa := rng.From(); ipa != rng.To(); ipa = ipa.Next() {
|
||||
init.Do(func() { resChan <- &huego.Bridge{} })
|
||||
ctxLoop:
|
||||
for {
|
||||
|
@ -130,8 +129,8 @@ func checkAddrs(ctx context.Context, addrs []net.Addr, working *int32, resChan c
|
|||
}
|
||||
log.Trace().Msgf("checking %s", ipa.String())
|
||||
atomic.AddInt32(working, 1)
|
||||
go func(ip netaddr.IP) {
|
||||
resChan <- enumerateBridge(ip.IPAddr(), ctx)
|
||||
go func(ip netip.Addr) {
|
||||
resChan <- enumerateBridge(ip, ctx)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
atomic.AddInt32(working, -1)
|
||||
}(ipa)
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
package network
|
||||
|
||||
import ipa "inet.af/netaddr"
|
||||
|
||||
/*
|
||||
IterateNetRange will ingest:
|
||||
|
||||
- an inet.af/netaddr.Range
|
||||
|
||||
- an inet.af/netaddr.Prefix
|
||||
|
||||
- or a string to be parsed as either of the above options
|
||||
|
||||
- valid subnet string example: 192.168.69.0/24
|
||||
|
||||
- valid range string example: 192.168.69.0-192.168.69.254
|
||||
|
||||
it then returns a channel that will stream all the individual netaddr.IP types within the given range or prefix.
|
||||
if the input is invalid this function will return nil.
|
||||
*/
|
||||
func IterateNetRange(ips interface{}) chan ipa.IP {
|
||||
var addrs ipa.IPRange
|
||||
|
||||
switch ips.(type) {
|
||||
case string:
|
||||
strefix, prefixErr := ipa.ParseIPPrefix(ips.(string))
|
||||
strange, rangeErr := ipa.ParseIPRange(ips.(string))
|
||||
switch {
|
||||
case rangeErr == nil:
|
||||
addrs = strange
|
||||
case prefixErr == nil:
|
||||
addrs = strefix.Range()
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
case ipa.IPRange:
|
||||
addrs = ips.(ipa.IPRange)
|
||||
case ipa.IPPrefix:
|
||||
addrs = ips.(ipa.IPPrefix).Range()
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
ch := make(chan ipa.IP, 254)
|
||||
go func(ret chan ipa.IP) {
|
||||
for head := addrs.From(); head != addrs.To(); head = head.Next() {
|
||||
if !head.IsUnspecified() {
|
||||
ret <- head
|
||||
}
|
||||
}
|
||||
close(ret)
|
||||
}(ch)
|
||||
return ch
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2020, Brad Fitzpatrick
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,4 +0,0 @@
|
|||
# go4.org/intern
|
||||
|
||||
See https://godoc.org/go4.org/intern
|
||||
|
|
@ -1,183 +0,0 @@
|
|||
// Copyright 2020 Brad Fitzpatrick. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package intern lets you make smaller comparable values by boxing
|
||||
// a larger comparable value (such as a 16 byte string header) down
|
||||
// into a globally unique 8 byte pointer.
|
||||
//
|
||||
// The globally unique pointers are garbage collected with weak
|
||||
// references and finalizers. This package hides that.
|
||||
//
|
||||
// The GitHub repo is https://github.com/go4org/intern
|
||||
package intern // import "go4.org/intern"
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
_ "go4.org/unsafe/assume-no-moving-gc"
|
||||
)
|
||||
|
||||
// A Value pointer is the handle to an underlying comparable value.
|
||||
// See func Get for how Value pointers may be used.
|
||||
type Value struct {
|
||||
_ [0]func() // prevent people from accidentally using value type as comparable
|
||||
cmpVal interface{}
|
||||
// resurrected is guarded by mu (for all instances of Value).
|
||||
// It is set true whenever v is synthesized from a uintptr.
|
||||
resurrected bool
|
||||
}
|
||||
|
||||
// Get returns the comparable value passed to the Get func
|
||||
// that returned v.
|
||||
func (v *Value) Get() interface{} { return v.cmpVal }
|
||||
|
||||
// key is a key in our global value map.
|
||||
// It contains type-specialized fields to avoid allocations
|
||||
// when converting common types to empty interfaces.
|
||||
type key struct {
|
||||
s string
|
||||
cmpVal interface{}
|
||||
// isString reports whether key contains a string.
|
||||
// Without it, the zero value of key is ambiguous.
|
||||
isString bool
|
||||
}
|
||||
|
||||
// keyFor returns a key to use with cmpVal.
|
||||
func keyFor(cmpVal interface{}) key {
|
||||
if s, ok := cmpVal.(string); ok {
|
||||
return key{s: s, isString: true}
|
||||
}
|
||||
return key{cmpVal: cmpVal}
|
||||
}
|
||||
|
||||
// Value returns a *Value built from k.
|
||||
func (k key) Value() *Value {
|
||||
if k.isString {
|
||||
return &Value{cmpVal: k.s}
|
||||
}
|
||||
return &Value{cmpVal: k.cmpVal}
|
||||
}
|
||||
|
||||
var (
|
||||
// mu guards valMap, a weakref map of *Value by underlying value.
|
||||
// It also guards the resurrected field of all *Values.
|
||||
mu sync.Mutex
|
||||
valMap = map[key]uintptr{} // to uintptr(*Value)
|
||||
valSafe = safeMap() // non-nil in safe+leaky mode
|
||||
)
|
||||
|
||||
// safeMap returns a non-nil map if we're in safe-but-leaky mode,
|
||||
// as controlled by GO4_INTERN_SAFE_BUT_LEAKY.
|
||||
func safeMap() map[key]*Value {
|
||||
if v, _ := strconv.ParseBool(os.Getenv("GO4_INTERN_SAFE_BUT_LEAKY")); v {
|
||||
return map[key]*Value{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get returns a pointer representing the comparable value cmpVal.
|
||||
//
|
||||
// The returned pointer will be the same for Get(v) and Get(v2)
|
||||
// if and only if v == v2, and can be used as a map key.
|
||||
func Get(cmpVal interface{}) *Value {
|
||||
return get(keyFor(cmpVal))
|
||||
}
|
||||
|
||||
// GetByString is identical to Get, except that it is specialized for strings.
|
||||
// This avoids an allocation from putting a string into an interface{}
|
||||
// to pass as an argument to Get.
|
||||
func GetByString(s string) *Value {
|
||||
return get(key{s: s, isString: true})
|
||||
}
|
||||
|
||||
// We play unsafe games that violate Go's rules (and assume a non-moving
|
||||
// collector). So we quiet Go here.
|
||||
// See the comment below Get for more implementation details.
|
||||
//go:nocheckptr
|
||||
func get(k key) *Value {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
var v *Value
|
||||
if valSafe != nil {
|
||||
v = valSafe[k]
|
||||
} else if addr, ok := valMap[k]; ok {
|
||||
v = (*Value)((unsafe.Pointer)(addr))
|
||||
v.resurrected = true
|
||||
}
|
||||
if v != nil {
|
||||
return v
|
||||
}
|
||||
v = k.Value()
|
||||
if valSafe != nil {
|
||||
valSafe[k] = v
|
||||
} else {
|
||||
// SetFinalizer before uintptr conversion (theoretical concern;
|
||||
// see https://github.com/go4org/intern/issues/13)
|
||||
runtime.SetFinalizer(v, finalize)
|
||||
valMap[k] = uintptr(unsafe.Pointer(v))
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func finalize(v *Value) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
if v.resurrected {
|
||||
// We lost the race. Somebody resurrected it while we
|
||||
// were about to finalize it. Try again next round.
|
||||
v.resurrected = false
|
||||
runtime.SetFinalizer(v, finalize)
|
||||
return
|
||||
}
|
||||
delete(valMap, keyFor(v.cmpVal))
|
||||
}
|
||||
|
||||
// Interning is simple if you don't require that unused values be
|
||||
// garbage collectable. But we do require that; we don't want to be
|
||||
// DOS vector. We do this by using a uintptr to hide the pointer from
|
||||
// the garbage collector, and using a finalizer to eliminate the
|
||||
// pointer when no other code is using it.
|
||||
//
|
||||
// The obvious implementation of this is to use a
|
||||
// map[interface{}]uintptr-of-*interface{}, and set up a finalizer to
|
||||
// delete from the map. Unfortunately, this is racy. Because pointers
|
||||
// are being created in violation of Go's unsafety rules, it's
|
||||
// possible to create a pointer to a value concurrently with the GC
|
||||
// concluding that the value can be collected. There are other races
|
||||
// that break the equality invariant as well, but the use-after-free
|
||||
// will cause a runtime crash.
|
||||
//
|
||||
// To make this work, the finalizer needs to know that no references
|
||||
// have been unsafely created since the finalizer was set up. To do
|
||||
// this, values carry a "resurrected" sentinel, which gets set
|
||||
// whenever a pointer is unsafely created. If the finalizer encounters
|
||||
// the sentinel, it clears the sentinel and delays collection for one
|
||||
// additional GC cycle, by re-installing itself as finalizer. This
|
||||
// ensures that the unsafely created pointer is visible to the GC, and
|
||||
// will correctly prevent collection.
|
||||
//
|
||||
// This technique does mean that interned values that get reused take
|
||||
// at least 3 GC cycles to fully collect (1 to clear the sentinel, 1
|
||||
// to clean up the unsafe map, 1 to be actually deleted).
|
||||
//
|
||||
// @ianlancetaylor commented in
|
||||
// https://github.com/golang/go/issues/41303#issuecomment-717401656
|
||||
// that it is possible to implement weak references in terms of
|
||||
// finalizers without unsafe. Unfortunately, the approach he outlined
|
||||
// does not work here, for two reasons. First, there is no way to
|
||||
// construct a strong pointer out of a weak pointer; our map stores
|
||||
// weak pointers, but we must return strong pointers to callers.
|
||||
// Second, and more fundamentally, we must return not just _a_ strong
|
||||
// pointer to callers, but _the same_ strong pointer to callers. In
|
||||
// order to return _the same_ strong pointer to callers, we must track
|
||||
// it, which is exactly what we cannot do with strong pointers.
|
||||
//
|
||||
// See https://github.com/inetaf/netaddr/issues/53 for more
|
||||
// discussion, and https://github.com/go4org/intern/issues/2 for an
|
||||
// illustration of the subtleties at play.
|
|
@ -1,29 +0,0 @@
|
|||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2020, Brad Fitzpatrick
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,13 +0,0 @@
|
|||
# go4.org/unsafe/assume-no-moving-gc
|
||||
|
||||
If your Go package wants to declare that it plays `unsafe` games that only
|
||||
work if the Go runtime's garbage collector is not a moving collector, then add:
|
||||
|
||||
```go
|
||||
import _ "go4.org/unsafe/assume-no-moving-gc"
|
||||
```
|
||||
|
||||
Then your program will explode if that's no longer the case. (Users can override
|
||||
the explosion with a scary sounding environment variable.)
|
||||
|
||||
This also gives us a way to find all the really gross unsafe packages.
|
|
@ -1,22 +0,0 @@
|
|||
// Copyright 2020 Brad Fitzpatrick. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package go4.org/unsafe/assume-no-moving-gc exists so you can depend
|
||||
// on it from unsafe code that wants to declare that it assumes that
|
||||
// the Go runtime does not using a moving garbage colllector.
|
||||
//
|
||||
// This package is then updated for new Go versions when that
|
||||
// is still the case and explodes at runtime with a failure
|
||||
// otherwise, unless an environment variable overrides it.
|
||||
//
|
||||
// To use:
|
||||
//
|
||||
// import _ "go4.org/unsafe/assume-no-moving-gc"
|
||||
//
|
||||
// There is no API.
|
||||
//
|
||||
// The GitHub repo is at https://github.com/go4org/unsafe-assume-no-moving-gc
|
||||
package assume_no_moving_gc
|
||||
|
||||
const env = "ASSUME_NO_MOVING_GC_UNSAFE_RISK_IT_WITH"
|
|
@ -1,26 +0,0 @@
|
|||
// Copyright 2020 Brad Fitzpatrick. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build go1.20
|
||||
// +build go1.20
|
||||
|
||||
package assume_no_moving_gc
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func init() {
|
||||
dots := strings.SplitN(runtime.Version(), ".", 3)
|
||||
v := runtime.Version()
|
||||
if len(dots) >= 2 {
|
||||
v = dots[0] + "." + dots[1]
|
||||
}
|
||||
if os.Getenv(env) == v {
|
||||
return
|
||||
}
|
||||
panic("Something in this program imports go4.org/unsafe/assume-no-moving-gc to declare that it assumes a non-moving garbage collector, but your version of go4.org/unsafe/assume-no-moving-gc hasn't been updated to assert that it's safe against the " + v + " runtime. If you want to risk it, run with environment variable " + env + "=" + v + " set. Notably, if " + v + " adds a moving garbage collector, this program is unsafe to use.")
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
crashers
|
||||
suppressions
|
||||
netaddr-fuzz.zip
|
|
@ -1,3 +0,0 @@
|
|||
[submodule "corpus"]
|
||||
path = corpus
|
||||
url = https://github.com/inetaf/netaddr-corpus.git
|
|
@ -1,4 +0,0 @@
|
|||
Alex Willmer <alex@moreati.org.uk>
|
||||
Matt Layher <mdlayher@gmail.com>
|
||||
Tailscale Inc.
|
||||
Tobias Klauser <tklauser@distanz.ch>
|
|
@ -1,27 +0,0 @@
|
|||
Copyright (c) 2020 The Inet.af AUTHORS. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Tailscale Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,46 +0,0 @@
|
|||
# netaddr [![Test Status](https://github.com/inetaf/netaddr/workflows/Linux/badge.svg)](https://github.com/inetaf/netaddr/actions) [![Go Reference](https://pkg.go.dev/badge/inet.af/netaddr.svg)](https://pkg.go.dev/inet.af/netaddr)
|
||||
|
||||
## Deprecated
|
||||
|
||||
Please see https://pkg.go.dev/go4.org/netipx and the standard library's
|
||||
[`net/netip`](https://pkg.go.dev/net/netip).
|
||||
|
||||
## What
|
||||
|
||||
This is a package containing a new IP address type for Go.
|
||||
|
||||
See its docs: https://pkg.go.dev/inet.af/netaddr
|
||||
|
||||
## Status
|
||||
|
||||
This package is mature, optimized, and used heavily in production at [Tailscale](https://tailscale.com).
|
||||
However, API stability is not yet guaranteed.
|
||||
|
||||
netaddr is intended to be a core, low-level package.
|
||||
We take code review, testing, dependencies, and performance seriously, similar to Go's standard library or the golang.org/x repos.
|
||||
|
||||
## Motivation
|
||||
|
||||
See https://tailscale.com/blog/netaddr-new-ip-type-for-go/ for a long
|
||||
blog post about why we made a new IP address package.
|
||||
|
||||
Other links:
|
||||
|
||||
* https://github.com/golang/go/issues/18804 ("net: reconsider representation of IP")
|
||||
* https://github.com/golang/go/issues/18757 ("net: ParseIP should return an error, like other Parse functions")
|
||||
* https://github.com/golang/go/issues/37921 ("net: Unable to reliably distinguish IPv4-mapped-IPv6 addresses from regular IPv4 addresses")
|
||||
* merges net.IPAddr and net.IP (which the Go net package is a little torn between for legacy reasons)
|
||||
|
||||
## Testing
|
||||
|
||||
In addition to regular Go tests, netaddr uses fuzzing.
|
||||
The corpus is stored separately, in a submodule,
|
||||
to minimize the impact on everyone else.
|
||||
|
||||
To use:
|
||||
|
||||
```
|
||||
$ git submodule update --init
|
||||
$ go get -u github.com/dvyukov/go-fuzz/go-fuzz github.com/dvyukov/go-fuzz/go-fuzz-build
|
||||
$ go-fuzz-build && go-fuzz
|
||||
```
|
|
@ -1,203 +0,0 @@
|
|||
// Copyright 2020 The Inet.Af AUTHORS. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gofuzz
|
||||
// +build gofuzz
|
||||
|
||||
package netaddr
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding"
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Fuzz(b []byte) int {
|
||||
s := string(b)
|
||||
|
||||
ip, _ := ParseIP(s)
|
||||
checkStringParseRoundTrip(ip, parseIP)
|
||||
checkEncoding(ip)
|
||||
|
||||
// Check that we match the standard library's IP parser, modulo zones.
|
||||
if !strings.Contains(s, "%") {
|
||||
stdip := net.ParseIP(s)
|
||||
if ip.IsZero() != (stdip == nil) {
|
||||
fmt.Println("stdip=", stdip, "ip=", ip)
|
||||
panic("net.ParseIP nil != ParseIP zero")
|
||||
} else if !ip.IsZero() && !ip.Is4in6() && ip.String() != stdip.String() {
|
||||
fmt.Println("ip=", ip, "stdip=", stdip)
|
||||
panic("net.IP.String() != IP.String()")
|
||||
}
|
||||
}
|
||||
// Check that .Next().Prior() and .Prior().Next() preserve the IP.
|
||||
if !ip.IsZero() && !ip.Next().IsZero() && ip.Next().Prior() != ip {
|
||||
fmt.Println("ip=", ip, ".next=", ip.Next(), ".next.prior=", ip.Next().Prior())
|
||||
panic(".Next.Prior did not round trip")
|
||||
}
|
||||
if !ip.IsZero() && !ip.Prior().IsZero() && ip.Prior().Next() != ip {
|
||||
fmt.Println("ip=", ip, ".prior=", ip.Prior(), ".prior.next=", ip.Prior().Next())
|
||||
panic(".Prior.Next did not round trip")
|
||||
}
|
||||
|
||||
port, err := ParseIPPort(s)
|
||||
if err == nil {
|
||||
checkStringParseRoundTrip(port, parseIPPort)
|
||||
checkEncoding(port)
|
||||
}
|
||||
port = IPPortFrom(ip, 80)
|
||||
checkStringParseRoundTrip(port, parseIPPort)
|
||||
checkEncoding(port)
|
||||
|
||||
ipp, err := ParseIPPrefix(s)
|
||||
if err == nil {
|
||||
checkStringParseRoundTrip(ipp, parseIPPrefix)
|
||||
checkEncoding(ipp)
|
||||
}
|
||||
ipp = IPPrefixFrom(ip, 8)
|
||||
checkStringParseRoundTrip(ipp, parseIPPrefix)
|
||||
checkEncoding(ipp)
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// Hopefully some of these generic helpers will eventually make their way to the standard library.
|
||||
// See https://github.com/golang/go/issues/46268.
|
||||
|
||||
// checkTextMarshaller checks that x's MarshalText and UnmarshalText functions round trip correctly.
|
||||
func checkTextMarshaller(x encoding.TextMarshaler) {
|
||||
buf, err := x.MarshalText()
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
y := reflect.New(reflect.TypeOf(x)).Interface().(encoding.TextUnmarshaler)
|
||||
err = y.UnmarshalText(buf)
|
||||
if err != nil {
|
||||
fmt.Printf("(%v).MarshalText() = %q\n", x, buf)
|
||||
panic(fmt.Sprintf("(%T).UnmarshalText(%q) = %v", y, buf, err))
|
||||
}
|
||||
if !reflect.DeepEqual(x, y) {
|
||||
fmt.Printf("(%v).MarshalText() = %q\n", x, buf)
|
||||
fmt.Printf("(%T).UnmarshalText(%q) = %v", y, buf, y)
|
||||
panic(fmt.Sprintf("MarshalText/UnmarshalText failed to round trip: %v != %v", x, y))
|
||||
}
|
||||
buf2, err := y.(encoding.TextMarshaler).MarshalText()
|
||||
if err != nil {
|
||||
fmt.Printf("(%v).MarshalText() = %q\n", x, buf)
|
||||
fmt.Printf("(%T).UnmarshalText(%q) = %v", y, buf, y)
|
||||
panic(fmt.Sprintf("failed to MarshalText a second time: %v", err))
|
||||
}
|
||||
if !bytes.Equal(buf, buf2) {
|
||||
fmt.Printf("(%v).MarshalText() = %q\n", x, buf)
|
||||
fmt.Printf("(%T).UnmarshalText(%q) = %v", y, buf, y)
|
||||
fmt.Printf("(%v).MarshalText() = %q\n", y, buf2)
|
||||
panic(fmt.Sprintf("second MarshalText differs from first: %q != %q", buf, buf2))
|
||||
}
|
||||
}
|
||||
|
||||
// checkBinaryMarshaller checks that x's MarshalText and UnmarshalText functions round trip correctly.
|
||||
func checkBinaryMarshaller(x encoding.BinaryMarshaler) {
|
||||
buf, err := x.MarshalBinary()
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
y := reflect.New(reflect.TypeOf(x)).Interface().(encoding.BinaryUnmarshaler)
|
||||
err = y.UnmarshalBinary(buf)
|
||||
if err != nil {
|
||||
fmt.Printf("(%v).MarshalBinary() = %q\n", x, buf)
|
||||
panic(fmt.Sprintf("(%T).UnmarshalBinary(%q) = %v", y, buf, err))
|
||||
}
|
||||
if !reflect.DeepEqual(x, y) {
|
||||
fmt.Printf("(%v).MarshalBinary() = %q\n", x, buf)
|
||||
fmt.Printf("(%T).UnmarshalBinary(%q) = %v", y, buf, y)
|
||||
panic(fmt.Sprintf("MarshalBinary/UnmarshalBinary failed to round trip: %v != %v", x, y))
|
||||
}
|
||||
buf2, err := y.(encoding.BinaryMarshaler).MarshalBinary()
|
||||
if err != nil {
|
||||
fmt.Printf("(%v).MarshalBinary() = %q\n", x, buf)
|
||||
fmt.Printf("(%T).UnmarshalBinary(%q) = %v", y, buf, y)
|
||||
panic(fmt.Sprintf("failed to MarshalBinary a second time: %v", err))
|
||||
}
|
||||
if !bytes.Equal(buf, buf2) {
|
||||
fmt.Printf("(%v).MarshalBinary() = %q\n", x, buf)
|
||||
fmt.Printf("(%T).UnmarshalBinary(%q) = %v", y, buf, y)
|
||||
fmt.Printf("(%v).MarshalBinary() = %q\n", y, buf2)
|
||||
panic(fmt.Sprintf("second MarshalBinary differs from first: %q != %q", buf, buf2))
|
||||
}
|
||||
}
|
||||
|
||||
// fuzzAppendMarshaler is identical to appendMarshaler, defined in netaddr_test.go.
|
||||
// We have two because the two go-fuzz implementations differ
|
||||
// in whether they include _test.go files when typechecking.
|
||||
// We need this fuzz file to compile with and without netaddr_test.go,
|
||||
// which means defining the interface twice.
|
||||
type fuzzAppendMarshaler interface {
|
||||
encoding.TextMarshaler
|
||||
AppendTo([]byte) []byte
|
||||
}
|
||||
|
||||
// checkTextMarshalMatchesAppendTo checks that x's MarshalText matches x's AppendTo.
|
||||
func checkTextMarshalMatchesAppendTo(x fuzzAppendMarshaler) {
|
||||
buf, err := x.MarshalText()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf2 := make([]byte, 0, len(buf))
|
||||
buf2 = x.AppendTo(buf2)
|
||||
if !bytes.Equal(buf, buf2) {
|
||||
panic(fmt.Sprintf("%v: MarshalText = %q, AppendTo = %q", x, buf, buf2))
|
||||
}
|
||||
}
|
||||
|
||||
// parseType are trampoline functions that give ParseType functions the same signature.
|
||||
// This would be nicer with generics.
|
||||
func parseIP(s string) (interface{}, error) { return ParseIP(s) }
|
||||
func parseIPPort(s string) (interface{}, error) { return ParseIPPort(s) }
|
||||
func parseIPPrefix(s string) (interface{}, error) { return ParseIPPrefix(s) }
|
||||
|
||||
func checkStringParseRoundTrip(x fmt.Stringer, parse func(string) (interface{}, error)) {
|
||||
v, vok := x.(interface{ IsValid() bool })
|
||||
if vok && !v.IsValid() {
|
||||
// Ignore invalid values.
|
||||
return
|
||||
}
|
||||
// Zero values tend to print something like "invalid <TYPE>", so it's OK if they don't round trip.
|
||||
// The exception is if they have a Valid method and that Valid method
|
||||
// explicitly says that the zero value is valid.
|
||||
z, zok := x.(interface{ IsZero() bool })
|
||||
if zok && z.IsZero() && !(vok && v.IsValid()) {
|
||||
return
|
||||
}
|
||||
s := x.String()
|
||||
y, err := parse(s)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("s=%q err=%v", s, err))
|
||||
}
|
||||
if !reflect.DeepEqual(x, y) {
|
||||
fmt.Printf("s=%q x=%#v y=%#v\n", s, x, y)
|
||||
panic(fmt.Sprintf("%T round trip identity failure", x))
|
||||
}
|
||||
s2 := y.(fmt.Stringer).String()
|
||||
if s != s2 {
|
||||
fmt.Printf("s=%#v s2=%#v\n", s, s2)
|
||||
panic(fmt.Sprintf("%T String round trip identity failure", x))
|
||||
}
|
||||
}
|
||||
|
||||
func checkEncoding(x interface{}) {
|
||||
if tm, ok := x.(encoding.TextMarshaler); ok {
|
||||
checkTextMarshaller(tm)
|
||||
}
|
||||
if bm, ok := x.(encoding.BinaryMarshaler); ok {
|
||||
checkBinaryMarshaller(bm)
|
||||
}
|
||||
if am, ok := x.(fuzzAppendMarshaler); ok {
|
||||
checkTextMarshalMatchesAppendTo(am)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add helpers that check that String matches MarshalText for non-zero-ish values
|
|
@ -1,497 +0,0 @@
|
|||
// Copyright 2020 The Inet.Af 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 netaddr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// IPSetBuilder builds an immutable IPSet.
|
||||
//
|
||||
// The zero value is a valid value representing a set of no IPs.
|
||||
//
|
||||
// The Add and Remove methods add or remove IPs to/from the set.
|
||||
// Removals only affect the current membership of the set, so in
|
||||
// general Adds should be called first. Input ranges may overlap in
|
||||
// any way.
|
||||
//
|
||||
// Most IPSetBuilder methods do not return errors.
|
||||
// Instead, errors are accumulated and reported by IPSetBuilder.IPSet.
|
||||
type IPSetBuilder struct {
|
||||
// in are the ranges in the set.
|
||||
in []IPRange
|
||||
|
||||
// out are the ranges to be removed from 'in'.
|
||||
out []IPRange
|
||||
|
||||
// errs are errors accumulated during construction.
|
||||
errs multiErr
|
||||
}
|
||||
|
||||
// normalize normalizes s: s.in becomes the minimal sorted list of
|
||||
// ranges required to describe s, and s.out becomes empty.
|
||||
func (s *IPSetBuilder) normalize() {
|
||||
const debug = false
|
||||
if debug {
|
||||
debugf("ranges start in=%v out=%v", s.in, s.out)
|
||||
}
|
||||
in, ok := mergeIPRanges(s.in)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
out, ok := mergeIPRanges(s.out)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if debug {
|
||||
debugf("ranges sort in=%v out=%v", in, out)
|
||||
}
|
||||
|
||||
// in and out are sorted in ascending range order, and have no
|
||||
// overlaps within each other. We can run a merge of the two lists
|
||||
// in one pass.
|
||||
|
||||
min := make([]IPRange, 0, len(in))
|
||||
for len(in) > 0 && len(out) > 0 {
|
||||
rin, rout := in[0], out[0]
|
||||
if debug {
|
||||
debugf("step in=%v out=%v", rin, rout)
|
||||
}
|
||||
|
||||
switch {
|
||||
case !rout.IsValid() || !rin.IsValid():
|
||||
// mergeIPRanges should have prevented invalid ranges from
|
||||
// sneaking in.
|
||||
panic("invalid IPRanges during Ranges merge")
|
||||
case rout.entirelyBefore(rin):
|
||||
// "out" is entirely before "in".
|
||||
//
|
||||
// out in
|
||||
// f-------t f-------t
|
||||
out = out[1:]
|
||||
if debug {
|
||||
debugf("out before in; drop out")
|
||||
}
|
||||
case rin.entirelyBefore(rout):
|
||||
// "in" is entirely before "out".
|
||||
//
|
||||
// in out
|
||||
// f------t f-------t
|
||||
min = append(min, rin)
|
||||
in = in[1:]
|
||||
if debug {
|
||||
debugf("in before out; append in")
|
||||
debugf("min=%v", min)
|
||||
}
|
||||
case rin.coveredBy(rout):
|
||||
// "out" entirely covers "in".
|
||||
//
|
||||
// out
|
||||
// f-------------t
|
||||
// f------t
|
||||
// in
|
||||
in = in[1:]
|
||||
if debug {
|
||||
debugf("in inside out; drop in")
|
||||
}
|
||||
case rout.inMiddleOf(rin):
|
||||
// "in" entirely covers "out".
|
||||
//
|
||||
// in
|
||||
// f-------------t
|
||||
// f------t
|
||||
// out
|
||||
min = append(min, IPRange{from: rin.from, to: rout.from.Prior()})
|
||||
// Adjust in[0], not ir, because we want to consider the
|
||||
// mutated range on the next iteration.
|
||||
in[0].from = rout.to.Next()
|
||||
out = out[1:]
|
||||
if debug {
|
||||
debugf("out inside in; split in, append first in, drop out, adjust second in")
|
||||
debugf("min=%v", min)
|
||||
}
|
||||
case rout.overlapsStartOf(rin):
|
||||
// "out" overlaps start of "in".
|
||||
//
|
||||
// out
|
||||
// f------t
|
||||
// f------t
|
||||
// in
|
||||
in[0].from = rout.to.Next()
|
||||
// Can't move ir onto min yet, another later out might
|
||||
// trim it further. Just discard or and continue.
|
||||
out = out[1:]
|
||||
if debug {
|
||||
debugf("out cuts start of in; adjust in, drop out")
|
||||
}
|
||||
case rout.overlapsEndOf(rin):
|
||||
// "out" overlaps end of "in".
|
||||
//
|
||||
// out
|
||||
// f------t
|
||||
// f------t
|
||||
// in
|
||||
min = append(min, IPRange{from: rin.from, to: rout.from.Prior()})
|
||||
in = in[1:]
|
||||
if debug {
|
||||
debugf("merge out cuts end of in; append shortened in")
|
||||
debugf("min=%v", min)
|
||||
}
|
||||
default:
|
||||
// The above should account for all combinations of in and
|
||||
// out overlapping, but insert a panic to be sure.
|
||||
panic("unexpected additional overlap scenario")
|
||||
}
|
||||
}
|
||||
if len(in) > 0 {
|
||||
// Ran out of removals before the end of in.
|
||||
min = append(min, in...)
|
||||
if debug {
|
||||
debugf("min=%v", min)
|
||||
}
|
||||
}
|
||||
|
||||
s.in = min
|
||||
s.out = nil
|
||||
}
|
||||
|
||||
// Clone returns a copy of s that shares no memory with s.
|
||||
func (s *IPSetBuilder) Clone() *IPSetBuilder {
|
||||
return &IPSetBuilder{
|
||||
in: append([]IPRange(nil), s.in...),
|
||||
out: append([]IPRange(nil), s.out...),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *IPSetBuilder) addError(msg string, args ...interface{}) {
|
||||
se := new(stacktraceErr)
|
||||
// Skip three frames: runtime.Callers, addError, and the IPSetBuilder
|
||||
// method that called addError (such as IPSetBuilder.Add).
|
||||
// The resulting stack trace ends at the line in the user's
|
||||
// code where they called into netaddr.
|
||||
n := runtime.Callers(3, se.pcs[:])
|
||||
se.at = se.pcs[:n]
|
||||
se.err = fmt.Errorf(msg, args...)
|
||||
s.errs = append(s.errs, se)
|
||||
}
|
||||
|
||||
// Add adds ip to s.
|
||||
func (s *IPSetBuilder) Add(ip IP) {
|
||||
if ip.IsZero() {
|
||||
s.addError("Add(IP{})")
|
||||
return
|
||||
}
|
||||
s.AddRange(IPRangeFrom(ip, ip))
|
||||
}
|
||||
|
||||
// AddPrefix adds all IPs in p to s.
|
||||
func (s *IPSetBuilder) AddPrefix(p IPPrefix) {
|
||||
if r := p.Range(); r.IsValid() {
|
||||
s.AddRange(r)
|
||||
} else {
|
||||
s.addError("AddPrefix(%v/%v)", p.IP(), p.Bits())
|
||||
}
|
||||
}
|
||||
|
||||
// AddRange adds r to s.
|
||||
// If r is not Valid, AddRange does nothing.
|
||||
func (s *IPSetBuilder) AddRange(r IPRange) {
|
||||
if !r.IsValid() {
|
||||
s.addError("AddRange(%v-%v)", r.From(), r.To())
|
||||
return
|
||||
}
|
||||
// If there are any removals (s.out), then we need to compact the set
|
||||
// first to get the order right.
|
||||
if len(s.out) > 0 {
|
||||
s.normalize()
|
||||
}
|
||||
s.in = append(s.in, r)
|
||||
}
|
||||
|
||||
// AddSet adds all IPs in b to s.
|
||||
func (s *IPSetBuilder) AddSet(b *IPSet) {
|
||||
if b == nil {
|
||||
return
|
||||
}
|
||||
for _, r := range b.rr {
|
||||
s.AddRange(r)
|
||||
}
|
||||
}
|
||||
|
||||
// Remove removes ip from s.
|
||||
func (s *IPSetBuilder) Remove(ip IP) {
|
||||
if ip.IsZero() {
|
||||
s.addError("Remove(IP{})")
|
||||
} else {
|
||||
s.RemoveRange(IPRangeFrom(ip, ip))
|
||||
}
|
||||
}
|
||||
|
||||
// RemovePrefix removes all IPs in p from s.
|
||||
func (s *IPSetBuilder) RemovePrefix(p IPPrefix) {
|
||||
if r := p.Range(); r.IsValid() {
|
||||
s.RemoveRange(r)
|
||||
} else {
|
||||
s.addError("RemovePrefix(%v/%v)", p.IP(), p.Bits())
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveRange removes all IPs in r from s.
|
||||
func (s *IPSetBuilder) RemoveRange(r IPRange) {
|
||||
if r.IsValid() {
|
||||
s.out = append(s.out, r)
|
||||
} else {
|
||||
s.addError("RemoveRange(%v-%v)", r.From(), r.To())
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveSet removes all IPs in o from s.
|
||||
func (s *IPSetBuilder) RemoveSet(b *IPSet) {
|
||||
if b == nil {
|
||||
return
|
||||
}
|
||||
for _, r := range b.rr {
|
||||
s.RemoveRange(r)
|
||||
}
|
||||
}
|
||||
|
||||
// removeBuilder removes all IPs in b from s.
|
||||
func (s *IPSetBuilder) removeBuilder(b *IPSetBuilder) {
|
||||
b.normalize()
|
||||
for _, r := range b.in {
|
||||
s.RemoveRange(r)
|
||||
}
|
||||
}
|
||||
|
||||
// Complement updates s to contain the complement of its current
|
||||
// contents.
|
||||
func (s *IPSetBuilder) Complement() {
|
||||
s.normalize()
|
||||
s.out = s.in
|
||||
s.in = []IPRange{
|
||||
IPPrefix{ip: IPv4(0, 0, 0, 0), bits: 0}.Range(),
|
||||
IPPrefix{ip: IPv6Unspecified(), bits: 0}.Range(),
|
||||
}
|
||||
}
|
||||
|
||||
// Intersect updates s to the set intersection of s and b.
|
||||
func (s *IPSetBuilder) Intersect(b *IPSet) {
|
||||
var o IPSetBuilder
|
||||
o.Complement()
|
||||
o.RemoveSet(b)
|
||||
s.removeBuilder(&o)
|
||||
}
|
||||
|
||||
func discardf(format string, args ...interface{}) {}
|
||||
|
||||
// debugf is reassigned by tests.
|
||||
var debugf = discardf
|
||||
|
||||
// IPSet returns an immutable IPSet representing the current state of s.
|
||||
//
|
||||
// Most IPSetBuilder methods do not return errors.
|
||||
// Rather, the builder ignores any invalid inputs (such as an invalid IPPrefix),
|
||||
// and accumulates a list of any such errors that it encountered.
|
||||
//
|
||||
// IPSet also reports any such accumulated errors.
|
||||
// Even if the returned error is non-nil, the returned IPSet is usable
|
||||
// and contains all modifications made with valid inputs.
|
||||
//
|
||||
// The builder remains usable after calling IPSet.
|
||||
// Calling IPSet clears any accumulated errors.
|
||||
func (s *IPSetBuilder) IPSet() (*IPSet, error) {
|
||||
s.normalize()
|
||||
ret := &IPSet{
|
||||
rr: append([]IPRange{}, s.in...),
|
||||
}
|
||||
if len(s.errs) == 0 {
|
||||
return ret, nil
|
||||
} else {
|
||||
errs := s.errs
|
||||
s.errs = nil
|
||||
return ret, errs
|
||||
}
|
||||
}
|
||||
|
||||
// IPSet represents a set of IP addresses.
|
||||
//
|
||||
// IPSet is safe for concurrent use.
|
||||
// The zero value is a valid value representing a set of no IPs.
|
||||
// Use IPSetBuilder to construct IPSets.
|
||||
type IPSet struct {
|
||||
// rr is the set of IPs that belong to this IPSet. The IPRanges
|
||||
// are normalized according to IPSetBuilder.normalize, meaning
|
||||
// they are a sorted, minimal representation (no overlapping
|
||||
// ranges, no contiguous ranges). The implementation of various
|
||||
// methods rely on this property.
|
||||
rr []IPRange
|
||||
}
|
||||
|
||||
// Ranges returns the minimum and sorted set of IP
|
||||
// ranges that covers s.
|
||||
func (s *IPSet) Ranges() []IPRange {
|
||||
return append([]IPRange{}, s.rr...)
|
||||
}
|
||||
|
||||
// Prefixes returns the minimum and sorted set of IP prefixes
|
||||
// that covers s.
|
||||
func (s *IPSet) Prefixes() []IPPrefix {
|
||||
out := make([]IPPrefix, 0, len(s.rr))
|
||||
for _, r := range s.rr {
|
||||
out = append(out, r.Prefixes()...)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Equal reports whether s and o represent the same set of IP
|
||||
// addresses.
|
||||
func (s *IPSet) Equal(o *IPSet) bool {
|
||||
if len(s.rr) != len(o.rr) {
|
||||
return false
|
||||
}
|
||||
for i := range s.rr {
|
||||
if s.rr[i] != o.rr[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Contains reports whether ip is in s.
|
||||
// If ip has an IPv6 zone, Contains returns false,
|
||||
// because IPSets do not track zones.
|
||||
func (s *IPSet) Contains(ip IP) bool {
|
||||
if ip.hasZone() {
|
||||
return false
|
||||
}
|
||||
// TODO: data structure permitting more efficient lookups:
|
||||
// https://github.com/inetaf/netaddr/issues/139
|
||||
i := sort.Search(len(s.rr), func(i int) bool {
|
||||
return ip.Less(s.rr[i].from)
|
||||
})
|
||||
if i == 0 {
|
||||
return false
|
||||
}
|
||||
i--
|
||||
return s.rr[i].contains(ip)
|
||||
}
|
||||
|
||||
// ContainsRange reports whether all IPs in r are in s.
|
||||
func (s *IPSet) ContainsRange(r IPRange) bool {
|
||||
for _, x := range s.rr {
|
||||
if r.coveredBy(x) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ContainsPrefix reports whether all IPs in p are in s.
|
||||
func (s *IPSet) ContainsPrefix(p IPPrefix) bool {
|
||||
return s.ContainsRange(p.Range())
|
||||
}
|
||||
|
||||
// Overlaps reports whether any IP in b is also in s.
|
||||
func (s *IPSet) Overlaps(b *IPSet) bool {
|
||||
// TODO: sorted ranges lets us do this in O(n+m)
|
||||
for _, r := range s.rr {
|
||||
for _, or := range b.rr {
|
||||
if r.Overlaps(or) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// OverlapsRange reports whether any IP in r is also in s.
|
||||
func (s *IPSet) OverlapsRange(r IPRange) bool {
|
||||
// TODO: sorted ranges lets us do this more efficiently.
|
||||
for _, x := range s.rr {
|
||||
if x.Overlaps(r) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// OverlapsPrefix reports whether any IP in p is also in s.
|
||||
func (s *IPSet) OverlapsPrefix(p IPPrefix) bool {
|
||||
return s.OverlapsRange(p.Range())
|
||||
}
|
||||
|
||||
// RemoveFreePrefix splits s into a Prefix of length bitLen and a new
|
||||
// IPSet with that prefix removed.
|
||||
//
|
||||
// If no contiguous prefix of length bitLen exists in s,
|
||||
// RemoveFreePrefix returns ok=false.
|
||||
func (s *IPSet) RemoveFreePrefix(bitLen uint8) (p IPPrefix, newSet *IPSet, ok bool) {
|
||||
var bestFit IPPrefix
|
||||
for _, r := range s.rr {
|
||||
for _, prefix := range r.Prefixes() {
|
||||
if prefix.bits > bitLen {
|
||||
continue
|
||||
}
|
||||
if bestFit.ip.IsZero() || prefix.bits > bestFit.bits {
|
||||
bestFit = prefix
|
||||
if bestFit.bits == bitLen {
|
||||
// exact match, done.
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if bestFit.ip.IsZero() {
|
||||
return IPPrefix{}, s, false
|
||||
}
|
||||
|
||||
prefix := IPPrefix{ip: bestFit.ip, bits: bitLen}
|
||||
|
||||
var b IPSetBuilder
|
||||
b.AddSet(s)
|
||||
b.RemovePrefix(prefix)
|
||||
newSet, _ = b.IPSet()
|
||||
return prefix, newSet, true
|
||||
}
|
||||
|
||||
type multiErr []error
|
||||
|
||||
func (e multiErr) Error() string {
|
||||
var ret []string
|
||||
for _, err := range e {
|
||||
ret = append(ret, err.Error())
|
||||
}
|
||||
return strings.Join(ret, "; ")
|
||||
}
|
||||
|
||||
// A stacktraceErr combines an error with a stack trace.
|
||||
type stacktraceErr struct {
|
||||
pcs [16]uintptr // preallocated array of PCs
|
||||
at []uintptr // stack trace whence the error
|
||||
err error // underlying error
|
||||
}
|
||||
|
||||
func (e *stacktraceErr) Error() string {
|
||||
frames := runtime.CallersFrames(e.at)
|
||||
buf := new(strings.Builder)
|
||||
buf.WriteString(e.err.Error())
|
||||
buf.WriteString(" @ ")
|
||||
for {
|
||||
frame, more := frames.Next()
|
||||
if !more {
|
||||
break
|
||||
}
|
||||
fmt.Fprintf(buf, "%s:%d ", frame.File, frame.Line)
|
||||
}
|
||||
return strings.TrimSpace(buf.String())
|
||||
}
|
||||
|
||||
func (e *stacktraceErr) Unwrap() error {
|
||||
return e.err
|
||||
}
|
|
@ -1,141 +0,0 @@
|
|||
// Copyright 2021 The Inet.Af 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 netaddr
|
||||
|
||||
// mask6 are bitmasks with the topmost n bits of a
|
||||
// 128-bit number, where n is the array index.
|
||||
//
|
||||
// generated with https://play.golang.org/p/64XKxaUSa_9
|
||||
var mask6 = [...]uint128{
|
||||
0: {0x0000000000000000, 0x0000000000000000},
|
||||
1: {0x8000000000000000, 0x0000000000000000},
|
||||
2: {0xc000000000000000, 0x0000000000000000},
|
||||
3: {0xe000000000000000, 0x0000000000000000},
|
||||
4: {0xf000000000000000, 0x0000000000000000},
|
||||
5: {0xf800000000000000, 0x0000000000000000},
|
||||
6: {0xfc00000000000000, 0x0000000000000000},
|
||||
7: {0xfe00000000000000, 0x0000000000000000},
|
||||
8: {0xff00000000000000, 0x0000000000000000},
|
||||
9: {0xff80000000000000, 0x0000000000000000},
|
||||
10: {0xffc0000000000000, 0x0000000000000000},
|
||||
11: {0xffe0000000000000, 0x0000000000000000},
|
||||
12: {0xfff0000000000000, 0x0000000000000000},
|
||||
13: {0xfff8000000000000, 0x0000000000000000},
|
||||
14: {0xfffc000000000000, 0x0000000000000000},
|
||||
15: {0xfffe000000000000, 0x0000000000000000},
|
||||
16: {0xffff000000000000, 0x0000000000000000},
|
||||
17: {0xffff800000000000, 0x0000000000000000},
|
||||
18: {0xffffc00000000000, 0x0000000000000000},
|
||||
19: {0xffffe00000000000, 0x0000000000000000},
|
||||
20: {0xfffff00000000000, 0x0000000000000000},
|
||||
21: {0xfffff80000000000, 0x0000000000000000},
|
||||
22: {0xfffffc0000000000, 0x0000000000000000},
|
||||
23: {0xfffffe0000000000, 0x0000000000000000},
|
||||
24: {0xffffff0000000000, 0x0000000000000000},
|
||||
25: {0xffffff8000000000, 0x0000000000000000},
|
||||
26: {0xffffffc000000000, 0x0000000000000000},
|
||||
27: {0xffffffe000000000, 0x0000000000000000},
|
||||
28: {0xfffffff000000000, 0x0000000000000000},
|
||||
29: {0xfffffff800000000, 0x0000000000000000},
|
||||
30: {0xfffffffc00000000, 0x0000000000000000},
|
||||
31: {0xfffffffe00000000, 0x0000000000000000},
|
||||
32: {0xffffffff00000000, 0x0000000000000000},
|
||||
33: {0xffffffff80000000, 0x0000000000000000},
|
||||
34: {0xffffffffc0000000, 0x0000000000000000},
|
||||
35: {0xffffffffe0000000, 0x0000000000000000},
|
||||
36: {0xfffffffff0000000, 0x0000000000000000},
|
||||
37: {0xfffffffff8000000, 0x0000000000000000},
|
||||
38: {0xfffffffffc000000, 0x0000000000000000},
|
||||
39: {0xfffffffffe000000, 0x0000000000000000},
|
||||
40: {0xffffffffff000000, 0x0000000000000000},
|
||||
41: {0xffffffffff800000, 0x0000000000000000},
|
||||
42: {0xffffffffffc00000, 0x0000000000000000},
|
||||
43: {0xffffffffffe00000, 0x0000000000000000},
|
||||
44: {0xfffffffffff00000, 0x0000000000000000},
|
||||
45: {0xfffffffffff80000, 0x0000000000000000},
|
||||
46: {0xfffffffffffc0000, 0x0000000000000000},
|
||||
47: {0xfffffffffffe0000, 0x0000000000000000},
|
||||
48: {0xffffffffffff0000, 0x0000000000000000},
|
||||
49: {0xffffffffffff8000, 0x0000000000000000},
|
||||
50: {0xffffffffffffc000, 0x0000000000000000},
|
||||
51: {0xffffffffffffe000, 0x0000000000000000},
|
||||
52: {0xfffffffffffff000, 0x0000000000000000},
|
||||
53: {0xfffffffffffff800, 0x0000000000000000},
|
||||
54: {0xfffffffffffffc00, 0x0000000000000000},
|
||||
55: {0xfffffffffffffe00, 0x0000000000000000},
|
||||
56: {0xffffffffffffff00, 0x0000000000000000},
|
||||
57: {0xffffffffffffff80, 0x0000000000000000},
|
||||
58: {0xffffffffffffffc0, 0x0000000000000000},
|
||||
59: {0xffffffffffffffe0, 0x0000000000000000},
|
||||
60: {0xfffffffffffffff0, 0x0000000000000000},
|
||||
61: {0xfffffffffffffff8, 0x0000000000000000},
|
||||
62: {0xfffffffffffffffc, 0x0000000000000000},
|
||||
63: {0xfffffffffffffffe, 0x0000000000000000},
|
||||
64: {0xffffffffffffffff, 0x0000000000000000},
|
||||
65: {0xffffffffffffffff, 0x8000000000000000},
|
||||
66: {0xffffffffffffffff, 0xc000000000000000},
|
||||
67: {0xffffffffffffffff, 0xe000000000000000},
|
||||
68: {0xffffffffffffffff, 0xf000000000000000},
|
||||
69: {0xffffffffffffffff, 0xf800000000000000},
|
||||
70: {0xffffffffffffffff, 0xfc00000000000000},
|
||||
71: {0xffffffffffffffff, 0xfe00000000000000},
|
||||
72: {0xffffffffffffffff, 0xff00000000000000},
|
||||
73: {0xffffffffffffffff, 0xff80000000000000},
|
||||
74: {0xffffffffffffffff, 0xffc0000000000000},
|
||||
75: {0xffffffffffffffff, 0xffe0000000000000},
|
||||
76: {0xffffffffffffffff, 0xfff0000000000000},
|
||||
77: {0xffffffffffffffff, 0xfff8000000000000},
|
||||
78: {0xffffffffffffffff, 0xfffc000000000000},
|
||||
79: {0xffffffffffffffff, 0xfffe000000000000},
|
||||
80: {0xffffffffffffffff, 0xffff000000000000},
|
||||
81: {0xffffffffffffffff, 0xffff800000000000},
|
||||
82: {0xffffffffffffffff, 0xffffc00000000000},
|
||||
83: {0xffffffffffffffff, 0xffffe00000000000},
|
||||
84: {0xffffffffffffffff, 0xfffff00000000000},
|
||||
85: {0xffffffffffffffff, 0xfffff80000000000},
|
||||
86: {0xffffffffffffffff, 0xfffffc0000000000},
|
||||
87: {0xffffffffffffffff, 0xfffffe0000000000},
|
||||
88: {0xffffffffffffffff, 0xffffff0000000000},
|
||||
89: {0xffffffffffffffff, 0xffffff8000000000},
|
||||
90: {0xffffffffffffffff, 0xffffffc000000000},
|
||||
91: {0xffffffffffffffff, 0xffffffe000000000},
|
||||
92: {0xffffffffffffffff, 0xfffffff000000000},
|
||||
93: {0xffffffffffffffff, 0xfffffff800000000},
|
||||
94: {0xffffffffffffffff, 0xfffffffc00000000},
|
||||
95: {0xffffffffffffffff, 0xfffffffe00000000},
|
||||
96: {0xffffffffffffffff, 0xffffffff00000000},
|
||||
97: {0xffffffffffffffff, 0xffffffff80000000},
|
||||
98: {0xffffffffffffffff, 0xffffffffc0000000},
|
||||
99: {0xffffffffffffffff, 0xffffffffe0000000},
|
||||
100: {0xffffffffffffffff, 0xfffffffff0000000},
|
||||
101: {0xffffffffffffffff, 0xfffffffff8000000},
|
||||
102: {0xffffffffffffffff, 0xfffffffffc000000},
|
||||
103: {0xffffffffffffffff, 0xfffffffffe000000},
|
||||
104: {0xffffffffffffffff, 0xffffffffff000000},
|
||||
105: {0xffffffffffffffff, 0xffffffffff800000},
|
||||
106: {0xffffffffffffffff, 0xffffffffffc00000},
|
||||
107: {0xffffffffffffffff, 0xffffffffffe00000},
|
||||
108: {0xffffffffffffffff, 0xfffffffffff00000},
|
||||
109: {0xffffffffffffffff, 0xfffffffffff80000},
|
||||
110: {0xffffffffffffffff, 0xfffffffffffc0000},
|
||||
111: {0xffffffffffffffff, 0xfffffffffffe0000},
|
||||
112: {0xffffffffffffffff, 0xffffffffffff0000},
|
||||
113: {0xffffffffffffffff, 0xffffffffffff8000},
|
||||
114: {0xffffffffffffffff, 0xffffffffffffc000},
|
||||
115: {0xffffffffffffffff, 0xffffffffffffe000},
|
||||
116: {0xffffffffffffffff, 0xfffffffffffff000},
|
||||
117: {0xffffffffffffffff, 0xfffffffffffff800},
|
||||
118: {0xffffffffffffffff, 0xfffffffffffffc00},
|
||||
119: {0xffffffffffffffff, 0xfffffffffffffe00},
|
||||
120: {0xffffffffffffffff, 0xffffffffffffff00},
|
||||
121: {0xffffffffffffffff, 0xffffffffffffff80},
|
||||
122: {0xffffffffffffffff, 0xffffffffffffffc0},
|
||||
123: {0xffffffffffffffff, 0xffffffffffffffe0},
|
||||
124: {0xffffffffffffffff, 0xfffffffffffffff0},
|
||||
125: {0xffffffffffffffff, 0xfffffffffffffff8},
|
||||
126: {0xffffffffffffffff, 0xfffffffffffffffc},
|
||||
127: {0xffffffffffffffff, 0xfffffffffffffffe},
|
||||
128: {0xffffffffffffffff, 0xffffffffffffffff},
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,82 +0,0 @@
|
|||
// Copyright 2020 The Inet.Af 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 netaddr
|
||||
|
||||
import "math/bits"
|
||||
|
||||
// uint128 represents a uint128 using two uint64s.
|
||||
//
|
||||
// When the methods below mention a bit number, bit 0 is the most
|
||||
// significant bit (in hi) and bit 127 is the lowest (lo&1).
|
||||
type uint128 struct {
|
||||
hi uint64
|
||||
lo uint64
|
||||
}
|
||||
|
||||
// isZero reports whether u == 0.
|
||||
//
|
||||
// It's faster than u == (uint128{}) because the compiler (as of Go
|
||||
// 1.15/1.16b1) doesn't do this trick and instead inserts a branch in
|
||||
// its eq alg's generated code.
|
||||
func (u uint128) isZero() bool { return u.hi|u.lo == 0 }
|
||||
|
||||
// and returns the bitwise AND of u and m (u&m).
|
||||
func (u uint128) and(m uint128) uint128 {
|
||||
return uint128{u.hi & m.hi, u.lo & m.lo}
|
||||
}
|
||||
|
||||
// xor returns the bitwise XOR of u and m (u^m).
|
||||
func (u uint128) xor(m uint128) uint128 {
|
||||
return uint128{u.hi ^ m.hi, u.lo ^ m.lo}
|
||||
}
|
||||
|
||||
// or returns the bitwise OR of u and m (u|m).
|
||||
func (u uint128) or(m uint128) uint128 {
|
||||
return uint128{u.hi | m.hi, u.lo | m.lo}
|
||||
}
|
||||
|
||||
// not returns the bitwise NOT of u.
|
||||
func (u uint128) not() uint128 {
|
||||
return uint128{^u.hi, ^u.lo}
|
||||
}
|
||||
|
||||
// subOne returns u - 1.
|
||||
func (u uint128) subOne() uint128 {
|
||||
lo, borrow := bits.Sub64(u.lo, 1, 0)
|
||||
return uint128{u.hi - borrow, lo}
|
||||
}
|
||||
|
||||
// addOne returns u + 1.
|
||||
func (u uint128) addOne() uint128 {
|
||||
lo, carry := bits.Add64(u.lo, 1, 0)
|
||||
return uint128{u.hi + carry, lo}
|
||||
}
|
||||
|
||||
func u64CommonPrefixLen(a, b uint64) uint8 {
|
||||
return uint8(bits.LeadingZeros64(a ^ b))
|
||||
}
|
||||
|
||||
func (u uint128) commonPrefixLen(v uint128) (n uint8) {
|
||||
if n = u64CommonPrefixLen(u.hi, v.hi); n == 64 {
|
||||
n += u64CommonPrefixLen(u.lo, v.lo)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (u *uint128) halves() [2]*uint64 {
|
||||
return [2]*uint64{&u.hi, &u.lo}
|
||||
}
|
||||
|
||||
// bitsSetFrom returns a copy of u with the given bit
|
||||
// and all subsequent ones set.
|
||||
func (u uint128) bitsSetFrom(bit uint8) uint128 {
|
||||
return u.or(mask6[bit].not())
|
||||
}
|
||||
|
||||
// bitsClearedFrom returns a copy of u with the given bit
|
||||
// and all subsequent ones cleared.
|
||||
func (u uint128) bitsClearedFrom(bit uint8) uint128 {
|
||||
return u.and(mask6[bit])
|
||||
}
|
|
@ -18,7 +18,6 @@ git.tcp.direct/Mirrors/go-prompt/internal/term
|
|||
# git.tcp.direct/kayos/common v0.7.6
|
||||
## explicit; go 1.19
|
||||
git.tcp.direct/kayos/common/entropy
|
||||
git.tcp.direct/kayos/common/network
|
||||
git.tcp.direct/kayos/common/pool
|
||||
git.tcp.direct/kayos/common/squish
|
||||
# git.tcp.direct/tcp.direct/database v0.0.0-20220829103039-b85255196bd1
|
||||
|
@ -168,12 +167,9 @@ github.com/spf13/viper/internal/encoding/yaml
|
|||
# github.com/subosito/gotenv v1.3.0
|
||||
## explicit; go 1.18
|
||||
github.com/subosito/gotenv
|
||||
# go4.org/intern v0.0.0-20211027215823-ae77deb06f29
|
||||
## explicit; go 1.13
|
||||
go4.org/intern
|
||||
# go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760
|
||||
## explicit; go 1.11
|
||||
go4.org/unsafe/assume-no-moving-gc
|
||||
# go4.org/netipx v0.0.0-20230125063823-8449b0a6169f
|
||||
## explicit; go 1.18
|
||||
go4.org/netipx
|
||||
# golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d
|
||||
## explicit; go 1.17
|
||||
golang.org/x/crypto/bcrypt
|
||||
|
@ -218,9 +214,6 @@ gopkg.in/yaml.v2
|
|||
# gopkg.in/yaml.v3 v3.0.0
|
||||
## explicit
|
||||
gopkg.in/yaml.v3
|
||||
# inet.af/netaddr v0.0.0-20220811202034-502d2d690317
|
||||
## explicit; go 1.12
|
||||
inet.af/netaddr
|
||||
# nullprogram.com/x/rng v1.1.0
|
||||
## explicit; go 1.13
|
||||
nullprogram.com/x/rng
|
||||
|
|
Loading…
Reference in New Issue