Skip to content

Commit

Permalink
feat: add equal in primitive
Browse files Browse the repository at this point in the history
  • Loading branch information
siyul-park committed Nov 24, 2023
1 parent 41f5a0e commit b4cc614
Show file tree
Hide file tree
Showing 17 changed files with 380 additions and 21 deletions.
15 changes: 15 additions & 0 deletions pkg/primitive/binary.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,21 @@ func (o Binary) Kind() Kind {
return KindBinary
}

func (o Binary) Equal(v Object) bool {
if r, ok := v.(Binary); !ok {
return false
} else if r.Len() != o.Len() {
return false
} else {
for i := 0; i < o.Len(); i++ {
if o.Get(i) != r.Get(i) {
return false
}
}
return true
}
}

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

func TestBinary_Hash(t *testing.T) {
assert.NotEqual(t, NewBinary([]byte{0}).Hash(), NewBinary([]byte{1}).Hash())
assert.Equal(t, NewBinary(nil).Hash(), NewBinary(nil).Hash())
assert.Equal(t, NewBinary([]byte{0}).Hash(), NewBinary([]byte{0}).Hash())
}

func TestBinary_Get(t *testing.T) {
v := NewBinary([]byte{0})

assert.Equal(t, 1, v.Len())
assert.Equal(t, byte(0), v.Get(0))
}

func TestBinary_Equal(t *testing.T) {
v1 := NewBinary([]byte{0})
v2 := NewBinary([]byte{0})
v3 := 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))
}

func TestBinary_Hash(t *testing.T) {
assert.NotEqual(t, NewBinary([]byte{0}).Hash(), NewBinary([]byte{1}).Hash())
assert.Equal(t, NewBinary(nil).Hash(), NewBinary(nil).Hash())
assert.Equal(t, NewBinary([]byte{0}).Hash(), NewBinary([]byte{0}).Hash())
}

func TestBinary_Encode(t *testing.T) {
e := NewBinaryEncoder()

Expand Down
8 changes: 8 additions & 0 deletions pkg/primitive/bool.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ func (o Bool) Kind() Kind {
return KindBool
}

func (o Bool) Equal(v Object) bool {
if r, ok := v.(Bool); !ok {
return false
} else {
return o.Bool() == r.Bool()
}
}

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_Equal(t *testing.T) {
assert.True(t, TRUE.Equal(TRUE))
assert.True(t, FALSE.Equal(FALSE))
assert.False(t, TRUE.Equal(FALSE))
assert.False(t, FALSE.Equal(TRUE))
}

func TestBool_Hash(t *testing.T) {
assert.NotEqual(t, TRUE.Hash(), FALSE.Hash())
assert.Equal(t, TRUE.Hash(), TRUE.Hash())
Expand Down
28 changes: 28 additions & 0 deletions pkg/primitive/float.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,20 @@ func (o Float32) Kind() Kind {
return KindFloat32
}

func (o Float32) Equal(v Object) bool {
if r, ok := v.(Float); !ok {
if r, ok := v.(Integer); ok {
return o.Float() == float64(r.Int())
} else if r, ok := v.(Uinteger); ok {
return o.Float() == float64(r.Uint())
} else {
return false
}
} else {
return 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 @@ -67,6 +81,20 @@ func (o Float64) Kind() Kind {
return KindFloat64
}

func (o Float64) Equal(v Object) bool {
if r, ok := v.(Float); !ok {
if r, ok := v.(Integer); ok {
return o.Float() == float64(r.Int())
} else if r, ok := v.(Uinteger); ok {
return o.Float() == float64(r.Uint())
} else {
return false
}
} else {
return o.Float() == r.Float()
}
}

func (o Float64) Hash() uint32 {
var buf [8]byte
binary.BigEndian.PutUint64(buf[:], math.Float64bits(float64(o)))
Expand Down
14 changes: 14 additions & 0 deletions pkg/primitive/float_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,20 @@ func TestNewFloat(t *testing.T) {
})
}

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)))
})

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

