119 lines
2.7 KiB
Go
119 lines
2.7 KiB
Go
/*
|
|
Copyright 2019 Intel Corporation
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package rdt
|
|
|
|
import (
|
|
"fmt"
|
|
"math/bits"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// bitmask represents a generic 64 bit wide bitmask
|
|
type bitmask uint64
|
|
|
|
// MarshalJSON implements the Marshaler interface of "encoding/json"
|
|
func (b bitmask) MarshalJSON() ([]byte, error) {
|
|
return []byte(fmt.Sprintf("\"%#x\"", b)), nil
|
|
}
|
|
|
|
// listStr prints the bitmask in human-readable format, similar to e.g. the
|
|
// cpuset format of the Linux kernel
|
|
func (b bitmask) listStr() string {
|
|
str := ""
|
|
sep := ""
|
|
|
|
shift := int(0)
|
|
lsbOne := b.lsbOne()
|
|
|
|
// Process "ranges of ones"
|
|
for lsbOne != -1 {
|
|
b >>= uint(lsbOne)
|
|
|
|
// Get range lenght from the position of the first zero
|
|
numOnes := b.lsbZero()
|
|
|
|
if numOnes == 1 {
|
|
str += sep + strconv.Itoa(lsbOne+shift)
|
|
} else {
|
|
str += sep + strconv.Itoa(lsbOne+shift) + "-" + strconv.Itoa(lsbOne+numOnes-1+shift)
|
|
}
|
|
|
|
// Shift away the bits that have been processed
|
|
b >>= uint(numOnes)
|
|
shift += lsbOne + numOnes
|
|
|
|
// Get next bit that is set (if any)
|
|
lsbOne = b.lsbOne()
|
|
|
|
sep = ","
|
|
}
|
|
|
|
return str
|
|
}
|
|
|
|
// listStrToBitmask parses a string containing a human-readable list of bit
|
|
// numbers into a bitmask
|
|
func listStrToBitmask(str string) (bitmask, error) {
|
|
b := bitmask(0)
|
|
|
|
// Empty bitmask
|
|
if len(str) == 0 {
|
|
return b, nil
|
|
}
|
|
|
|
ranges := strings.Split(str, ",")
|
|
for _, ran := range ranges {
|
|
split := strings.SplitN(ran, "-", 2)
|
|
|
|
bitNum, err := strconv.ParseUint(split[0], 10, 6)
|
|
if err != nil {
|
|
return b, fmt.Errorf("invalid bitmask %q: %v", str, err)
|
|
}
|
|
|
|
if len(split) == 1 {
|
|
b |= 1 << bitNum
|
|
} else {
|
|
endNum, err := strconv.ParseUint(split[1], 10, 6)
|
|
if err != nil {
|
|
return b, fmt.Errorf("invalid bitmask %q: %v", str, err)
|
|
}
|
|
if endNum <= bitNum {
|
|
return b, fmt.Errorf("invalid range %q in bitmask %q", ran, str)
|
|
}
|
|
b |= (1<<(endNum-bitNum+1) - 1) << bitNum
|
|
}
|
|
}
|
|
return b, nil
|
|
}
|
|
|
|
func (b bitmask) lsbOne() int {
|
|
if b == 0 {
|
|
return -1
|
|
}
|
|
return bits.TrailingZeros64(uint64(b))
|
|
}
|
|
|
|
func (b bitmask) msbOne() int {
|
|
// Returns -1 for b == 0
|
|
return 63 - bits.LeadingZeros64(uint64(b))
|
|
}
|
|
|
|
func (b bitmask) lsbZero() int {
|
|
return bits.TrailingZeros64(^uint64(b))
|
|
}
|