Skip to content

Commit

Permalink
feat: add primitive compare
Browse files Browse the repository at this point in the history
  • Loading branch information
siyul-park committed Nov 24, 2023
1 parent 2b97aa7 commit 864b33f
Show file tree
Hide file tree
Showing 17 changed files with 459 additions and 8 deletions.
26 changes: 26 additions & 0 deletions pkg/primitive/binary.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,32 @@ func (o Binary) Equal(v Object) bool {
}
}

func (o Binary) Compare(v Object) int {
if r, ok := v.(Binary); !ok {
if o.Kind() > v.Kind() {
return 1
} else {
return -1
}
} else {
for i := 0; i < o.Len(); i++ {
if r.Len() == i {
return 1
}

v1 := o.Get(i)
v2 := r.Get(i)

if v1 > v2 {
return 1
} else if v1 < v2 {
return -1
}
}
return 0
}
}

func (o Binary) Hash() uint32 {
h := fnv.New32()
h.Write([]byte{byte(KindBinary), 0})
Expand Down
18 changes: 12 additions & 6 deletions pkg/primitive/binary_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,19 @@ func TestBinary_Get(t *testing.T) {

func TestBinary_Equal(t *testing.T) {
v1 := NewBinary([]byte{0})
v2 := NewBinary([]byte{0})
v3 := NewBinary([]byte{1})
v2 := NewBinary([]byte{1})

assert.True(t, v1.Equal(v2))
assert.True(t, v2.Equal(v1))
assert.False(t, v1.Equal(v3))
assert.False(t, v2.Equal(v3))
assert.True(t, v1.Equal(v1))
assert.False(t, v1.Equal(v2))
}

func TestBinary_Compare(t *testing.T) {
v1 := NewBinary([]byte{0})
v2 := NewBinary([]byte{1})

assert.Equal(t, 0, v1.Compare(v1))
assert.Equal(t, -1, v1.Compare(v2))
assert.Equal(t, 1, v2.Compare(v1))
}

func TestBinary_Hash(t *testing.T) {
Expand Down
16 changes: 16 additions & 0 deletions pkg/primitive/bool.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,22 @@ func (o Bool) Equal(v Object) bool {
}
}

func (o Bool) Compare(v Object) int {
if r, ok := v.(Bool); !ok {
if o.Kind() > v.Kind() {
return 1
} else {
return -1
}
} else if o == r {
return 0
} else if o == TRUE {
return 1
} else {
return -1
}
}

func (o Bool) Hash() uint32 {
var v byte
if o {
Expand Down
7 changes: 7 additions & 0 deletions pkg/primitive/bool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ func TestNewBool(t *testing.T) {
assert.Equal(t, true, v.Interface())
}

func TestBool_Compare(t *testing.T) {
assert.Equal(t, 0, TRUE.Compare(TRUE))
assert.Equal(t, 0, FALSE.Compare(FALSE))
assert.Equal(t, 1, TRUE.Compare(FALSE))
assert.Equal(t, -1, FALSE.Compare(TRUE))
}

func TestBool_Equal(t *testing.T) {
assert.True(t, TRUE.Equal(TRUE))
assert.True(t, FALSE.Equal(FALSE))
Expand Down
20 changes: 20 additions & 0 deletions pkg/primitive/compare.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package primitive

type (
ordered interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64 | ~string
}
)

func compare[T ordered](x, y T) int {
if x == y {
return 0
}
if x > y {
return 1
}
if x < y {
return -1
}
return 0
}
32 changes: 32 additions & 0 deletions pkg/primitive/float.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,22 @@ func (o Float32) Equal(v Object) bool {
}
}

func (o Float32) Compare(v Object) int {
if r, ok := v.(Float); !ok {
if r, ok := v.(Integer); ok {
return compare[float64](o.Float(), float64(r.Int()))
} else if r, ok := v.(Uinteger); ok {
return compare[float64](o.Float(), float64(r.Uint()))
} else if o.Kind() > v.Kind() {
return 1
} else {
return -1
}
} else {
return compare[float64](o.Float(), r.Float())
}
}

func (o Float32) Hash() uint32 {
var buf [4]byte
binary.BigEndian.PutUint32(buf[:], math.Float32bits(float32(o)))
Expand Down Expand Up @@ -95,6 +111,22 @@ func (o Float64) Equal(v Object) bool {
}
}

func (o Float64) Compare(v Object) int {
if r, ok := v.(Float); !ok {
if r, ok := v.(Integer); ok {
return compare[float64](o.Float(), float64(r.Int()))
} else if r, ok := v.(Uinteger); ok {
return compare[float64](o.Float(), float64(r.Uint()))
} else if o.Kind() > v.Kind() {
return 1
} else {
return -1
}
} else {
return compare[float64](o.Float(), r.Float())
}
}

func (o Float64) Hash() uint32 {
var buf [8]byte
binary.BigEndian.PutUint64(buf[:], math.Float64bits(float64(o)))
Expand Down
18 changes: 17 additions & 1 deletion pkg/primitive/float_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func TestFloat_Equal(t *testing.T) {
t.Run("32", func(t *testing.T) {
assert.True(t, NewFloat32(0).Equal(NewFloat32(0)))
assert.True(t, NewFloat32(0).Equal(NewFloat64(0)))
assert.False(t, NewFloat32(0).Equal(NewFloat32(1)))
assert.False(t, NewFloat32(1).Equal(NewFloat32(0)))
})

t.Run("64", func(t *testing.T) {
Expand All @@ -35,6 +35,22 @@ func TestFloat_Equal(t *testing.T) {
})
}

func TestFloat_Compare(t *testing.T) {
t.Run("32", func(t *testing.T) {
assert.Equal(t, 0, NewFloat32(0).Compare(NewFloat32(0)))
assert.Equal(t, 0, NewFloat32(0).Compare(NewFloat64(0)))
assert.Equal(t, 1, NewFloat32(1).Compare(NewFloat32(0)))
assert.Equal(t, -1, NewFloat32(0).Compare(NewFloat32(1)))
})

t.Run("64", func(t *testing.T) {
assert.Equal(t, 0, NewFloat64(0).Compare(NewFloat64(0)))
assert.Equal(t, 0, NewFloat64(0).Compare(NewFloat32(0)))
assert.Equal(t, 1, NewFloat64(1).Compare(NewFloat64(0)))
assert.Equal(t, -1, NewFloat64(0).Compare(NewFloat64(1)))
})
}

func TestFloat_Hash(t *testing.T) {
t.Run("32", func(t *testing.T) {
assert.NotEqual(t, NewFloat32(0).Hash(), NewFloat32(1).Hash())
Expand Down
80 changes: 80 additions & 0 deletions pkg/primitive/int.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,22 @@ func (o Int) Equal(v Object) bool {
}
}

func (o Int) Compare(v Object) int {
if r, ok := v.(Integer); !ok {
if r, ok := v.(Uinteger); ok {
return compare[int64](o.Int(), int64(r.Uint()))
} else if r, ok := v.(Float); ok {
return compare[float64](float64(o.Int()), r.Float())
} else if o.Kind() > v.Kind() {
return 1
} else {
return -1
}
} else {
return compare[int64](o.Int(), r.Int())
}
}

func (o Int) Hash() uint32 {
buf := *(*[unsafe.Sizeof(o)]byte)(unsafe.Pointer(&o))

Expand Down Expand Up @@ -102,6 +118,22 @@ func (o Int8) Equal(v Object) bool {
}
}

func (o Int8) Compare(v Object) int {
if r, ok := v.(Integer); !ok {
if r, ok := v.(Uinteger); ok {
return compare[int64](o.Int(), int64(r.Uint()))
} else if r, ok := v.(Float); ok {
return compare[float64](float64(o.Int()), r.Float())
} else if o.Kind() > v.Kind() {
return 1
} else {
return -1
}
} else {
return compare[int64](o.Int(), r.Int())
}
}

func (o Int8) Hash() uint32 {
buf := *(*[unsafe.Sizeof(o)]byte)(unsafe.Pointer(&o))

Expand Down Expand Up @@ -144,6 +176,22 @@ func (o Int16) Equal(v Object) bool {
}
}

func (o Int16) Compare(v Object) int {
if r, ok := v.(Integer); !ok {
if r, ok := v.(Uinteger); ok {
return compare[int64](o.Int(), int64(r.Uint()))
} else if r, ok := v.(Float); ok {
return compare[float64](float64(o.Int()), r.Float())
} else if o.Kind() > v.Kind() {
return 1
} else {
return -1
}
} else {
return compare[int64](o.Int(), r.Int())
}
}

func (o Int16) Hash() uint32 {
buf := *(*[unsafe.Sizeof(o)]byte)(unsafe.Pointer(&o))

Expand Down Expand Up @@ -186,6 +234,22 @@ func (o Int32) Equal(v Object) bool {
}
}

func (o Int32) Compare(v Object) int {
if r, ok := v.(Integer); !ok {
if r, ok := v.(Uinteger); ok {
return compare[int64](o.Int(), int64(r.Uint()))
} else if r, ok := v.(Float); ok {
return compare[float64](float64(o.Int()), r.Float())
} else if o.Kind() > v.Kind() {
return 1
} else {
return -1
}
} else {
return compare[int64](o.Int(), r.Int())
}
}

func (o Int32) Hash() uint32 {
buf := *(*[unsafe.Sizeof(o)]byte)(unsafe.Pointer(&o))

Expand Down Expand Up @@ -228,6 +292,22 @@ func (o Int64) Equal(v Object) bool {
}
}

func (o Int64) Compare(v Object) int {
if r, ok := v.(Integer); !ok {
if r, ok := v.(Uinteger); ok {
return compare[int64](o.Int(), int64(r.Uint()))
} else if r, ok := v.(Float); ok {
return compare[float64](float64(o.Int()), r.Float())
} else if o.Kind() > v.Kind() {
return 1
} else {
return -1
}
} else {
return compare[int64](o.Int(), r.Int())
}
}

func (o Int64) Hash() uint32 {
buf := *(*[unsafe.Sizeof(o)]byte)(unsafe.Pointer(&o))

Expand Down
33 changes: 33 additions & 0 deletions pkg/primitive/int_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,39 @@ func TestInt_Equal(t *testing.T) {
})
}

func TestInt_Compare(t *testing.T) {
t.Run("", func(t *testing.T) {
assert.Equal(t, 0, NewInt(0).Compare(NewInt(0)))
assert.Equal(t, 1, NewInt(1).Compare(NewInt(0)))
assert.Equal(t, -1, NewInt(0).Compare(NewInt(1)))
assert.Equal(t, 0, NewInt(0).Compare(NewFloat32(0)))
})
t.Run("8", func(t *testing.T) {
assert.Equal(t, 0, NewInt8(0).Compare(NewInt(0)))
assert.Equal(t, 1, NewInt8(1).Compare(NewInt(0)))
assert.Equal(t, -1, NewInt8(0).Compare(NewInt(1)))
assert.Equal(t, 0, NewInt8(0).Compare(NewFloat32(0)))
})
t.Run("16", func(t *testing.T) {
assert.Equal(t, 0, NewInt16(0).Compare(NewInt(0)))
assert.Equal(t, 1, NewInt16(1).Compare(NewInt(0)))
assert.Equal(t, -1, NewInt16(0).Compare(NewInt(1)))
assert.Equal(t, 0, NewInt16(0).Compare(NewFloat32(0)))
})
t.Run("32", func(t *testing.T) {
assert.Equal(t, 0, NewInt32(0).Compare(NewInt(0)))
assert.Equal(t, 1, NewInt32(1).Compare(NewInt(0)))
assert.Equal(t, -1, NewInt32(0).Compare(NewInt(1)))
assert.Equal(t, 0, NewInt32(0).Compare(NewFloat32(0)))
})
t.Run("64", func(t *testing.T) {
assert.Equal(t, 0, NewInt64(0).Compare(NewInt(0)))
assert.Equal(t, 1, NewInt64(1).Compare(NewInt(0)))
assert.Equal(t, -1, NewInt64(0).Compare(NewInt(1)))
assert.Equal(t, 0, NewInt64(0).Compare(NewFloat32(0)))
})
}

func TestInt_Hash(t *testing.T) {
t.Run("", func(t *testing.T) {
assert.NotEqual(t, NewInt(0).Hash(), NewInt(1).Hash())
Expand Down
38 changes: 38 additions & 0 deletions pkg/primitive/map.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,44 @@ func (o *Map) Equal(v Object) bool {
}
}

func (o *Map) Compare(v Object) int {
if r, ok := v.(*Map); !ok {
if o.Kind() > v.Kind() {
return 1
} else {
return -1
}
} else {
keys1 := o.Keys()
keys2 := r.Keys()

for i, k1 := range keys1 {
if len(keys2) == i {
return 1
}

k2 := keys2[i]
if diff := Compare(k1, k2); diff != 0 {
return diff
}

v1, ok1 := o.Get(k1)
v2, ok2 := o.Get(k2)
if diff := Compare(NewBool(ok1), NewBool(ok2)); diff != 0 {
return diff
}
if diff := Compare(v1, v2); diff != 0 {
return diff
}
}

if len(keys2) > len(keys1) {
return -1
}
return 0
}
}

func (o *Map) Hash() uint32 {
h := fnv.New32()
h.Write([]byte{byte(KindMap), 0})
Expand Down
Loading

0 comments on commit 864b33f

Please sign in to comment.