1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
// Copyright 2021 The gVisor Authors.
//
// 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 cgroupfs
import (
"fmt"
"strconv"
"strings"
"gvisor.dev/gvisor/pkg/bitmap"
)
// formatBitmap produces a string representation of b, which lists the indicies
// of set bits in the bitmap. Indicies are separated by commas and ranges of
// set bits are abbreviated. Example outputs: "0,2,4", "0,3-7,10", "0-10".
//
// Inverse of parseBitmap.
func formatBitmap(b *bitmap.Bitmap) string {
ones := b.ToSlice()
if len(ones) == 0 {
return ""
}
elems := make([]string, 0, len(ones))
runStart := ones[0]
lastVal := ones[0]
inRun := false
for _, v := range ones[1:] {
last := lastVal
lastVal = v
if last+1 == v {
// In a contiguous block of ones.
if !inRun {
runStart = last
inRun = true
}
continue
}
// Non-contiguous bit.
if inRun {
// Render a run
elems = append(elems, fmt.Sprintf("%d-%d", runStart, last))
inRun = false
continue
}
// Lone non-contiguous bit.
elems = append(elems, fmt.Sprintf("%d", last))
}
// Process potential final run
if inRun {
elems = append(elems, fmt.Sprintf("%d-%d", runStart, lastVal))
} else {
elems = append(elems, fmt.Sprintf("%d", lastVal))
}
return strings.Join(elems, ",")
}
func parseToken(token string) (start, end uint32, err error) {
ts := strings.SplitN(token, "-", 2)
switch len(ts) {
case 0:
return 0, 0, fmt.Errorf("invalid token %q", token)
case 1:
val, err := strconv.ParseUint(ts[0], 10, 32)
if err != nil {
return 0, 0, err
}
return uint32(val), uint32(val), nil
case 2:
val1, err := strconv.ParseUint(ts[0], 10, 32)
if err != nil {
return 0, 0, err
}
val2, err := strconv.ParseUint(ts[1], 10, 32)
if err != nil {
return 0, 0, err
}
if val1 >= val2 {
return 0, 0, fmt.Errorf("start (%v) must be less than end (%v)", val1, val2)
}
return uint32(val1), uint32(val2), nil
default:
panic(fmt.Sprintf("Unreachable: got %d substrs", len(ts)))
}
}
// parseBitmap parses input as a bitmap. input should be a comma separated list
// of indices, and ranges of set bits may be abbreviated. Examples: "0,2,4",
// "0,3-7,10", "0-10". Input after the first newline or null byte is discarded.
//
// sizeHint sets the initial size of the bitmap, which may prevent reallocation
// when growing the bitmap during parsing. Ideally sizeHint should be at least
// as large as the bitmap represented by input, but this is not required.
//
// Inverse of formatBitmap.
func parseBitmap(input string, sizeHint uint32) (*bitmap.Bitmap, error) {
b := bitmap.New(sizeHint)
if termIdx := strings.IndexAny(input, "\n\000"); termIdx != -1 {
input = input[:termIdx]
}
input = strings.TrimSpace(input)
if len(input) == 0 {
return &b, nil
}
tokens := strings.Split(input, ",")
for _, t := range tokens {
start, end, err := parseToken(strings.TrimSpace(t))
if err != nil {
return nil, err
}
for i := start; i <= end; i++ {
b.Add(i)
}
}
return &b, nil
}
|