github.com/MontFerret/ferret@v0.18.0/pkg/runtime/values/array.go (about) 1 package values 2 3 import ( 4 "context" 5 "encoding/binary" 6 "hash/fnv" 7 "sort" 8 9 "github.com/wI2L/jettison" 10 11 "github.com/MontFerret/ferret/pkg/runtime/core" 12 "github.com/MontFerret/ferret/pkg/runtime/values/types" 13 ) 14 15 type ( 16 ArrayPredicate = func(value core.Value, idx int) bool 17 18 ArraySorter = func(first, second core.Value) bool 19 20 Array struct { 21 items []core.Value 22 } 23 ) 24 25 func EmptyArray() *Array { 26 return &Array{items: make([]core.Value, 0, 0)} 27 } 28 29 func NewArray(size int) *Array { 30 return &Array{items: make([]core.Value, 0, size)} 31 } 32 33 func NewArrayWith(values ...core.Value) *Array { 34 return &Array{items: values} 35 } 36 37 func NewArrayOf(values []core.Value) *Array { 38 return &Array{items: values} 39 } 40 41 func (t *Array) MarshalJSON() ([]byte, error) { 42 return jettison.MarshalOpts(t.items, jettison.NoHTMLEscaping()) 43 } 44 45 func (t *Array) Type() core.Type { 46 return types.Array 47 } 48 49 func (t *Array) String() string { 50 marshaled, err := t.MarshalJSON() 51 52 if err != nil { 53 return "[]" 54 } 55 56 return string(marshaled) 57 } 58 59 func (t *Array) Compare(other core.Value) int64 { 60 if other.Type() == types.Array { 61 other := other.(*Array) 62 63 if t.Length() == 0 && other.Length() == 0 { 64 return 0 65 } 66 67 if t.Length() < other.Length() { 68 return -1 69 } 70 71 if t.Length() > other.Length() { 72 return 1 73 } 74 75 var res int64 76 var val core.Value 77 78 other.ForEach(func(otherVal core.Value, idx int) bool { 79 val = t.Get(NewInt(idx)) 80 res = val.Compare(otherVal) 81 82 return res == 0 83 }) 84 85 return res 86 } 87 88 return types.Compare(types.Array, other.Type()) 89 } 90 91 func (t *Array) Unwrap() interface{} { 92 arr := make([]interface{}, t.Length()) 93 94 for idx, val := range t.items { 95 arr[idx] = val.Unwrap() 96 } 97 98 return arr 99 } 100 101 func (t *Array) Hash() uint64 { 102 h := fnv.New64a() 103 104 h.Write([]byte(t.Type().String())) 105 h.Write([]byte(":")) 106 h.Write([]byte("[")) 107 108 endIndex := len(t.items) - 1 109 110 for i, el := range t.items { 111 bytes := make([]byte, 8) 112 binary.LittleEndian.PutUint64(bytes, el.Hash()) 113 114 h.Write(bytes) 115 116 if i != endIndex { 117 h.Write([]byte(",")) 118 } 119 } 120 121 h.Write([]byte("]")) 122 123 return h.Sum64() 124 } 125 126 func (t *Array) Copy() core.Value { 127 c := NewArray(len(t.items)) 128 129 for _, el := range t.items { 130 c.Push(el) 131 } 132 133 return c 134 } 135 136 func (t *Array) Length() Int { 137 return Int(len(t.items)) 138 } 139 140 func (t *Array) ForEach(predicate ArrayPredicate) { 141 for idx, val := range t.items { 142 if !predicate(val, idx) { 143 break 144 } 145 } 146 } 147 148 func (t *Array) First() core.Value { 149 if len(t.items) > 0 { 150 return t.items[0] 151 } 152 153 return None 154 } 155 156 func (t *Array) Last() core.Value { 157 size := len(t.items) 158 159 if size > 1 { 160 return t.items[size-1] 161 } else if size == 1 { 162 return t.items[0] 163 } 164 165 return None 166 } 167 168 func (t *Array) Find(predicate ArrayPredicate) (*Array, Boolean) { 169 result := NewArray(len(t.items)) 170 171 for idx, val := range t.items { 172 if predicate(val, idx) { 173 result.Push(val) 174 } 175 } 176 177 return result, result.Length() > 0 178 } 179 180 func (t *Array) FindOne(predicate ArrayPredicate) (core.Value, Boolean) { 181 for idx, val := range t.items { 182 if predicate(val, idx) { 183 return val, True 184 } 185 } 186 187 return None, False 188 } 189 190 func (t *Array) Get(idx Int) core.Value { 191 l := len(t.items) - 1 192 193 if l < 0 { 194 return None 195 } 196 197 if int(idx) > l { 198 return None 199 } 200 201 return t.items[idx] 202 } 203 204 func (t *Array) Set(idx Int, value core.Value) error { 205 last := len(t.items) - 1 206 207 if last >= int(idx) { 208 t.items[idx] = value 209 210 return nil 211 } 212 213 return core.Error(core.ErrInvalidOperation, "out of bounds") 214 } 215 216 func (t *Array) Push(item core.Value) { 217 t.items = append(t.items, item) 218 } 219 220 func (t *Array) Slice(from, to Int) *Array { 221 length := t.Length() 222 223 if from >= length { 224 return NewArray(0) 225 } 226 227 if to > length { 228 to = length 229 } 230 231 result := new(Array) 232 result.items = t.items[from:to] 233 234 return result 235 } 236 237 func (t *Array) IndexOf(item core.Value) Int { 238 res := Int(-1) 239 240 for idx, el := range t.items { 241 if el.Compare(item) == 0 { 242 res = Int(idx) 243 break 244 } 245 } 246 247 return res 248 } 249 250 func (t *Array) Insert(idx Int, value core.Value) { 251 t.items = append(t.items[:idx], append([]core.Value{value}, t.items[idx:]...)...) 252 } 253 254 func (t *Array) RemoveAt(idx Int) { 255 i := int(idx) 256 max := len(t.items) - 1 257 258 if i > max { 259 return 260 } 261 262 t.items = append(t.items[:i], t.items[i+1:]...) 263 } 264 265 func (t *Array) Clone() core.Cloneable { 266 cloned := NewArray(0) 267 268 var value core.Value 269 for idx := NewInt(0); idx < t.Length(); idx++ { 270 value = t.Get(idx) 271 272 cloneable, ok := value.(core.Cloneable) 273 274 if ok { 275 value = cloneable.Clone() 276 } 277 278 cloned.Push(value) 279 } 280 281 return cloned 282 } 283 284 func (t *Array) Sort() *Array { 285 return t.SortWith(func(first, second core.Value) bool { 286 return first.Compare(second) == -1 287 }) 288 } 289 290 func (t *Array) SortWith(sorter ArraySorter) *Array { 291 c := make([]core.Value, len(t.items)) 292 copy(c, t.items) 293 294 sort.SliceStable(c, func(i, j int) bool { 295 return sorter(c[i], c[j]) 296 }) 297 298 res := new(Array) 299 res.items = c 300 301 return res 302 } 303 304 func (t *Array) GetIn(ctx context.Context, path []core.Value) (core.Value, core.PathError) { 305 if len(path) == 0 { 306 return None, nil 307 } 308 309 segmentIdx := 0 310 311 if typ := path[segmentIdx].Type(); typ != types.Int { 312 return None, core.NewPathError(core.TypeError(typ, types.Int), segmentIdx) 313 } 314 315 first := t.Get(path[segmentIdx].(Int)) 316 317 if len(path) == 1 { 318 return first, nil 319 } 320 321 segmentIdx++ 322 323 if first == None || first == nil { 324 return None, core.NewPathError(core.ErrInvalidPath, segmentIdx) 325 } 326 327 getter, ok := first.(core.Getter) 328 329 if !ok { 330 return GetIn(ctx, first, path[segmentIdx:]) 331 } 332 333 return getter.GetIn(ctx, path[segmentIdx:]) 334 }