blob: cb72db14bc7480fc06855d3371107f006f6ae604 [file] [log] [blame]
package state
import (
"bytes"
"fmt"
"reflect"
"sort"
"veyron2/storage"
)
// This function returns an interface with a pointer to the element in val.
// Note that this is different from returning &val which returns a pointer to
// val. This is required temporarily before we switch to VOM value so that
// we can append to slices.
// TODO(bprosnitz) This is hacky -- remove this when we switch to VOM Value
func makeInnerReference(val interface{}) interface{} {
rv := reflect.ValueOf(val)
ptr := reflect.New(rv.Type())
ptr.Elem().Set(rv)
return ptr.Interface()
}
func deepcopyReflect(rv reflect.Value) reflect.Value {
switch rv.Kind() {
case reflect.Array:
arr := reflect.New(rv.Type()).Elem()
for i := 0; i < rv.Len(); i++ {
valcopy := deepcopyReflect(rv.Index(i))
arr.Index(i).Set(valcopy)
}
return arr
case reflect.Slice:
s := reflect.MakeSlice(rv.Type(), rv.Len(), rv.Cap())
for i := 0; i < rv.Len(); i++ {
valcopy := deepcopyReflect(rv.Index(i))
s.Index(i).Set(valcopy)
}
ptr := reflect.New(rv.Type())
ptr.Elem().Set(s)
return ptr.Elem()
case reflect.Map:
m := reflect.MakeMap(rv.Type())
keys := rv.MapKeys()
for _, key := range keys {
val := rv.MapIndex(key)
keycopy := deepcopyReflect(key)
valcopy := deepcopyReflect(val)
m.SetMapIndex(keycopy, valcopy)
}
return m
case reflect.Struct:
s := reflect.New(rv.Type()).Elem()
for i := 0; i < rv.NumField(); i++ {
valcopy := deepcopyReflect(rv.Field(i))
s.Field(i).Set(valcopy)
}
return s
case reflect.Ptr:
ptr := reflect.New(rv.Type()).Elem()
elem := reflect.New(rv.Type().Elem())
ptr.Set(elem)
ptr.Elem().Set(deepcopyReflect(rv.Elem()))
return ptr
case reflect.Interface:
intr := reflect.New(rv.Type()).Elem()
intr.Set(deepcopyReflect(rv.Elem()))
return intr
case reflect.Chan, reflect.Func, reflect.UnsafePointer:
panic(fmt.Sprintf("deepcopy of kind %v not supported", rv.Kind()))
default:
// Primitives (copy it so we can't set the original)
return reflect.ValueOf(rv.Interface())
}
}
// deepcopy performs a deep copy of a value. We need this to simulate secondary
// storage where each time a value is stored, it is copied to secondary storage;
// and when it is retrieved, it is copied out of secondary storage.
func deepcopy(v interface{}) interface{} {
if v == nil {
return nil
}
return deepcopyReflect(reflect.ValueOf(v)).Interface()
}
// addIDToSort adds a storage.ID to a sorted array.
func addIDToSort(id storage.ID, refs []storage.ID) []storage.ID {
i := findIDInSort(id, refs)
newRefs := make([]storage.ID, len(refs)+1)
copy(newRefs[0:i], refs[0:i])
newRefs[i] = id
copy(newRefs[i+1:], refs[i:])
return newRefs
}
// removeIDFromSort removes a storage.ID from a sorted array.
func removeIDFromSort(id storage.ID, refs []storage.ID) []storage.ID {
i := findIDInSort(id, refs)
if i < len(refs) && refs[i] == id {
newRefs := make([]storage.ID, len(refs)-1)
copy(newRefs[0:i], refs[0:i])
copy(newRefs[i:], refs[i+1:])
return newRefs
}
return refs
}
func findIDInSort(id storage.ID, refs []storage.ID) int {
return sort.Search(len(refs), func(i int) bool {
return bytes.Compare(refs[i][:], id[:]) >= 0
})
}