1
0
mirror of https://github.com/MontFerret/ferret.git synced 2024-12-14 11:23:02 +02:00
ferret/pkg/runtime/values/array.go

288 lines
4.5 KiB
Go
Raw Normal View History

2018-09-18 22:42:38 +02:00
package values
import (
"context"
2018-10-05 21:17:22 +02:00
"encoding/binary"
2018-09-18 22:42:38 +02:00
"encoding/json"
"hash/fnv"
"sort"
2018-09-18 22:42:38 +02:00
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
2018-09-18 22:42:38 +02:00
)
type (
ArrayPredicate = func(value core.Value, idx int) bool
2018-10-28 07:45:26 +02:00
ArraySorter = func(first, second core.Value) bool
Array struct {
items []core.Value
2018-09-18 22:42:38 +02:00
}
)
func NewArray(size int) *Array {
2018-10-28 07:45:26 +02:00
return &Array{items: make([]core.Value, 0, size)}
2018-09-18 22:42:38 +02:00
}
func NewArrayWith(values ...core.Value) *Array {
2018-10-28 07:45:26 +02:00
return &Array{items: values}
2018-09-18 22:42:38 +02:00
}
func (t *Array) MarshalJSON() ([]byte, error) {
2018-10-28 07:45:26 +02:00
return json.Marshal(t.items)
2018-09-18 22:42:38 +02:00
}
func (t *Array) Type() core.Type {
return types.Array
2018-09-18 22:42:38 +02:00
}
func (t *Array) String() string {
marshaled, err := t.MarshalJSON()
if err != nil {
return "[]"
}
return string(marshaled)
}
func (t *Array) Compare(other core.Value) int64 {
if other.Type() == types.Array {
other := other.(*Array)
2018-09-18 22:42:38 +02:00
if t.Length() == 0 && other.Length() == 0 {
2018-09-18 22:42:38 +02:00
return 0
}
if t.Length() < other.Length() {
return -1
}
if t.Length() > other.Length() {
return 1
}
2018-09-18 22:42:38 +02:00
var res int64
var val core.Value
2018-09-18 22:42:38 +02:00
other.ForEach(func(otherVal core.Value, idx int) bool {
val = t.Get(NewInt(idx))
res = val.Compare(otherVal)
2018-09-18 22:42:38 +02:00
return res == 0
})
2018-09-18 22:42:38 +02:00
return res
}
return types.Compare(types.Array, other.Type())
2018-09-18 22:42:38 +02:00
}
func (t *Array) Unwrap() interface{} {
arr := make([]interface{}, t.Length())
2018-10-28 07:45:26 +02:00
for idx, val := range t.items {
2018-09-18 22:42:38 +02:00
arr[idx] = val.Unwrap()
}
return arr
}
2018-10-05 21:17:22 +02:00
func (t *Array) Hash() uint64 {
h := fnv.New64a()
2018-09-18 22:42:38 +02:00
2018-10-05 21:17:22 +02:00
h.Write([]byte(t.Type().String()))
h.Write([]byte(":"))
h.Write([]byte("["))
2018-09-18 22:42:38 +02:00
2018-10-28 07:45:26 +02:00
endIndex := len(t.items) - 1
2018-09-18 22:42:38 +02:00
2018-10-28 07:45:26 +02:00
for i, el := range t.items {
2018-10-05 21:17:22 +02:00
bytes := make([]byte, 8)
binary.LittleEndian.PutUint64(bytes, el.Hash())
2018-09-18 22:42:38 +02:00
2018-10-05 21:17:22 +02:00
h.Write(bytes)
if i != endIndex {
h.Write([]byte(","))
}
2018-09-18 22:42:38 +02:00
}
2018-10-05 21:17:22 +02:00
h.Write([]byte("]"))
return h.Sum64()
2018-09-18 22:42:38 +02:00
}
func (t *Array) Copy() core.Value {
2018-10-28 07:45:26 +02:00
c := NewArray(len(t.items))
2018-09-27 17:53:26 +02:00
2018-10-28 07:45:26 +02:00
for _, el := range t.items {
2018-09-27 17:53:26 +02:00
c.Push(el)
}
return c
}
2018-09-18 22:42:38 +02:00
func (t *Array) Length() Int {
2018-10-28 07:45:26 +02:00
return Int(len(t.items))
2018-09-18 22:42:38 +02:00
}
func (t *Array) ForEach(predicate ArrayPredicate) {
2018-10-28 07:45:26 +02:00
for idx, val := range t.items {
if !predicate(val, idx) {
2018-09-18 22:42:38 +02:00
break
}
}
}
func (t *Array) Find(predicate ArrayPredicate) (core.Value, Boolean) {
for idx, val := range t.items {
if predicate(val, idx) {
return val, True
}
}
return None, False
}
2018-09-18 22:42:38 +02:00
func (t *Array) Get(idx Int) core.Value {
2018-10-28 07:45:26 +02:00
l := len(t.items) - 1
2018-09-18 22:42:38 +02:00
if l < 0 {
return None
}
2018-09-18 22:42:38 +02:00
if int(idx) > l {
return None
}
2018-10-28 07:45:26 +02:00
return t.items[idx]
2018-09-18 22:42:38 +02:00
}
func (t *Array) Set(idx Int, value core.Value) error {
2018-10-28 07:45:26 +02:00
last := len(t.items) - 1
2018-09-18 22:42:38 +02:00
if last >= int(idx) {
2018-10-28 07:45:26 +02:00
t.items[idx] = value
2018-09-18 22:42:38 +02:00
return nil
}
2018-10-28 07:45:26 +02:00
return core.Error(core.ErrInvalidOperation, "out of bounds")
2018-09-18 22:42:38 +02:00
}
func (t *Array) Push(item core.Value) {
2018-10-28 07:45:26 +02:00
t.items = append(t.items, item)
2018-09-18 22:42:38 +02:00
}
func (t *Array) Slice(from, to Int) *Array {
length := t.Length()
if from >= length {
return NewArray(0)
}
if to > length {
to = length
}
result := new(Array)
2018-10-28 07:45:26 +02:00
result.items = t.items[from:to]
return result
2018-09-18 22:42:38 +02:00
}
2018-09-23 03:06:19 +02:00
func (t *Array) IndexOf(item core.Value) Int {
res := Int(-1)
2018-10-28 07:45:26 +02:00
for idx, el := range t.items {
2018-09-23 03:06:19 +02:00
if el.Compare(item) == 0 {
res = Int(idx)
break
}
}
return res
}
2018-09-27 06:26:56 +02:00
func (t *Array) Insert(idx Int, value core.Value) {
2018-10-28 07:45:26 +02:00
t.items = append(t.items[:idx], append([]core.Value{value}, t.items[idx:]...)...)
2018-09-27 06:26:56 +02:00
}
func (t *Array) RemoveAt(idx Int) {
i := int(idx)
2018-10-28 07:45:26 +02:00
max := len(t.items) - 1
2018-09-27 06:26:56 +02:00
if i > max {
return
}
2018-10-28 07:45:26 +02:00
t.items = append(t.items[:i], t.items[i+1:]...)
2018-09-27 06:26:56 +02:00
}
func (t *Array) Clone() core.Cloneable {
cloned := NewArray(0)
var value core.Value
for idx := NewInt(0); idx < t.Length(); idx++ {
value = t.Get(idx)
cloneable, ok := value.(core.Cloneable)
if ok {
value = cloneable.Clone()
}
cloned.Push(value)
}
return cloned
}
func (t *Array) Sort() *Array {
2018-10-28 07:45:26 +02:00
return t.SortWith(func(first, second core.Value) bool {
return first.Compare(second) == -1
})
}
func (t *Array) SortWith(sorter ArraySorter) *Array {
c := make([]core.Value, len(t.items))
copy(c, t.items)
sort.SliceStable(c, func(i, j int) bool {
2018-10-28 07:45:26 +02:00
return sorter(c[i], c[j])
})
res := new(Array)
2018-10-28 07:45:26 +02:00
res.items = c
return res
}
func (t *Array) GetIn(ctx context.Context, path []core.Value) (core.Value, error) {
if len(path) == 0 {
return None, nil
}
if typ := path[0].Type(); typ != types.Int {
return None, core.TypeError(typ, types.Int)
}
first := t.Get(path[0].(Int))
if len(path) == 1 {
return first, nil
}
getter, ok := first.(core.Getter)
if !ok {
return None, core.TypeError(
first.Type(),
core.NewType("Getter"),
)
}
return getter.GetIn(ctx, path[1:])
}