New parser and comparison
This commit is contained in:
parent
364180b396
commit
cbb5f21112
|
@ -77,6 +77,11 @@ func TimeToPtr(t time.Duration) *time.Duration {
|
||||||
return &t
|
return &t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Float64ToPtr returns the pointer to an float64
|
||||||
|
func Float64ToPtr(f float64) *float64 {
|
||||||
|
return &f
|
||||||
|
}
|
||||||
|
|
||||||
func IntMin(a, b int) int {
|
func IntMin(a, b int) int {
|
||||||
if a < b {
|
if a < b {
|
||||||
return a
|
return a
|
||||||
|
|
|
@ -2,8 +2,18 @@ package structs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"math/big"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
|
"github.com/hashicorp/nomad/helper"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// floatPrecision is the precision used before rounding. It is set to a high
|
||||||
|
// number to give a high chance of correctly returning equality.
|
||||||
|
floatPrecision = uint(256)
|
||||||
)
|
)
|
||||||
|
|
||||||
// BaseUnit is a unique base unit. All units that share the same base unit
|
// BaseUnit is a unique base unit. All units that share the same base unit
|
||||||
|
@ -27,7 +37,7 @@ type Unit struct {
|
||||||
Base BaseUnit
|
Base BaseUnit
|
||||||
|
|
||||||
// Multiplier is the multiplier over the base unit (KiB multiplier is 1024)
|
// Multiplier is the multiplier over the base unit (KiB multiplier is 1024)
|
||||||
Multiplier uint64
|
Multiplier int64
|
||||||
|
|
||||||
// InverseMultiplier specifies that the multiplier is an inverse so:
|
// InverseMultiplier specifies that the multiplier is an inverse so:
|
||||||
// Base / Multiplier. For example a mW is a W/1000.
|
// Base / Multiplier. For example a mW is a W/1000.
|
||||||
|
@ -47,83 +57,323 @@ func (u *Unit) Comparable(o *Unit) bool {
|
||||||
// specifying units
|
// specifying units
|
||||||
type Attribute struct {
|
type Attribute struct {
|
||||||
// Float is the float value for the attribute
|
// Float is the float value for the attribute
|
||||||
Float float64
|
Float *float64
|
||||||
|
|
||||||
// Int is the int value for the attribute
|
// Int is the int value for the attribute
|
||||||
Int int64
|
Int *int64
|
||||||
|
|
||||||
// String is the string value for the attribute
|
// String is the string value for the attribute
|
||||||
String string
|
String *string
|
||||||
|
|
||||||
// Bool is the bool value for the attribute
|
// Bool is the bool value for the attribute
|
||||||
Bool bool
|
Bool *bool
|
||||||
|
|
||||||
// Unit is the optional unit for the set int or float value
|
// Unit is the optional unit for the set int or float value
|
||||||
Unit string
|
Unit string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GoString returns a string representation of the attribute
|
||||||
|
func (a *Attribute) GoString() string {
|
||||||
|
if a == nil {
|
||||||
|
return "nil attribute"
|
||||||
|
}
|
||||||
|
|
||||||
|
var b strings.Builder
|
||||||
|
if a.Float != nil {
|
||||||
|
b.WriteString(fmt.Sprintf("%v", *a.Float))
|
||||||
|
} else if a.Int != nil {
|
||||||
|
b.WriteString(fmt.Sprintf("%v", *a.Int))
|
||||||
|
} else if a.Bool != nil {
|
||||||
|
b.WriteString(fmt.Sprintf("%v", *a.Bool))
|
||||||
|
} else if a.String != nil {
|
||||||
|
b.WriteString(*a.String)
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.Unit != "" {
|
||||||
|
b.WriteString(a.Unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
|
||||||
// Validate checks if the attribute is valid
|
// Validate checks if the attribute is valid
|
||||||
func (a *Attribute) Validate() error {
|
func (a *Attribute) Validate() error {
|
||||||
if a.Unit != "" {
|
if a.Unit != "" {
|
||||||
if _, ok := UnitIndex[a.Unit]; !ok {
|
if _, ok := UnitIndex[a.Unit]; !ok {
|
||||||
return fmt.Errorf("unrecognized unit %q", a.Unit)
|
return fmt.Errorf("unrecognized unit %q", a.Unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check only int/float set
|
||||||
|
if a.String != nil || a.Bool != nil {
|
||||||
|
return fmt.Errorf("unit can not be specified on a boolean or string attribute")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assert only one of the attributes is set
|
||||||
|
set := 0
|
||||||
|
if a.Float != nil {
|
||||||
|
set++
|
||||||
|
}
|
||||||
|
if a.Int != nil {
|
||||||
|
set++
|
||||||
|
}
|
||||||
|
if a.String != nil {
|
||||||
|
set++
|
||||||
|
}
|
||||||
|
if a.Bool != nil {
|
||||||
|
set++
|
||||||
|
}
|
||||||
|
|
||||||
|
if set == 0 {
|
||||||
|
return fmt.Errorf("no attribute value set")
|
||||||
|
} else if set > 1 {
|
||||||
|
return fmt.Errorf("only one attribute value may be set")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
// Compare compares two attributes. If the returned boolean value is false, it
|
||||||
// numericWithUnits matches only if it is a integer or float ending with
|
// means the values are not comparable, either because they are of different
|
||||||
// units. It has two capture groups, one for the numeric value and one for
|
// types (bool versus int) or the units are incompatible for comparison.
|
||||||
// the unit value
|
// The returned int will be 0 if a==b, -1 if a < b, and +1 if a > b for all
|
||||||
numericWithUnits = regexp.MustCompile(`^([-]?(?:[0-9]+|[0-9]+\.[0-9]+|\.[0-9]+))\s*([a-zA-Z]+\/?[a-zA-z]+|[a-zA-Z])$`)
|
// values but bool. For bool it will be 0 if a==b or 1 if a!=b.
|
||||||
)
|
func (a *Attribute) Compare(b *Attribute) (int, bool) {
|
||||||
|
if !a.Comparable(b) {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.comparitor()(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// comparitor returns the comparitor function for the attribute
|
||||||
|
func (a *Attribute) comparitor() compareFn {
|
||||||
|
if a.Bool != nil {
|
||||||
|
return a.boolComparitor
|
||||||
|
}
|
||||||
|
if a.String != nil {
|
||||||
|
return a.stringComparitor
|
||||||
|
}
|
||||||
|
if a.Int != nil || a.Float != nil {
|
||||||
|
return a.numberComparitor
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullComparitor
|
||||||
|
}
|
||||||
|
|
||||||
|
// boolComparitor compares two boolean attributes
|
||||||
|
func (a *Attribute) boolComparitor(b *Attribute) (int, bool) {
|
||||||
|
if *a.Bool == *b.Bool {
|
||||||
|
return 0, true
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// stringComparitor compares two string attributes
|
||||||
|
func (a *Attribute) stringComparitor(b *Attribute) (int, bool) {
|
||||||
|
return strings.Compare(*a.String, *b.String), true
|
||||||
|
}
|
||||||
|
|
||||||
|
// numberComparitor compares two number attributes, having either Int or Float
|
||||||
|
// set.
|
||||||
|
func (a *Attribute) numberComparitor(b *Attribute) (int, bool) {
|
||||||
|
// If they are both integers we do perfect precision comparisons
|
||||||
|
if a.Int != nil && b.Int != nil {
|
||||||
|
return a.intComparitor(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push both into the float space
|
||||||
|
af := a.getBigFloat()
|
||||||
|
bf := b.getBigFloat()
|
||||||
|
if af == nil || bf == nil {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return af.Cmp(bf), true
|
||||||
|
}
|
||||||
|
|
||||||
|
// intComparitor compares two integer attributes.
|
||||||
|
func (a *Attribute) intComparitor(b *Attribute) (int, bool) {
|
||||||
|
ai := a.getInt()
|
||||||
|
bi := b.getInt()
|
||||||
|
|
||||||
|
if ai == bi {
|
||||||
|
return 0, true
|
||||||
|
} else if ai < bi {
|
||||||
|
return -1, true
|
||||||
|
} else {
|
||||||
|
return 1, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// nullComparitor always returns false and is used when no comparison function
|
||||||
|
// is possible
|
||||||
|
func nullComparitor(*Attribute) (int, bool) {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// compareFn is used to compare two attributes. It returns -1, 0, 1 for ordering
|
||||||
|
// and a boolean for if the comparison is possible.
|
||||||
|
type compareFn func(b *Attribute) (int, bool)
|
||||||
|
|
||||||
|
// getBigFloat returns a big.Float representation of the attribute, converting
|
||||||
|
// the value to the base unit if a unit is specified.
|
||||||
|
func (a *Attribute) getBigFloat() *big.Float {
|
||||||
|
f := new(big.Float)
|
||||||
|
f.SetPrec(floatPrecision)
|
||||||
|
if a.Int != nil {
|
||||||
|
f.SetInt64(*a.Int)
|
||||||
|
} else if a.Float != nil {
|
||||||
|
f.SetFloat64(*a.Float)
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the unit
|
||||||
|
u := a.getTypedUnit()
|
||||||
|
|
||||||
|
// If there is no unit just return the float
|
||||||
|
if u == nil {
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to the base unit
|
||||||
|
multiplier := new(big.Float)
|
||||||
|
multiplier.SetPrec(floatPrecision)
|
||||||
|
multiplier.SetInt64(u.Multiplier)
|
||||||
|
if u.InverseMultiplier {
|
||||||
|
base := big.NewFloat(1.0)
|
||||||
|
base.SetPrec(floatPrecision)
|
||||||
|
multiplier = multiplier.Quo(base, multiplier)
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Mul(f, multiplier)
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
// getInt returns an int representation of the attribute, converting
|
||||||
|
// the value to the base unit if a unit is specified.
|
||||||
|
func (a *Attribute) getInt() int64 {
|
||||||
|
if a.Int == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
i := *a.Int
|
||||||
|
|
||||||
|
// Get the unit
|
||||||
|
u := a.getTypedUnit()
|
||||||
|
|
||||||
|
// If there is no unit just return the int
|
||||||
|
if u == nil {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
if u.InverseMultiplier {
|
||||||
|
i /= u.Multiplier
|
||||||
|
} else {
|
||||||
|
i *= u.Multiplier
|
||||||
|
}
|
||||||
|
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comparable returns whether they are comparable
|
||||||
|
func (a *Attribute) Comparable(b *Attribute) bool {
|
||||||
|
if a == nil || b == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// First use the units to decide if comparison is possible
|
||||||
|
aUnit := a.getTypedUnit()
|
||||||
|
bUnit := b.getTypedUnit()
|
||||||
|
if aUnit != nil && bUnit != nil {
|
||||||
|
return aUnit.Comparable(bUnit)
|
||||||
|
} else if aUnit != nil && bUnit == nil {
|
||||||
|
return false
|
||||||
|
} else if aUnit == nil && bUnit != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.String != nil {
|
||||||
|
if b.String != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if a.Bool != nil {
|
||||||
|
if b.Bool != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// getTypedUnit returns the Unit for the attribute or nil if no unit exists.
|
||||||
|
func (a *Attribute) getTypedUnit() *Unit {
|
||||||
|
return UnitIndex[a.Unit]
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseAttribute takes a string and parses it into an attribute, pulling out
|
||||||
|
// units if they are specified as a suffix on a number
|
||||||
func ParseAttribute(input string) *Attribute {
|
func ParseAttribute(input string) *Attribute {
|
||||||
|
ll := len(input)
|
||||||
|
if ll == 0 {
|
||||||
|
return &Attribute{String: helper.StringToPtr(input)}
|
||||||
|
}
|
||||||
|
|
||||||
// Try to parse as a bool
|
// Try to parse as a bool
|
||||||
b, err := strconv.ParseBool(input)
|
b, err := strconv.ParseBool(input)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return &Attribute{Bool: b}
|
return &Attribute{Bool: helper.BoolToPtr(b)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to parse as a number.
|
|
||||||
|
|
||||||
// Check if the string is a number ending with potential units
|
// Check if the string is a number ending with potential units
|
||||||
if matches := numericWithUnits.FindStringSubmatch(input); len(matches) == 3 {
|
if unicode.IsLetter(rune(input[ll-1])) {
|
||||||
numeric := matches[1]
|
// Try suffix matching
|
||||||
unit := matches[2]
|
var unit string
|
||||||
|
for _, u := range lengthSortedUnits {
|
||||||
|
if strings.HasSuffix(input, u) {
|
||||||
|
unit = u
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if we know about the unit. If we don't we can only treat this
|
// Check if we know about the unit. If we don't we can only treat this
|
||||||
// as a string
|
// as a string
|
||||||
if _, ok := UnitIndex[unit]; !ok {
|
if len(unit) == 0 {
|
||||||
return &Attribute{String: input}
|
return &Attribute{String: helper.StringToPtr(input)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Grab the numeric
|
||||||
|
numeric := strings.TrimSpace(strings.TrimSuffix(input, unit))
|
||||||
|
|
||||||
// Try to parse as an int
|
// Try to parse as an int
|
||||||
i, err := strconv.ParseInt(numeric, 10, 64)
|
i, err := strconv.ParseInt(numeric, 10, 64)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return &Attribute{Int: i, Unit: unit}
|
return &Attribute{Int: helper.Int64ToPtr(i), Unit: unit}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to parse as a float
|
// Try to parse as a float
|
||||||
f, err := strconv.ParseFloat(numeric, 64)
|
f, err := strconv.ParseFloat(numeric, 64)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return &Attribute{Float: f, Unit: unit}
|
return &Attribute{Float: helper.Float64ToPtr(f), Unit: unit}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to parse as an int
|
// Try to parse as an int
|
||||||
i, err := strconv.ParseInt(input, 10, 64)
|
i, err := strconv.ParseInt(input, 10, 64)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return &Attribute{Int: i}
|
return &Attribute{Int: helper.Int64ToPtr(i)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to parse as a float
|
// Try to parse as a float
|
||||||
f, err := strconv.ParseFloat(input, 64)
|
f, err := strconv.ParseFloat(input, 64)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return &Attribute{Float: f}
|
return &Attribute{Float: helper.Float64ToPtr(f)}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Attribute{String: input}
|
return &Attribute{String: helper.StringToPtr(input)}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,546 @@
|
||||||
package structs
|
package structs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/nomad/helper"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestAttribute_Validate(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
Input *Attribute
|
||||||
|
Fail bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Input: &Attribute{
|
||||||
|
Bool: helper.BoolToPtr(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: &Attribute{
|
||||||
|
String: helper.StringToPtr("foo"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(123),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(123.2),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: &Attribute{
|
||||||
|
Bool: helper.BoolToPtr(true),
|
||||||
|
Unit: "MB",
|
||||||
|
},
|
||||||
|
Fail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: &Attribute{
|
||||||
|
String: helper.StringToPtr("foo"),
|
||||||
|
Unit: "MB",
|
||||||
|
},
|
||||||
|
Fail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(123),
|
||||||
|
Unit: "lolNO",
|
||||||
|
},
|
||||||
|
Fail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(123.2),
|
||||||
|
Unit: "lolNO",
|
||||||
|
},
|
||||||
|
Fail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(123),
|
||||||
|
Float: helper.Float64ToPtr(123.2),
|
||||||
|
Unit: "mW",
|
||||||
|
},
|
||||||
|
Fail: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
|
t.Run(c.Input.GoString(), func(t *testing.T) {
|
||||||
|
if err := c.Input.Validate(); err != nil && !c.Fail {
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type compareTestCase struct {
|
||||||
|
A *Attribute
|
||||||
|
B *Attribute
|
||||||
|
Expected int
|
||||||
|
NotComparable bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAttribute_Compare_Bool(t *testing.T) {
|
||||||
|
cases := []*compareTestCase{
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Bool: helper.BoolToPtr(true),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Bool: helper.BoolToPtr(true),
|
||||||
|
},
|
||||||
|
Expected: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Bool: helper.BoolToPtr(true),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Bool: helper.BoolToPtr(false),
|
||||||
|
},
|
||||||
|
Expected: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Bool: helper.BoolToPtr(true),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
String: helper.StringToPtr("foo"),
|
||||||
|
},
|
||||||
|
NotComparable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Bool: helper.BoolToPtr(true),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(123),
|
||||||
|
},
|
||||||
|
NotComparable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Bool: helper.BoolToPtr(true),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(123.2),
|
||||||
|
},
|
||||||
|
NotComparable: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
testComparison(t, cases)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAttribute_Compare_String(t *testing.T) {
|
||||||
|
cases := []*compareTestCase{
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
String: helper.StringToPtr("a"),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
String: helper.StringToPtr("b"),
|
||||||
|
},
|
||||||
|
Expected: -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
String: helper.StringToPtr("hello"),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
String: helper.StringToPtr("hello"),
|
||||||
|
},
|
||||||
|
Expected: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
String: helper.StringToPtr("b"),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
String: helper.StringToPtr("a"),
|
||||||
|
},
|
||||||
|
Expected: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
String: helper.StringToPtr("hello"),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Bool: helper.BoolToPtr(true),
|
||||||
|
},
|
||||||
|
NotComparable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
String: helper.StringToPtr("hello"),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(123),
|
||||||
|
},
|
||||||
|
NotComparable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
String: helper.StringToPtr("hello"),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(123.2),
|
||||||
|
},
|
||||||
|
NotComparable: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
testComparison(t, cases)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAttribute_Compare_Float(t *testing.T) {
|
||||||
|
cases := []*compareTestCase{
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(101.5),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(100001.5),
|
||||||
|
},
|
||||||
|
Expected: -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(100001.5),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(100001.5),
|
||||||
|
},
|
||||||
|
Expected: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(999999999.5),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(101.5),
|
||||||
|
},
|
||||||
|
Expected: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(101.5),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Bool: helper.BoolToPtr(true),
|
||||||
|
},
|
||||||
|
NotComparable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(101.5),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
String: helper.StringToPtr("hello"),
|
||||||
|
},
|
||||||
|
NotComparable: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
testComparison(t, cases)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAttribute_Compare_Int(t *testing.T) {
|
||||||
|
cases := []*compareTestCase{
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(3),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(10),
|
||||||
|
},
|
||||||
|
Expected: -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(10),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(10),
|
||||||
|
},
|
||||||
|
Expected: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(100),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(10),
|
||||||
|
},
|
||||||
|
Expected: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(10),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Bool: helper.BoolToPtr(true),
|
||||||
|
},
|
||||||
|
NotComparable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(10),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
String: helper.StringToPtr("hello"),
|
||||||
|
},
|
||||||
|
NotComparable: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
testComparison(t, cases)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAttribute_Compare_Int_With_Units(t *testing.T) {
|
||||||
|
cases := []*compareTestCase{
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(3),
|
||||||
|
Unit: "MB",
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(10),
|
||||||
|
Unit: "MB",
|
||||||
|
},
|
||||||
|
Expected: -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(10),
|
||||||
|
Unit: "MB",
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(10),
|
||||||
|
Unit: "MB",
|
||||||
|
},
|
||||||
|
Expected: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(100),
|
||||||
|
Unit: "MB",
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(10),
|
||||||
|
Unit: "MB",
|
||||||
|
},
|
||||||
|
Expected: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(3),
|
||||||
|
Unit: "GB",
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(3),
|
||||||
|
Unit: "MB",
|
||||||
|
},
|
||||||
|
Expected: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(1),
|
||||||
|
Unit: "GiB",
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(1024),
|
||||||
|
Unit: "MiB",
|
||||||
|
},
|
||||||
|
Expected: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(1),
|
||||||
|
Unit: "GiB",
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(1025),
|
||||||
|
Unit: "MiB",
|
||||||
|
},
|
||||||
|
Expected: -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(1000),
|
||||||
|
Unit: "mW",
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(1),
|
||||||
|
Unit: "W",
|
||||||
|
},
|
||||||
|
Expected: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
testComparison(t, cases)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAttribute_Compare_Float_With_Units(t *testing.T) {
|
||||||
|
cases := []*compareTestCase{
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(3.0),
|
||||||
|
Unit: "MB",
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(10.0),
|
||||||
|
Unit: "MB",
|
||||||
|
},
|
||||||
|
Expected: -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(10.0),
|
||||||
|
Unit: "MB",
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(10.0),
|
||||||
|
Unit: "MB",
|
||||||
|
},
|
||||||
|
Expected: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(100.0),
|
||||||
|
Unit: "MB",
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(10.0),
|
||||||
|
Unit: "MB",
|
||||||
|
},
|
||||||
|
Expected: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(3.0),
|
||||||
|
Unit: "GB",
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(3.0),
|
||||||
|
Unit: "MB",
|
||||||
|
},
|
||||||
|
Expected: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(1.0),
|
||||||
|
Unit: "GiB",
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(1024.0),
|
||||||
|
Unit: "MiB",
|
||||||
|
},
|
||||||
|
Expected: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(1.0),
|
||||||
|
Unit: "GiB",
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(1025.0),
|
||||||
|
Unit: "MiB",
|
||||||
|
},
|
||||||
|
Expected: -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(1000.0),
|
||||||
|
Unit: "mW",
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(1.0),
|
||||||
|
Unit: "W",
|
||||||
|
},
|
||||||
|
Expected: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(1.5),
|
||||||
|
Unit: "GiB",
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(1400.0),
|
||||||
|
Unit: "MiB",
|
||||||
|
},
|
||||||
|
Expected: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
testComparison(t, cases)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAttribute_Compare_IntToFloat(t *testing.T) {
|
||||||
|
cases := []*compareTestCase{
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(3),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(10.0),
|
||||||
|
},
|
||||||
|
Expected: -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(10),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(10.0),
|
||||||
|
},
|
||||||
|
Expected: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(10),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(10.1),
|
||||||
|
},
|
||||||
|
Expected: -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(100),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(10.0),
|
||||||
|
},
|
||||||
|
Expected: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: &Attribute{
|
||||||
|
Int: helper.Int64ToPtr(100),
|
||||||
|
},
|
||||||
|
B: &Attribute{
|
||||||
|
Float: helper.Float64ToPtr(100.00001),
|
||||||
|
},
|
||||||
|
Expected: -1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
testComparison(t, cases)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testComparison(t *testing.T, cases []*compareTestCase) {
|
||||||
|
for _, c := range cases {
|
||||||
|
t.Run(fmt.Sprintf("%#v vs %#v", c.A, c.B), func(t *testing.T) {
|
||||||
|
v, ok := c.A.Compare(c.B)
|
||||||
|
if !ok && !c.NotComparable {
|
||||||
|
t.Fatal("should be comparable")
|
||||||
|
} else if ok {
|
||||||
|
require.Equal(t, c.Expected, v)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestAttribute_ParseAndValidate(t *testing.T) {
|
func TestAttribute_ParseAndValidate(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
Input string
|
Input string
|
||||||
|
@ -14,102 +549,102 @@ func TestAttribute_ParseAndValidate(t *testing.T) {
|
||||||
{
|
{
|
||||||
Input: "true",
|
Input: "true",
|
||||||
Expected: &Attribute{
|
Expected: &Attribute{
|
||||||
Bool: true,
|
Bool: helper.BoolToPtr(true),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Input: "false",
|
Input: "false",
|
||||||
Expected: &Attribute{
|
Expected: &Attribute{
|
||||||
Bool: false,
|
Bool: helper.BoolToPtr(false),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Input: "100",
|
Input: "100",
|
||||||
Expected: &Attribute{
|
Expected: &Attribute{
|
||||||
Int: 100,
|
Int: helper.Int64ToPtr(100),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Input: "-100",
|
Input: "-100",
|
||||||
Expected: &Attribute{
|
Expected: &Attribute{
|
||||||
Int: -100,
|
Int: helper.Int64ToPtr(-100),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Input: "-1.0",
|
Input: "-1.0",
|
||||||
Expected: &Attribute{
|
Expected: &Attribute{
|
||||||
Float: -1.0,
|
Float: helper.Float64ToPtr(-1.0),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Input: "-100.25",
|
Input: "-100.25",
|
||||||
Expected: &Attribute{
|
Expected: &Attribute{
|
||||||
Float: -100.25,
|
Float: helper.Float64ToPtr(-100.25),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Input: "1.01",
|
Input: "1.01",
|
||||||
Expected: &Attribute{
|
Expected: &Attribute{
|
||||||
Float: 1.01,
|
Float: helper.Float64ToPtr(1.01),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Input: "100.25",
|
Input: "100.25",
|
||||||
Expected: &Attribute{
|
Expected: &Attribute{
|
||||||
Float: 100.25,
|
Float: helper.Float64ToPtr(100.25),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Input: "foobar",
|
Input: "foobar",
|
||||||
Expected: &Attribute{
|
Expected: &Attribute{
|
||||||
String: "foobar",
|
String: helper.StringToPtr("foobar"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Input: "foo123bar",
|
Input: "foo123bar",
|
||||||
Expected: &Attribute{
|
Expected: &Attribute{
|
||||||
String: "foo123bar",
|
String: helper.StringToPtr("foo123bar"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Input: "100MB",
|
Input: "100MB",
|
||||||
Expected: &Attribute{
|
Expected: &Attribute{
|
||||||
Int: 100,
|
Int: helper.Int64ToPtr(100),
|
||||||
Unit: "MB",
|
Unit: "MB",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Input: "-100MHz",
|
Input: "-100MHz",
|
||||||
Expected: &Attribute{
|
Expected: &Attribute{
|
||||||
Int: -100,
|
Int: helper.Int64ToPtr(-100),
|
||||||
Unit: "MHz",
|
Unit: "MHz",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Input: "-1.0MB/s",
|
Input: "-1.0MB/s",
|
||||||
Expected: &Attribute{
|
Expected: &Attribute{
|
||||||
Float: -1.0,
|
Float: helper.Float64ToPtr(-1.0),
|
||||||
Unit: "MB/s",
|
Unit: "MB/s",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Input: "-100.25GiB/s",
|
Input: "-100.25GiB/s",
|
||||||
Expected: &Attribute{
|
Expected: &Attribute{
|
||||||
Float: -100.25,
|
Float: helper.Float64ToPtr(-100.25),
|
||||||
Unit: "GiB/s",
|
Unit: "GiB/s",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Input: "1.01TB",
|
Input: "1.01TB",
|
||||||
Expected: &Attribute{
|
Expected: &Attribute{
|
||||||
Float: 1.01,
|
Float: helper.Float64ToPtr(1.01),
|
||||||
Unit: "TB",
|
Unit: "TB",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Input: "100.25mW",
|
Input: "100.25mW",
|
||||||
Expected: &Attribute{
|
Expected: &Attribute{
|
||||||
Float: 100.25,
|
Float: helper.Float64ToPtr(100.25),
|
||||||
Unit: "mW",
|
Unit: "mW",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -123,3 +658,31 @@ func TestAttribute_ParseAndValidate(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkParse(b *testing.B) {
|
||||||
|
cases := []string{
|
||||||
|
"true",
|
||||||
|
"false",
|
||||||
|
"100",
|
||||||
|
"-100",
|
||||||
|
"-1.0",
|
||||||
|
"-100.25",
|
||||||
|
"1.01",
|
||||||
|
"100.25",
|
||||||
|
"foobar",
|
||||||
|
"foo123bar",
|
||||||
|
"100MB",
|
||||||
|
"-100MHz",
|
||||||
|
"-1.0MB/s",
|
||||||
|
"-100.25GiB/s",
|
||||||
|
"1.01TB",
|
||||||
|
"100.25mW",
|
||||||
|
}
|
||||||
|
|
||||||
|
// run the Fib function b.N times
|
||||||
|
for n := 0; n < b.N; n++ {
|
||||||
|
for _, c := range cases {
|
||||||
|
ParseAttribute(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,17 @@
|
||||||
package structs.
|
package structs
|
||||||
|
|
||||||
|
import "sort"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
UnitIndex = make(map[string]*Unit, len(binarySIBytes)+len(decimalSIBytes)+len(binarySIByteRates)+len(decimalSIByteRates)+len(watts)+len(hertz))
|
// numUnits is the number of known units
|
||||||
|
numUnits = len(binarySIBytes) + len(decimalSIBytes) + len(binarySIByteRates) + len(decimalSIByteRates) + len(watts) + len(hertz)
|
||||||
|
|
||||||
|
// UnitIndex is a map of unit name to unit
|
||||||
|
UnitIndex = make(map[string]*Unit, numUnits)
|
||||||
|
|
||||||
|
// lengthSortedUnits is a list of unit names sorted by length with longest
|
||||||
|
// first
|
||||||
|
lengthSortedUnits = make([]string, 0, numUnits)
|
||||||
|
|
||||||
binarySIBytes = []*Unit{
|
binarySIBytes = []*Unit{
|
||||||
&Unit{
|
&Unit{
|
||||||
|
@ -193,6 +203,11 @@ func init() {
|
||||||
for _, units := range [][]*Unit{binarySIBytes, decimalSIBytes, binarySIByteRates, decimalSIByteRates, watts, hertz} {
|
for _, units := range [][]*Unit{binarySIBytes, decimalSIBytes, binarySIByteRates, decimalSIByteRates, watts, hertz} {
|
||||||
for _, unit := range units {
|
for _, unit := range units {
|
||||||
UnitIndex[unit.Name] = unit
|
UnitIndex[unit.Name] = unit
|
||||||
|
lengthSortedUnits = append(lengthSortedUnits, unit.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sort.Slice(lengthSortedUnits, func(i, j int) bool {
|
||||||
|
return len(lengthSortedUnits[i]) >= len(lengthSortedUnits[j])
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package structs
|
package structs
|
||||||
|
|
||||||
import "github.com/hashicorp/nomad/plugins/shared/structs/proto"
|
import (
|
||||||
|
"github.com/hashicorp/nomad/helper"
|
||||||
|
"github.com/hashicorp/nomad/plugins/shared/structs/proto"
|
||||||
|
)
|
||||||
|
|
||||||
func ConvertProtoAttribute(in *proto.Attribute) *Attribute {
|
func ConvertProtoAttribute(in *proto.Attribute) *Attribute {
|
||||||
out := &Attribute{
|
out := &Attribute{
|
||||||
|
@ -9,21 +12,21 @@ func ConvertProtoAttribute(in *proto.Attribute) *Attribute {
|
||||||
|
|
||||||
switch in.Value.(type) {
|
switch in.Value.(type) {
|
||||||
case *proto.Attribute_BoolVal:
|
case *proto.Attribute_BoolVal:
|
||||||
out.Bool = in.GetBoolVal()
|
out.Bool = helper.BoolToPtr(in.GetBoolVal())
|
||||||
case *proto.Attribute_FloatVal:
|
case *proto.Attribute_FloatVal:
|
||||||
out.Float = in.GetFloatVal()
|
out.Float = helper.Float64ToPtr(in.GetFloatVal())
|
||||||
case *proto.Attribute_IntVal:
|
case *proto.Attribute_IntVal:
|
||||||
out.Int = in.GetIntVal()
|
out.Int = helper.Int64ToPtr(in.GetIntVal())
|
||||||
case *proto.Attribute_StringVal:
|
case *proto.Attribute_StringVal:
|
||||||
out.String = in.GetStringVal()
|
out.String = helper.StringToPtr(in.GetStringVal())
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func Pow(a, b uint64) uint64 {
|
func Pow(a, b int64) int64 {
|
||||||
var p uint64 = 1
|
var p int64 = 1
|
||||||
for b > 0 {
|
for b > 0 {
|
||||||
if b&1 != 0 {
|
if b&1 != 0 {
|
||||||
p *= a
|
p *= a
|
||||||
|
|
Loading…
Reference in New Issue