mirror of https://github.com/k3s-io/k3s
bump(golang.org/x/tools/container/intsets): 2382e3994d48b1d22acc2c86bcad0a2aff028e32
parent
b5eadb5d6b
commit
986cdfa6ff
|
@ -2739,6 +2739,10 @@
|
|||
"ImportPath": "golang.org/x/time/rate",
|
||||
"Rev": "f51c12702a4d776e4c1fa9b0fabab841babae631"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/tools/container/intsets",
|
||||
"Rev": "2382e3994d48b1d22acc2c86bcad0a2aff028e32"
|
||||
},
|
||||
{
|
||||
"ImportPath": "google.golang.org/api/cloudmonitoring/v2beta2",
|
||||
"Rev": "e3824ed33c72bf7e81da0286772c34b987520914"
|
||||
|
|
|
@ -83172,6 +83172,41 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
================================================================================
|
||||
|
||||
|
||||
================================================================================
|
||||
= vendor/golang.org/x/tools/container/intsets licensed under: =
|
||||
|
||||
Copyright (c) 2009 The Go 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 Google 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.
|
||||
|
||||
= vendor/golang.org/x/tools/LICENSE 5d4950ecb7b26d2c5e4e7b4e0dd74707 -
|
||||
================================================================================
|
||||
|
||||
|
||||
================================================================================
|
||||
= vendor/google.golang.org/api/cloudmonitoring/v2beta2 licensed under: =
|
||||
|
||||
|
|
|
@ -346,6 +346,7 @@ filegroup(
|
|||
"//vendor/golang.org/x/text/unicode/norm:all-srcs",
|
||||
"//vendor/golang.org/x/text/width:all-srcs",
|
||||
"//vendor/golang.org/x/time/rate:all-srcs",
|
||||
"//vendor/golang.org/x/tools/container/intsets:all-srcs",
|
||||
"//vendor/google.golang.org/api/cloudmonitoring/v2beta2:all-srcs",
|
||||
"//vendor/google.golang.org/api/compute/v0.alpha:all-srcs",
|
||||
"//vendor/google.golang.org/api/compute/v0.beta:all-srcs",
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# This source code refers to The Go Authors for copyright purposes.
|
||||
# The master list of authors is in the main Go distribution,
|
||||
# visible at http://tip.golang.org/AUTHORS.
|
|
@ -0,0 +1,3 @@
|
|||
# This source code was written by the Go contributors.
|
||||
# The master list of contributors is in the main Go distribution,
|
||||
# visible at http://tip.golang.org/CONTRIBUTORS.
|
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2009 The Go 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 Google 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.
|
|
@ -0,0 +1,22 @@
|
|||
Additional IP Rights Grant (Patents)
|
||||
|
||||
"This implementation" means the copyrightable works distributed by
|
||||
Google as part of the Go project.
|
||||
|
||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||
patent license to make, have made, use, offer to sell, sell, import,
|
||||
transfer and otherwise run, modify and propagate the contents of this
|
||||
implementation of Go, where such license applies only to those patent
|
||||
claims, both currently owned or controlled by Google and acquired in
|
||||
the future, licensable by Google that are necessarily infringed by this
|
||||
implementation of Go. This grant does not include claims that would be
|
||||
infringed only as a consequence of further modification of this
|
||||
implementation. If you or your agent or exclusive licensee institute or
|
||||
order or agree to the institution of patent litigation against any
|
||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||
that this implementation of Go or any code incorporated within this
|
||||
implementation of Go constitutes direct or contributory patent
|
||||
infringement, or inducement of patent infringement, then any patent
|
||||
rights granted to you under this License for this implementation of Go
|
||||
shall terminate as of the date such litigation is filed.
|
|
@ -0,0 +1,32 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"popcnt_amd64.go",
|
||||
"popcnt_amd64.s",
|
||||
"sparse.go",
|
||||
"util.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
// +build amd64,!appengine,!gccgo
|
||||
|
||||
package intsets
|
||||
|
||||
func popcnt(x word) int
|
||||
func havePOPCNT() bool
|
||||
|
||||
var hasPOPCNT = havePOPCNT()
|
||||
|
||||
// popcount returns the population count (number of set bits) of x.
|
||||
func popcount(x word) int {
|
||||
if hasPOPCNT {
|
||||
return popcnt(x)
|
||||
}
|
||||
return popcountTable(x) // faster than Hacker's Delight
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
// +build amd64,!appengine,!gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// func havePOPCNT() bool
|
||||
TEXT ·havePOPCNT(SB),4,$0
|
||||
MOVQ $1, AX
|
||||
CPUID
|
||||
SHRQ $23, CX
|
||||
ANDQ $1, CX
|
||||
MOVB CX, ret+0(FP)
|
||||
RET
|
||||
|
||||
// func popcnt(word) int
|
||||
TEXT ·popcnt(SB),NOSPLIT,$0-8
|
||||
XORQ AX, AX
|
||||
MOVQ x+0(FP), SI
|
||||
// POPCNT (SI), AX is not recognized by Go assembler,
|
||||
// so we assemble it ourselves.
|
||||
BYTE $0xf3
|
||||
BYTE $0x48
|
||||
BYTE $0x0f
|
||||
BYTE $0xb8
|
||||
BYTE $0xc6
|
||||
MOVQ AX, ret+8(FP)
|
||||
RET
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
// +build gccgo
|
||||
|
||||
package intsets
|
||||
|
||||
func popcount(x word) int
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
// +build gccgo
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define _STRINGIFY2_(x) #x
|
||||
#define _STRINGIFY_(x) _STRINGIFY2_(x)
|
||||
#define GOSYM_PREFIX _STRINGIFY_(__USER_LABEL_PREFIX__)
|
||||
|
||||
extern intptr_t popcount(uintptr_t x) __asm__(GOSYM_PREFIX GOPKGPATH ".popcount");
|
||||
|
||||
intptr_t popcount(uintptr_t x) {
|
||||
return __builtin_popcountl((unsigned long)(x));
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
// +build !amd64 appengine
|
||||
// +build !gccgo
|
||||
|
||||
package intsets
|
||||
|
||||
import "runtime"
|
||||
|
||||
// We compared three algorithms---Hacker's Delight, table lookup,
|
||||
// and AMD64's SSE4.1 hardware POPCNT---on a 2.67GHz Xeon X5550.
|
||||
//
|
||||
// % GOARCH=amd64 go test -run=NONE -bench=Popcount
|
||||
// POPCNT 5.12 ns/op
|
||||
// Table 8.53 ns/op
|
||||
// HackersDelight 9.96 ns/op
|
||||
//
|
||||
// % GOARCH=386 go test -run=NONE -bench=Popcount
|
||||
// Table 10.4 ns/op
|
||||
// HackersDelight 5.23 ns/op
|
||||
//
|
||||
// (AMD64's ABM1 hardware supports ntz and nlz too,
|
||||
// but they aren't critical.)
|
||||
|
||||
// popcount returns the population count (number of set bits) of x.
|
||||
func popcount(x word) int {
|
||||
if runtime.GOARCH == "386" {
|
||||
return popcountHD(uint32(x))
|
||||
}
|
||||
return popcountTable(x)
|
||||
}
|
|
@ -0,0 +1,967 @@
|
|||
// Copyright 2014 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 intsets provides Sparse, a compact and fast representation
|
||||
// for sparse sets of int values.
|
||||
//
|
||||
// The time complexity of the operations Len, Insert, Remove and Has
|
||||
// is in O(n) but in practice those methods are faster and more
|
||||
// space-efficient than equivalent operations on sets based on the Go
|
||||
// map type. The IsEmpty, Min, Max, Clear and TakeMin operations
|
||||
// require constant time.
|
||||
//
|
||||
package intsets
|
||||
|
||||
// TODO(adonovan):
|
||||
// - Add InsertAll(...int), RemoveAll(...int)
|
||||
// - Add 'bool changed' results for {Intersection,Difference}With too.
|
||||
//
|
||||
// TODO(adonovan): implement Dense, a dense bit vector with a similar API.
|
||||
// The space usage would be proportional to Max(), not Len(), and the
|
||||
// implementation would be based upon big.Int.
|
||||
//
|
||||
// TODO(adonovan): experiment with making the root block indirect (nil
|
||||
// iff IsEmpty). This would reduce the memory usage when empty and
|
||||
// might simplify the aliasing invariants.
|
||||
//
|
||||
// TODO(adonovan): opt: make UnionWith and Difference faster.
|
||||
// These are the hot-spots for go/pointer.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// A Sparse is a set of int values.
|
||||
// Sparse operations (even queries) are not concurrency-safe.
|
||||
//
|
||||
// The zero value for Sparse is a valid empty set.
|
||||
//
|
||||
// Sparse sets must be copied using the Copy method, not by assigning
|
||||
// a Sparse value.
|
||||
//
|
||||
type Sparse struct {
|
||||
// An uninitialized Sparse represents an empty set.
|
||||
// An empty set may also be represented by
|
||||
// root.next == root.prev == &root.
|
||||
// In a non-empty set, root.next points to the first block and
|
||||
// root.prev to the last.
|
||||
// root.offset and root.bits are unused.
|
||||
root block
|
||||
}
|
||||
|
||||
type word uintptr
|
||||
|
||||
const (
|
||||
_m = ^word(0)
|
||||
bitsPerWord = 8 << (_m>>8&1 + _m>>16&1 + _m>>32&1)
|
||||
bitsPerBlock = 256 // optimal value for go/pointer solver performance
|
||||
wordsPerBlock = bitsPerBlock / bitsPerWord
|
||||
)
|
||||
|
||||
// Limit values of implementation-specific int type.
|
||||
const (
|
||||
MaxInt = int(^uint(0) >> 1)
|
||||
MinInt = -MaxInt - 1
|
||||
)
|
||||
|
||||
// -- block ------------------------------------------------------------
|
||||
|
||||
// A set is represented as a circular doubly-linked list of blocks,
|
||||
// each containing an offset and a bit array of fixed size
|
||||
// bitsPerBlock; the blocks are ordered by increasing offset.
|
||||
//
|
||||
// The set contains an element x iff the block whose offset is x - (x
|
||||
// mod bitsPerBlock) has the bit (x mod bitsPerBlock) set, where mod
|
||||
// is the Euclidean remainder.
|
||||
//
|
||||
// A block may only be empty transiently.
|
||||
//
|
||||
type block struct {
|
||||
offset int // offset mod bitsPerBlock == 0
|
||||
bits [wordsPerBlock]word // contains at least one set bit
|
||||
next, prev *block // doubly-linked list of blocks
|
||||
}
|
||||
|
||||
// wordMask returns the word index (in block.bits)
|
||||
// and single-bit mask for the block's ith bit.
|
||||
func wordMask(i uint) (w uint, mask word) {
|
||||
w = i / bitsPerWord
|
||||
mask = 1 << (i % bitsPerWord)
|
||||
return
|
||||
}
|
||||
|
||||
// insert sets the block b's ith bit and
|
||||
// returns true if it was not already set.
|
||||
//
|
||||
func (b *block) insert(i uint) bool {
|
||||
w, mask := wordMask(i)
|
||||
if b.bits[w]&mask == 0 {
|
||||
b.bits[w] |= mask
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// remove clears the block's ith bit and
|
||||
// returns true if the bit was previously set.
|
||||
// NB: may leave the block empty.
|
||||
//
|
||||
func (b *block) remove(i uint) bool {
|
||||
w, mask := wordMask(i)
|
||||
if b.bits[w]&mask != 0 {
|
||||
b.bits[w] &^= mask
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// has reports whether the block's ith bit is set.
|
||||
func (b *block) has(i uint) bool {
|
||||
w, mask := wordMask(i)
|
||||
return b.bits[w]&mask != 0
|
||||
}
|
||||
|
||||
// empty reports whether b.len()==0, but more efficiently.
|
||||
func (b *block) empty() bool {
|
||||
for _, w := range b.bits {
|
||||
if w != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// len returns the number of set bits in block b.
|
||||
func (b *block) len() int {
|
||||
var l int
|
||||
for _, w := range b.bits {
|
||||
l += popcount(w)
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// max returns the maximum element of the block.
|
||||
// The block must not be empty.
|
||||
//
|
||||
func (b *block) max() int {
|
||||
bi := b.offset + bitsPerBlock
|
||||
// Decrement bi by number of high zeros in last.bits.
|
||||
for i := len(b.bits) - 1; i >= 0; i-- {
|
||||
if w := b.bits[i]; w != 0 {
|
||||
return bi - nlz(w) - 1
|
||||
}
|
||||
bi -= bitsPerWord
|
||||
}
|
||||
panic("BUG: empty block")
|
||||
}
|
||||
|
||||
// min returns the minimum element of the block,
|
||||
// and also removes it if take is set.
|
||||
// The block must not be initially empty.
|
||||
// NB: may leave the block empty.
|
||||
//
|
||||
func (b *block) min(take bool) int {
|
||||
for i, w := range b.bits {
|
||||
if w != 0 {
|
||||
tz := ntz(w)
|
||||
if take {
|
||||
b.bits[i] = w &^ (1 << uint(tz))
|
||||
}
|
||||
return b.offset + int(i*bitsPerWord) + tz
|
||||
}
|
||||
}
|
||||
panic("BUG: empty block")
|
||||
}
|
||||
|
||||
// forEach calls f for each element of block b.
|
||||
// f must not mutate b's enclosing Sparse.
|
||||
func (b *block) forEach(f func(int)) {
|
||||
for i, w := range b.bits {
|
||||
offset := b.offset + i*bitsPerWord
|
||||
for bi := 0; w != 0 && bi < bitsPerWord; bi++ {
|
||||
if w&1 != 0 {
|
||||
f(offset)
|
||||
}
|
||||
offset++
|
||||
w >>= 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// offsetAndBitIndex returns the offset of the block that would
|
||||
// contain x and the bit index of x within that block.
|
||||
//
|
||||
func offsetAndBitIndex(x int) (int, uint) {
|
||||
mod := x % bitsPerBlock
|
||||
if mod < 0 {
|
||||
// Euclidean (non-negative) remainder
|
||||
mod += bitsPerBlock
|
||||
}
|
||||
return x - mod, uint(mod)
|
||||
}
|
||||
|
||||
// -- Sparse --------------------------------------------------------------
|
||||
|
||||
// start returns the root's next block, which is the root block
|
||||
// (if s.IsEmpty()) or the first true block otherwise.
|
||||
// start has the side effect of ensuring that s is properly
|
||||
// initialized.
|
||||
//
|
||||
func (s *Sparse) start() *block {
|
||||
root := &s.root
|
||||
if root.next == nil {
|
||||
root.next = root
|
||||
root.prev = root
|
||||
} else if root.next.prev != root {
|
||||
// Copying a Sparse x leads to pernicious corruption: the
|
||||
// new Sparse y shares the old linked list, but iteration
|
||||
// on y will never encounter &y.root so it goes into a
|
||||
// loop. Fail fast before this occurs.
|
||||
panic("A Sparse has been copied without (*Sparse).Copy()")
|
||||
}
|
||||
|
||||
return root.next
|
||||
}
|
||||
|
||||
// IsEmpty reports whether the set s is empty.
|
||||
func (s *Sparse) IsEmpty() bool {
|
||||
return s.start() == &s.root
|
||||
}
|
||||
|
||||
// Len returns the number of elements in the set s.
|
||||
func (s *Sparse) Len() int {
|
||||
var l int
|
||||
for b := s.start(); b != &s.root; b = b.next {
|
||||
l += b.len()
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// Max returns the maximum element of the set s, or MinInt if s is empty.
|
||||
func (s *Sparse) Max() int {
|
||||
if s.IsEmpty() {
|
||||
return MinInt
|
||||
}
|
||||
return s.root.prev.max()
|
||||
}
|
||||
|
||||
// Min returns the minimum element of the set s, or MaxInt if s is empty.
|
||||
func (s *Sparse) Min() int {
|
||||
if s.IsEmpty() {
|
||||
return MaxInt
|
||||
}
|
||||
return s.root.next.min(false)
|
||||
}
|
||||
|
||||
// block returns the block that would contain offset,
|
||||
// or nil if s contains no such block.
|
||||
//
|
||||
func (s *Sparse) block(offset int) *block {
|
||||
b := s.start()
|
||||
for b != &s.root && b.offset <= offset {
|
||||
if b.offset == offset {
|
||||
return b
|
||||
}
|
||||
b = b.next
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Insert adds x to the set s, and reports whether the set grew.
|
||||
func (s *Sparse) Insert(x int) bool {
|
||||
offset, i := offsetAndBitIndex(x)
|
||||
b := s.start()
|
||||
for b != &s.root && b.offset <= offset {
|
||||
if b.offset == offset {
|
||||
return b.insert(i)
|
||||
}
|
||||
b = b.next
|
||||
}
|
||||
|
||||
// Insert new block before b.
|
||||
new := &block{offset: offset}
|
||||
new.next = b
|
||||
new.prev = b.prev
|
||||
new.prev.next = new
|
||||
new.next.prev = new
|
||||
return new.insert(i)
|
||||
}
|
||||
|
||||
func (s *Sparse) removeBlock(b *block) {
|
||||
b.prev.next = b.next
|
||||
b.next.prev = b.prev
|
||||
}
|
||||
|
||||
// Remove removes x from the set s, and reports whether the set shrank.
|
||||
func (s *Sparse) Remove(x int) bool {
|
||||
offset, i := offsetAndBitIndex(x)
|
||||
if b := s.block(offset); b != nil {
|
||||
if !b.remove(i) {
|
||||
return false
|
||||
}
|
||||
if b.empty() {
|
||||
s.removeBlock(b)
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Clear removes all elements from the set s.
|
||||
func (s *Sparse) Clear() {
|
||||
s.root.next = &s.root
|
||||
s.root.prev = &s.root
|
||||
}
|
||||
|
||||
// If set s is non-empty, TakeMin sets *p to the minimum element of
|
||||
// the set s, removes that element from the set and returns true.
|
||||
// Otherwise, it returns false and *p is undefined.
|
||||
//
|
||||
// This method may be used for iteration over a worklist like so:
|
||||
//
|
||||
// var x int
|
||||
// for worklist.TakeMin(&x) { use(x) }
|
||||
//
|
||||
func (s *Sparse) TakeMin(p *int) bool {
|
||||
head := s.start()
|
||||
if head == &s.root {
|
||||
return false
|
||||
}
|
||||
*p = head.min(true)
|
||||
if head.empty() {
|
||||
s.removeBlock(head)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Has reports whether x is an element of the set s.
|
||||
func (s *Sparse) Has(x int) bool {
|
||||
offset, i := offsetAndBitIndex(x)
|
||||
if b := s.block(offset); b != nil {
|
||||
return b.has(i)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// forEach applies function f to each element of the set s in order.
|
||||
//
|
||||
// f must not mutate s. Consequently, forEach is not safe to expose
|
||||
// to clients. In any case, using "range s.AppendTo()" allows more
|
||||
// natural control flow with continue/break/return.
|
||||
//
|
||||
func (s *Sparse) forEach(f func(int)) {
|
||||
for b := s.start(); b != &s.root; b = b.next {
|
||||
b.forEach(f)
|
||||
}
|
||||
}
|
||||
|
||||
// Copy sets s to the value of x.
|
||||
func (s *Sparse) Copy(x *Sparse) {
|
||||
if s == x {
|
||||
return
|
||||
}
|
||||
|
||||
xb := x.start()
|
||||
sb := s.start()
|
||||
for xb != &x.root {
|
||||
if sb == &s.root {
|
||||
sb = s.insertBlockBefore(sb)
|
||||
}
|
||||
sb.offset = xb.offset
|
||||
sb.bits = xb.bits
|
||||
xb = xb.next
|
||||
sb = sb.next
|
||||
}
|
||||
s.discardTail(sb)
|
||||
}
|
||||
|
||||
// insertBlockBefore returns a new block, inserting it before next.
|
||||
func (s *Sparse) insertBlockBefore(next *block) *block {
|
||||
b := new(block)
|
||||
b.next = next
|
||||
b.prev = next.prev
|
||||
b.prev.next = b
|
||||
next.prev = b
|
||||
return b
|
||||
}
|
||||
|
||||
// discardTail removes block b and all its successors from s.
|
||||
func (s *Sparse) discardTail(b *block) {
|
||||
if b != &s.root {
|
||||
b.prev.next = &s.root
|
||||
s.root.prev = b.prev
|
||||
}
|
||||
}
|
||||
|
||||
// IntersectionWith sets s to the intersection s ∩ x.
|
||||
func (s *Sparse) IntersectionWith(x *Sparse) {
|
||||
if s == x {
|
||||
return
|
||||
}
|
||||
|
||||
xb := x.start()
|
||||
sb := s.start()
|
||||
for xb != &x.root && sb != &s.root {
|
||||
switch {
|
||||
case xb.offset < sb.offset:
|
||||
xb = xb.next
|
||||
|
||||
case xb.offset > sb.offset:
|
||||
sb = sb.next
|
||||
s.removeBlock(sb.prev)
|
||||
|
||||
default:
|
||||
var sum word
|
||||
for i := range sb.bits {
|
||||
r := xb.bits[i] & sb.bits[i]
|
||||
sb.bits[i] = r
|
||||
sum |= r
|
||||
}
|
||||
if sum != 0 {
|
||||
sb = sb.next
|
||||
} else {
|
||||
// sb will be overwritten or removed
|
||||
}
|
||||
|
||||
xb = xb.next
|
||||
}
|
||||
}
|
||||
|
||||
s.discardTail(sb)
|
||||
}
|
||||
|
||||
// Intersection sets s to the intersection x ∩ y.
|
||||
func (s *Sparse) Intersection(x, y *Sparse) {
|
||||
switch {
|
||||
case s == x:
|
||||
s.IntersectionWith(y)
|
||||
return
|
||||
case s == y:
|
||||
s.IntersectionWith(x)
|
||||
return
|
||||
case x == y:
|
||||
s.Copy(x)
|
||||
return
|
||||
}
|
||||
|
||||
xb := x.start()
|
||||
yb := y.start()
|
||||
sb := s.start()
|
||||
for xb != &x.root && yb != &y.root {
|
||||
switch {
|
||||
case xb.offset < yb.offset:
|
||||
xb = xb.next
|
||||
continue
|
||||
case xb.offset > yb.offset:
|
||||
yb = yb.next
|
||||
continue
|
||||
}
|
||||
|
||||
if sb == &s.root {
|
||||
sb = s.insertBlockBefore(sb)
|
||||
}
|
||||
sb.offset = xb.offset
|
||||
|
||||
var sum word
|
||||
for i := range sb.bits {
|
||||
r := xb.bits[i] & yb.bits[i]
|
||||
sb.bits[i] = r
|
||||
sum |= r
|
||||
}
|
||||
if sum != 0 {
|
||||
sb = sb.next
|
||||
} else {
|
||||
// sb will be overwritten or removed
|
||||
}
|
||||
|
||||
xb = xb.next
|
||||
yb = yb.next
|
||||
}
|
||||
|
||||
s.discardTail(sb)
|
||||
}
|
||||
|
||||
// Intersects reports whether s ∩ x ≠ ∅.
|
||||
func (s *Sparse) Intersects(x *Sparse) bool {
|
||||
sb := s.start()
|
||||
xb := x.start()
|
||||
for sb != &s.root && xb != &x.root {
|
||||
switch {
|
||||
case xb.offset < sb.offset:
|
||||
xb = xb.next
|
||||
case xb.offset > sb.offset:
|
||||
sb = sb.next
|
||||
default:
|
||||
for i := range sb.bits {
|
||||
if sb.bits[i]&xb.bits[i] != 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
sb = sb.next
|
||||
xb = xb.next
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// UnionWith sets s to the union s ∪ x, and reports whether s grew.
|
||||
func (s *Sparse) UnionWith(x *Sparse) bool {
|
||||
if s == x {
|
||||
return false
|
||||
}
|
||||
|
||||
var changed bool
|
||||
xb := x.start()
|
||||
sb := s.start()
|
||||
for xb != &x.root {
|
||||
if sb != &s.root && sb.offset == xb.offset {
|
||||
for i := range xb.bits {
|
||||
if sb.bits[i] != xb.bits[i] {
|
||||
sb.bits[i] |= xb.bits[i]
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
xb = xb.next
|
||||
} else if sb == &s.root || sb.offset > xb.offset {
|
||||
sb = s.insertBlockBefore(sb)
|
||||
sb.offset = xb.offset
|
||||
sb.bits = xb.bits
|
||||
changed = true
|
||||
|
||||
xb = xb.next
|
||||
}
|
||||
sb = sb.next
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
// Union sets s to the union x ∪ y.
|
||||
func (s *Sparse) Union(x, y *Sparse) {
|
||||
switch {
|
||||
case x == y:
|
||||
s.Copy(x)
|
||||
return
|
||||
case s == x:
|
||||
s.UnionWith(y)
|
||||
return
|
||||
case s == y:
|
||||
s.UnionWith(x)
|
||||
return
|
||||
}
|
||||
|
||||
xb := x.start()
|
||||
yb := y.start()
|
||||
sb := s.start()
|
||||
for xb != &x.root || yb != &y.root {
|
||||
if sb == &s.root {
|
||||
sb = s.insertBlockBefore(sb)
|
||||
}
|
||||
switch {
|
||||
case yb == &y.root || (xb != &x.root && xb.offset < yb.offset):
|
||||
sb.offset = xb.offset
|
||||
sb.bits = xb.bits
|
||||
xb = xb.next
|
||||
|
||||
case xb == &x.root || (yb != &y.root && yb.offset < xb.offset):
|
||||
sb.offset = yb.offset
|
||||
sb.bits = yb.bits
|
||||
yb = yb.next
|
||||
|
||||
default:
|
||||
sb.offset = xb.offset
|
||||
for i := range xb.bits {
|
||||
sb.bits[i] = xb.bits[i] | yb.bits[i]
|
||||
}
|
||||
xb = xb.next
|
||||
yb = yb.next
|
||||
}
|
||||
sb = sb.next
|
||||
}
|
||||
|
||||
s.discardTail(sb)
|
||||
}
|
||||
|
||||
// DifferenceWith sets s to the difference s ∖ x.
|
||||
func (s *Sparse) DifferenceWith(x *Sparse) {
|
||||
if s == x {
|
||||
s.Clear()
|
||||
return
|
||||
}
|
||||
|
||||
xb := x.start()
|
||||
sb := s.start()
|
||||
for xb != &x.root && sb != &s.root {
|
||||
switch {
|
||||
case xb.offset > sb.offset:
|
||||
sb = sb.next
|
||||
|
||||
case xb.offset < sb.offset:
|
||||
xb = xb.next
|
||||
|
||||
default:
|
||||
var sum word
|
||||
for i := range sb.bits {
|
||||
r := sb.bits[i] & ^xb.bits[i]
|
||||
sb.bits[i] = r
|
||||
sum |= r
|
||||
}
|
||||
sb = sb.next
|
||||
xb = xb.next
|
||||
|
||||
if sum == 0 {
|
||||
s.removeBlock(sb.prev)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Difference sets s to the difference x ∖ y.
|
||||
func (s *Sparse) Difference(x, y *Sparse) {
|
||||
switch {
|
||||
case x == y:
|
||||
s.Clear()
|
||||
return
|
||||
case s == x:
|
||||
s.DifferenceWith(y)
|
||||
return
|
||||
case s == y:
|
||||
var y2 Sparse
|
||||
y2.Copy(y)
|
||||
s.Difference(x, &y2)
|
||||
return
|
||||
}
|
||||
|
||||
xb := x.start()
|
||||
yb := y.start()
|
||||
sb := s.start()
|
||||
for xb != &x.root && yb != &y.root {
|
||||
if xb.offset > yb.offset {
|
||||
// y has block, x has none
|
||||
yb = yb.next
|
||||
continue
|
||||
}
|
||||
|
||||
if sb == &s.root {
|
||||
sb = s.insertBlockBefore(sb)
|
||||
}
|
||||
sb.offset = xb.offset
|
||||
|
||||
switch {
|
||||
case xb.offset < yb.offset:
|
||||
// x has block, y has none
|
||||
sb.bits = xb.bits
|
||||
|
||||
sb = sb.next
|
||||
|
||||
default:
|
||||
// x and y have corresponding blocks
|
||||
var sum word
|
||||
for i := range sb.bits {
|
||||
r := xb.bits[i] & ^yb.bits[i]
|
||||
sb.bits[i] = r
|
||||
sum |= r
|
||||
}
|
||||
if sum != 0 {
|
||||
sb = sb.next
|
||||
} else {
|
||||
// sb will be overwritten or removed
|
||||
}
|
||||
|
||||
yb = yb.next
|
||||
}
|
||||
xb = xb.next
|
||||
}
|
||||
|
||||
for xb != &x.root {
|
||||
if sb == &s.root {
|
||||
sb = s.insertBlockBefore(sb)
|
||||
}
|
||||
sb.offset = xb.offset
|
||||
sb.bits = xb.bits
|
||||
sb = sb.next
|
||||
|
||||
xb = xb.next
|
||||
}
|
||||
|
||||
s.discardTail(sb)
|
||||
}
|
||||
|
||||
// SymmetricDifferenceWith sets s to the symmetric difference s ∆ x.
|
||||
func (s *Sparse) SymmetricDifferenceWith(x *Sparse) {
|
||||
if s == x {
|
||||
s.Clear()
|
||||
return
|
||||
}
|
||||
|
||||
sb := s.start()
|
||||
xb := x.start()
|
||||
for xb != &x.root && sb != &s.root {
|
||||
switch {
|
||||
case sb.offset < xb.offset:
|
||||
sb = sb.next
|
||||
case xb.offset < sb.offset:
|
||||
nb := s.insertBlockBefore(sb)
|
||||
nb.offset = xb.offset
|
||||
nb.bits = xb.bits
|
||||
xb = xb.next
|
||||
default:
|
||||
var sum word
|
||||
for i := range sb.bits {
|
||||
r := sb.bits[i] ^ xb.bits[i]
|
||||
sb.bits[i] = r
|
||||
sum |= r
|
||||
}
|
||||
sb = sb.next
|
||||
xb = xb.next
|
||||
if sum == 0 {
|
||||
s.removeBlock(sb.prev)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for xb != &x.root { // append the tail of x to s
|
||||
sb = s.insertBlockBefore(sb)
|
||||
sb.offset = xb.offset
|
||||
sb.bits = xb.bits
|
||||
sb = sb.next
|
||||
xb = xb.next
|
||||
}
|
||||
}
|
||||
|
||||
// SymmetricDifference sets s to the symmetric difference x ∆ y.
|
||||
func (s *Sparse) SymmetricDifference(x, y *Sparse) {
|
||||
switch {
|
||||
case x == y:
|
||||
s.Clear()
|
||||
return
|
||||
case s == x:
|
||||
s.SymmetricDifferenceWith(y)
|
||||
return
|
||||
case s == y:
|
||||
s.SymmetricDifferenceWith(x)
|
||||
return
|
||||
}
|
||||
|
||||
sb := s.start()
|
||||
xb := x.start()
|
||||
yb := y.start()
|
||||
for xb != &x.root && yb != &y.root {
|
||||
if sb == &s.root {
|
||||
sb = s.insertBlockBefore(sb)
|
||||
}
|
||||
switch {
|
||||
case yb.offset < xb.offset:
|
||||
sb.offset = yb.offset
|
||||
sb.bits = yb.bits
|
||||
sb = sb.next
|
||||
yb = yb.next
|
||||
case xb.offset < yb.offset:
|
||||
sb.offset = xb.offset
|
||||
sb.bits = xb.bits
|
||||
sb = sb.next
|
||||
xb = xb.next
|
||||
default:
|
||||
var sum word
|
||||
for i := range sb.bits {
|
||||
r := xb.bits[i] ^ yb.bits[i]
|
||||
sb.bits[i] = r
|
||||
sum |= r
|
||||
}
|
||||
if sum != 0 {
|
||||
sb.offset = xb.offset
|
||||
sb = sb.next
|
||||
}
|
||||
xb = xb.next
|
||||
yb = yb.next
|
||||
}
|
||||
}
|
||||
|
||||
for xb != &x.root { // append the tail of x to s
|
||||
if sb == &s.root {
|
||||
sb = s.insertBlockBefore(sb)
|
||||
}
|
||||
sb.offset = xb.offset
|
||||
sb.bits = xb.bits
|
||||
sb = sb.next
|
||||
xb = xb.next
|
||||
}
|
||||
|
||||
for yb != &y.root { // append the tail of y to s
|
||||
if sb == &s.root {
|
||||
sb = s.insertBlockBefore(sb)
|
||||
}
|
||||
sb.offset = yb.offset
|
||||
sb.bits = yb.bits
|
||||
sb = sb.next
|
||||
yb = yb.next
|
||||
}
|
||||
|
||||
s.discardTail(sb)
|
||||
}
|
||||
|
||||
// SubsetOf reports whether s ∖ x = ∅.
|
||||
func (s *Sparse) SubsetOf(x *Sparse) bool {
|
||||
if s == x {
|
||||
return true
|
||||
}
|
||||
|
||||
sb := s.start()
|
||||
xb := x.start()
|
||||
for sb != &s.root {
|
||||
switch {
|
||||
case xb == &x.root || xb.offset > sb.offset:
|
||||
return false
|
||||
case xb.offset < sb.offset:
|
||||
xb = xb.next
|
||||
default:
|
||||
for i := range sb.bits {
|
||||
if sb.bits[i]&^xb.bits[i] != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
sb = sb.next
|
||||
xb = xb.next
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Equals reports whether the sets s and t have the same elements.
|
||||
func (s *Sparse) Equals(t *Sparse) bool {
|
||||
if s == t {
|
||||
return true
|
||||
}
|
||||
sb := s.start()
|
||||
tb := t.start()
|
||||
for {
|
||||
switch {
|
||||
case sb == &s.root && tb == &t.root:
|
||||
return true
|
||||
case sb == &s.root || tb == &t.root:
|
||||
return false
|
||||
case sb.offset != tb.offset:
|
||||
return false
|
||||
case sb.bits != tb.bits:
|
||||
return false
|
||||
}
|
||||
|
||||
sb = sb.next
|
||||
tb = tb.next
|
||||
}
|
||||
}
|
||||
|
||||
// String returns a human-readable description of the set s.
|
||||
func (s *Sparse) String() string {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteByte('{')
|
||||
s.forEach(func(x int) {
|
||||
if buf.Len() > 1 {
|
||||
buf.WriteByte(' ')
|
||||
}
|
||||
fmt.Fprintf(&buf, "%d", x)
|
||||
})
|
||||
buf.WriteByte('}')
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// BitString returns the set as a string of 1s and 0s denoting the sum
|
||||
// of the i'th powers of 2, for each i in s. A radix point, always
|
||||
// preceded by a digit, appears if the sum is non-integral.
|
||||
//
|
||||
// Examples:
|
||||
// {}.BitString() = "0"
|
||||
// {4,5}.BitString() = "110000"
|
||||
// {-3}.BitString() = "0.001"
|
||||
// {-3,0,4,5}.BitString() = "110001.001"
|
||||
//
|
||||
func (s *Sparse) BitString() string {
|
||||
if s.IsEmpty() {
|
||||
return "0"
|
||||
}
|
||||
|
||||
min, max := s.Min(), s.Max()
|
||||
var nbytes int
|
||||
if max > 0 {
|
||||
nbytes = max
|
||||
}
|
||||
nbytes++ // zero bit
|
||||
radix := nbytes
|
||||
if min < 0 {
|
||||
nbytes += len(".") - min
|
||||
}
|
||||
|
||||
b := make([]byte, nbytes)
|
||||
for i := range b {
|
||||
b[i] = '0'
|
||||
}
|
||||
if radix < nbytes {
|
||||
b[radix] = '.'
|
||||
}
|
||||
s.forEach(func(x int) {
|
||||
if x >= 0 {
|
||||
x += len(".")
|
||||
}
|
||||
b[radix-x] = '1'
|
||||
})
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// GoString returns a string showing the internal representation of
|
||||
// the set s.
|
||||
//
|
||||
func (s *Sparse) GoString() string {
|
||||
var buf bytes.Buffer
|
||||
for b := s.start(); b != &s.root; b = b.next {
|
||||
fmt.Fprintf(&buf, "block %p {offset=%d next=%p prev=%p",
|
||||
b, b.offset, b.next, b.prev)
|
||||
for _, w := range b.bits {
|
||||
fmt.Fprintf(&buf, " 0%016x", w)
|
||||
}
|
||||
fmt.Fprintf(&buf, "}\n")
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// AppendTo returns the result of appending the elements of s to slice
|
||||
// in order.
|
||||
func (s *Sparse) AppendTo(slice []int) []int {
|
||||
s.forEach(func(x int) {
|
||||
slice = append(slice, x)
|
||||
})
|
||||
return slice
|
||||
}
|
||||
|
||||
// -- Testing/debugging ------------------------------------------------
|
||||
|
||||
// check returns an error if the representation invariants of s are violated.
|
||||
func (s *Sparse) check() error {
|
||||
if !s.root.empty() {
|
||||
return fmt.Errorf("non-empty root block")
|
||||
}
|
||||
if s.root.offset != 0 {
|
||||
return fmt.Errorf("root block has non-zero offset %d", s.root.offset)
|
||||
}
|
||||
for b := s.start(); b != &s.root; b = b.next {
|
||||
if b.offset%bitsPerBlock != 0 {
|
||||
return fmt.Errorf("bad offset modulo: %d", b.offset)
|
||||
}
|
||||
if b.empty() {
|
||||
return fmt.Errorf("empty block")
|
||||
}
|
||||
if b.prev.next != b {
|
||||
return fmt.Errorf("bad prev.next link")
|
||||
}
|
||||
if b.next.prev != b {
|
||||
return fmt.Errorf("bad next.prev link")
|
||||
}
|
||||
if b.prev != &s.root {
|
||||
if b.offset <= b.prev.offset {
|
||||
return fmt.Errorf("bad offset order: b.offset=%d, prev.offset=%d",
|
||||
b.offset, b.prev.offset)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
// Copyright 2013 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 intsets
|
||||
|
||||
// From Hacker's Delight, fig 5.2.
|
||||
func popcountHD(x uint32) int {
|
||||
x -= (x >> 1) & 0x55555555
|
||||
x = (x & 0x33333333) + ((x >> 2) & 0x33333333)
|
||||
x = (x + (x >> 4)) & 0x0f0f0f0f
|
||||
x = x + (x >> 8)
|
||||
x = x + (x >> 16)
|
||||
return int(x & 0x0000003f)
|
||||
}
|
||||
|
||||
var a [1 << 8]byte
|
||||
|
||||
func init() {
|
||||
for i := range a {
|
||||
var n byte
|
||||
for x := i; x != 0; x >>= 1 {
|
||||
if x&1 != 0 {
|
||||
n++
|
||||
}
|
||||
}
|
||||
a[i] = n
|
||||
}
|
||||
}
|
||||
|
||||
func popcountTable(x word) int {
|
||||
return int(a[byte(x>>(0*8))] +
|
||||
a[byte(x>>(1*8))] +
|
||||
a[byte(x>>(2*8))] +
|
||||
a[byte(x>>(3*8))] +
|
||||
a[byte(x>>(4*8))] +
|
||||
a[byte(x>>(5*8))] +
|
||||
a[byte(x>>(6*8))] +
|
||||
a[byte(x>>(7*8))])
|
||||
}
|
||||
|
||||
// nlz returns the number of leading zeros of x.
|
||||
// From Hacker's Delight, fig 5.11.
|
||||
func nlz(x word) int {
|
||||
x |= (x >> 1)
|
||||
x |= (x >> 2)
|
||||
x |= (x >> 4)
|
||||
x |= (x >> 8)
|
||||
x |= (x >> 16)
|
||||
x |= (x >> 32)
|
||||
return popcount(^x)
|
||||
}
|
||||
|
||||
// ntz returns the number of trailing zeros of x.
|
||||
// From Hacker's Delight, fig 5.13.
|
||||
func ntz(x word) int {
|
||||
if x == 0 {
|
||||
return bitsPerWord
|
||||
}
|
||||
n := 1
|
||||
if bitsPerWord == 64 {
|
||||
if (x & 0xffffffff) == 0 {
|
||||
n = n + 32
|
||||
x = x >> 32
|
||||
}
|
||||
}
|
||||
if (x & 0x0000ffff) == 0 {
|
||||
n = n + 16
|
||||
x = x >> 16
|
||||
}
|
||||
if (x & 0x000000ff) == 0 {
|
||||
n = n + 8
|
||||
x = x >> 8
|
||||
}
|
||||
if (x & 0x0000000f) == 0 {
|
||||
n = n + 4
|
||||
x = x >> 4
|
||||
}
|
||||
if (x & 0x00000003) == 0 {
|
||||
n = n + 2
|
||||
x = x >> 2
|
||||
}
|
||||
return n - int(x&1)
|
||||
}
|
Loading…
Reference in New Issue