Skip to content

Commit

Permalink
Merge pull request #128 from jennybuckley/fix-1.0-compare
Browse files Browse the repository at this point in the history
Cherrypick #126 to 1.0 - Implement equality for Values
  • Loading branch information
k8s-ci-robot authored Nov 11, 2019
2 parents 6149e45 + 08cde4d commit 442c558
Show file tree
Hide file tree
Showing 2 changed files with 191 additions and 51 deletions.
16 changes: 16 additions & 0 deletions value/less_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,9 @@ func TestValueLess(t *testing.T) {
t.Run(table[i].name, func(t *testing.T) {
tt := table[i]
if tt.eq {
if !tt.a.Equals(tt.b) {
t.Errorf("oops, a != b: %#v, %#v", tt.a, tt.b)
}
if tt.a.Less(tt.b) {
t.Errorf("oops, a < b: %#v, %#v", tt.a, tt.b)
}
Expand All @@ -307,6 +310,19 @@ func TestValueLess(t *testing.T) {
if tt.b.Less(tt.b) {
t.Errorf("oops, b < a: %#v, %#v", tt.b, tt.a)
}

if tt.eq {
if tt.a.Compare(tt.b) != 0 || tt.b.Compare(tt.b) != 0 {
t.Errorf("oops, a != b: %#v, %#v", tt.a, tt.b)
}
} else {
if !(tt.a.Compare(tt.b) < 0) {
t.Errorf("oops, a is not less than b: %#v, %#v", tt.a, tt.b)
}
if !(tt.b.Compare(tt.a) > 0) {
t.Errorf("oops, b is not more than a: %#v, %#v", tt.a, tt.b)
}
}
})
}

Expand Down
226 changes: 175 additions & 51 deletions value/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,93 +36,186 @@ type Value struct {

// Equals returns true iff the two values are equal.
func (v Value) Equals(rhs Value) bool {
return !v.Less(rhs) && !rhs.Less(v)
if v.FloatValue != nil || rhs.FloatValue != nil {
var lf float64
if v.FloatValue != nil {
lf = float64(*v.FloatValue)
} else if v.IntValue != nil {
lf = float64(*v.IntValue)
} else {
return false
}
var rf float64
if rhs.FloatValue != nil {
rf = float64(*rhs.FloatValue)
} else if rhs.IntValue != nil {
rf = float64(*rhs.IntValue)
} else {
return false
}
return lf == rf
}
if v.IntValue != nil {
if rhs.IntValue != nil {
return *v.IntValue == *rhs.IntValue
}
return false
}
if v.StringValue != nil {
if rhs.StringValue != nil {
return *v.StringValue == *rhs.StringValue
}
return false
}
if v.BooleanValue != nil {
if rhs.BooleanValue != nil {
return *v.BooleanValue == *rhs.BooleanValue
}
return false
}
if v.ListValue != nil {
if rhs.ListValue != nil {
return v.ListValue.Equals(rhs.ListValue)
}
return false
}
if v.MapValue != nil {
if rhs.MapValue != nil {
return v.MapValue.Equals(rhs.MapValue)
}
return false
}
if v.Null {
if rhs.Null {
return true
}
return false
}
// No field is set, on either objects.
return true
}

// Less provides a total ordering for Value (so that they can be sorted, even
// if they are of different types).
func (v Value) Less(rhs Value) bool {
return v.Compare(rhs) == -1
}

// Compare provides a total ordering for Value (so that they can be
// sorted, even if they are of different types). The result will be 0 if
// v==rhs, -1 if v < rhs, and +1 if v > rhs.
func (v Value) Compare(rhs Value) int {
if v.FloatValue != nil {
if rhs.FloatValue == nil {
// Extra: compare floats and ints numerically.
if rhs.IntValue != nil {
return float64(*v.FloatValue) < float64(*rhs.IntValue)
return v.FloatValue.Compare(Float(*rhs.IntValue))
}
return true
return -1
}
return *v.FloatValue < *rhs.FloatValue
return v.FloatValue.Compare(*rhs.FloatValue)
} else if rhs.FloatValue != nil {
// Extra: compare floats and ints numerically.
if v.IntValue != nil {
return float64(*v.IntValue) < float64(*rhs.FloatValue)
return Float(*v.IntValue).Compare(*rhs.FloatValue)
}
return false
return 1
}

if v.IntValue != nil {
if rhs.IntValue == nil {
return true
return -1
}
return *v.IntValue < *rhs.IntValue
return v.IntValue.Compare(*rhs.IntValue)
} else if rhs.IntValue != nil {
return false
return 1
}

if v.StringValue != nil {
if rhs.StringValue == nil {
return true
return -1
}
return *v.StringValue < *rhs.StringValue
return strings.Compare(string(*v.StringValue), string(*rhs.StringValue))
} else if rhs.StringValue != nil {
return false
return 1
}

if v.BooleanValue != nil {
if rhs.BooleanValue == nil {
return true
return -1
}
if *v.BooleanValue == *rhs.BooleanValue {
return false
}
return *v.BooleanValue == false
return v.BooleanValue.Compare(*rhs.BooleanValue)
} else if rhs.BooleanValue != nil {
return false
return 1
}

if v.ListValue != nil {
if rhs.ListValue == nil {
return true
return -1
}
return v.ListValue.Less(rhs.ListValue)
return v.ListValue.Compare(rhs.ListValue)
} else if rhs.ListValue != nil {
return false
return 1
}
if v.MapValue != nil {
if rhs.MapValue == nil {
return true
return -1
}
return v.MapValue.Less(rhs.MapValue)
return v.MapValue.Compare(rhs.MapValue)
} else if rhs.MapValue != nil {
return false
return 1
}
if v.Null {
if !rhs.Null {
return true
return -1
}
return false
return 0
} else if rhs.Null {
return false
return 1
}

// Invalid Value-- nothing is set.
return false
return 0
}

type Int int64
type Float float64
type String string
type Boolean bool

// Compare compares integers. The result will be 0 if i==rhs, -1 if i <
// rhs, and +1 if i > rhs.
func (i Int) Compare(rhs Int) int {
if i > rhs {
return 1
} else if i < rhs {
return -1
}
return 0
}

// Compare compares floats. The result will be 0 if f==rhs, -1 if f <
// rhs, and +1 if f > rhs.
func (f Float) Compare(rhs Float) int {
if f > rhs {
return 1
} else if f < rhs {
return -1
}
return 0
}

// Compare compares booleans. The result will be 0 if b==rhs, -1 if b <
// rhs, and +1 if b > rhs.
func (b Boolean) Compare(rhs Boolean) int {
if b == rhs {
return 0
} else if b == false {
return -1
}
return 1
}

// Field is an individual key-value pair.
type Field struct {
Name string
Expand All @@ -134,29 +227,44 @@ type List struct {
Items []Value
}

// Equals compares two lists lexically.
func (l *List) Equals(rhs *List) bool {
if len(l.Items) != len(rhs.Items) {
return false
}

for i, lv := range l.Items {
if !lv.Equals(rhs.Items[i]) {
return false
}
}
return true
}

// Less compares two lists lexically.
func (l *List) Less(rhs *List) bool {
return l.Compare(rhs) == -1
}

// Compare compares two lists lexically. The result will be 0 if l==rhs, -1
// if l < rhs, and +1 if l > rhs.
func (l *List) Compare(rhs *List) int {
i := 0
for {
if i >= len(l.Items) && i >= len(rhs.Items) {
// Lists are the same length and all items are equal.
return false
return 0
}
if i >= len(l.Items) {
// LHS is shorter.
return true
return -1
}
if i >= len(rhs.Items) {
// RHS is shorter.
return false
return 1
}
if l.Items[i].Less(rhs.Items[i]) {
// LHS is less; return
return true
}
if rhs.Items[i].Less(l.Items[i]) {
// RHS is less; return
return false
if c := l.Items[i].Compare(rhs.Items[i]); c != 0 {
return c
}
// The items are equal; continue.
i++
Expand Down Expand Up @@ -191,8 +299,30 @@ func (m *Map) computeOrder() []int {
return m.order
}

// Equals compares two maps lexically.
func (m *Map) Equals(rhs *Map) bool {
if len(m.Items) != len(rhs.Items) {
return false
}
for _, lfield := range m.Items {
rfield, ok := rhs.Get(lfield.Name)
if !ok {
return false
}
if !lfield.Value.Equals(rfield.Value) {
return false
}
}
return true
}

// Less compares two maps lexically.
func (m *Map) Less(rhs *Map) bool {
return m.Compare(rhs) == -1
}

// Compare compares two maps lexically.
func (m *Map) Compare(rhs *Map) int {
var noAllocL, noAllocR [2]int
var morder, rorder []int

Expand Down Expand Up @@ -238,28 +368,22 @@ func (m *Map) Less(rhs *Map) bool {
for {
if i >= len(morder) && i >= len(rorder) {
// Maps are the same length and all items are equal.
return false
return 0
}
if i >= len(morder) {
// LHS is shorter.
return true
return -1
}
if i >= len(rorder) {
// RHS is shorter.
return false
return 1
}
fa, fb := &m.Items[morder[i]], &rhs.Items[rorder[i]]
if fa.Name != fb.Name {
// the map having the field name that sorts lexically less is "less"
return fa.Name < fb.Name
if c := strings.Compare(fa.Name, fb.Name); c != 0 {
return c
}
if fa.Value.Less(fb.Value) {
// LHS is less; return
return true
}
if fb.Value.Less(fa.Value) {
// RHS is less; return
return false
if c := fa.Value.Compare(fb.Value); c != 0 {
return c
}
// The items are equal; continue.
i++
Expand Down

0 comments on commit 442c558

Please sign in to comment.