func TestFloat_Hash(t *testing.T) {
t.Run("32", func(t *testing.T) {
assert.NotEqual(t, NewFloat32(0).Hash(), NewFloat32(1).Hash())
Expand Down
70 changes: 70 additions & 0 deletions pkg/primitive/int.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ func (o Int) Kind() Kind {
return KindInt
}

func (o Int) Equal(v Object) bool {
if r, ok := v.(Integer); !ok {
if r, ok := v.(Uinteger); ok {
return o.Int() == int64(r.Uint())
} else if r, ok := v.(Float); ok {
return float64(o.Int()) == r.Float()
} else {
return false
}
} else {
return o.Int() == r.Int()
}
}

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

Expand Down Expand Up @@ -74,6 +88,20 @@ func (o Int8) Kind() Kind {
return KindInt8
}

func (o Int8) Equal(v Object) bool {
if r, ok := v.(Integer); !ok {
if r, ok := v.(Uinteger); ok {
return o.Int() == int64(r.Uint())
} else if r, ok := v.(Float); ok {
return float64(o.Int()) == r.Float()
} else {
return false
}
} else {
return o.Int() == r.Int()
}
}

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

Expand Down Expand Up @@ -102,6 +130,20 @@ func (o Int16) Kind() Kind {
return KindInt16
}

func (o Int16) Equal(v Object) bool {
if r, ok := v.(Integer); !ok {
if r, ok := v.(Uinteger); ok {
return o.Int() == int64(r.Uint())
} else if r, ok := v.(Float); ok {
return float64(o.Int()) == r.Float()
} else {
return false
}
} else {
return o.Int() == r.Int()
}
}

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

Expand Down Expand Up @@ -130,6 +172,20 @@ func (o Int32) Kind() Kind {
return KindInt32
}

func (o Int32) Equal(v Object) bool {
if r, ok := v.(Integer); !ok {
if r, ok := v.(Uinteger); ok {
return o.Int() == int64(r.Uint())
} else if r, ok := v.(Float); ok {
return float64(o.Int()) == r.Float()
} else {
return false
}
} else {
return o.Int() == r.Int()
}
}

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

Expand Down Expand Up @@ -158,6 +214,20 @@ func (o Int64) Kind() Kind {
return KindInt64
}

func (o Int64) Equal(v Object) bool {
if r, ok := v.(Integer); !ok {
if r, ok := v.(Uinteger); ok {
return o.Int() == int64(r.Uint())
} else if r, ok := v.(Float); ok {
return float64(o.Int()) == r.Float()
} else {
return false
}
} else {
return o.Int() == r.Int()
}
}

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

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

func TestInt_Equal(t *testing.T) {
t.Run("", func(t *testing.T) {
assert.True(t, NewInt(0).Equal(NewInt(0)))
assert.False(t, NewInt(0).Equal(NewInt(1)))
assert.True(t, NewInt(0).Equal(NewFloat32(0)))
})
t.Run("8", func(t *testing.T) {
assert.True(t, NewInt8(0).Equal(NewInt(0)))
assert.False(t, NewInt8(0).Equal(NewInt(1)))
assert.True(t, NewInt8(0).Equal(NewFloat32(0)))
})
t.Run("16", func(t *testing.T) {
assert.True(t, NewInt16(0).Equal(NewInt(0)))
assert.False(t, NewInt16(0).Equal(NewInt(1)))
assert.True(t, NewInt16(0).Equal(NewFloat32(0)))
})
t.Run("32", func(t *testing.T) {
assert.True(t, NewInt32(0).Equal(NewInt(0)))
assert.False(t, NewInt32(0).Equal(NewInt(1)))
assert.True(t, NewInt32(0).Equal(NewFloat32(0)))
})
t.Run("64", func(t *testing.T) {
assert.True(t, NewInt64(0).Equal(NewInt(0)))
assert.False(t, NewInt64(0).Equal(NewInt(1)))
assert.True(t, NewInt64(0).Equal(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
32 changes: 32 additions & 0 deletions pkg/primitive/map.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,38 @@ func (o *Map) Kind() Kind {
return KindMap
}

func (o *Map) Equal(v Object) bool {
if r, ok := v.(*Map); !ok {
return false
} else if o.Len() != r.Len() {
return false
} else {
keys1 := o.Keys()
keys2 := r.Keys()

for i, k1 := range keys1 {
k2 := keys2[i]
if k1 != k2 {
return false
}

v1, ok1 := o.Get(k1)
v2, ok2 := o.Get(k2)
if ok1 != ok2 {
return false
}
if !ok1 || !ok2 {
continue
}
if !v1.Equal(v2) {
return false
}
}

return true
}
}

func (o *Map) Hash() uint32 {
h := fnv.New32()
h.Write([]byte{byte(KindMap), 0})
Expand Down
10 changes: 10 additions & 0 deletions pkg/primitive/map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ func TestNewMap(t *testing.T) {
assert.Equal(t, map[string]string{k1.String(): v1.String()}, o.Interface())
}

func TestMap_Equal(t *testing.T) {
k1 := NewString(faker.Word())
k2 := NewString(faker.Word())
v1 := NewString(faker.Word())
v2 := NewString(faker.Word())

assert.True(t, NewMap(k1, v1).Equal(NewMap(k2, v2)))
assert.False(t, NewMap(k1, v1).Equal(NewMap(k1, v1)))
}

func TestMap_Hash(t *testing.T) {
k1 := NewString(faker.Word())
k2 := NewString(faker.Word())
Expand Down
1 change: 1 addition & 0 deletions pkg/primitive/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ type (
// Object is an atomic type.
Object interface {
Kind() Kind
Equal(v Object) bool
Hash() uint32
Interface() any
}
Expand Down
15 changes: 15 additions & 0 deletions pkg/primitive/slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,21 @@ func (o *Slice) Kind() Kind {
return KindSlice
}

func (o *Slice) Equal(v Object) bool {
if r, ok := v.(*Slice); !ok {
return false
} else if o.Len() != r.Len() {
return false
} else {
for i := 0; i < o.Len(); i++ {
if !o.Get(i).Equal(r.Get(i)) {
return false
}
}
return true
}
}

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

0 comments on commit b4cc614

Please sign in to comment.