com.yahoo.slime.ObjectValue Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vespajlib Show documentation
Show all versions of vespajlib Show documentation
Library for use in Java components of Vespa. Shared code which do
not fit anywhere else.
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.slime;
/**
* A Value holding a slime "Object", a dynamic collection of named
* value fields. Fields can be inspected or traversed using the
* {@link Inspector} interface, and you can add new fields by using the
* various "set" methods in the @ref Cursor interface.
*
* @author havardpe
*/
final class ObjectValue extends Value {
private int capacity = 16;
private int hashSize() { return (capacity + (capacity >> 1) - 1); }
private int used = 0;
private Value[] values = new Value[capacity];
private int[] hash = new int[capacity + hashSize() + (capacity << 1)];
private final SymbolTable names;
private void rehash() {
capacity = (capacity << 1);
Value[] v = values;
values = new Value[capacity];
System.arraycopy(v, 0, values, 0, used);
int[] h = hash;
hash = new int[capacity + hashSize() + (capacity << 1)];
System.arraycopy(h, 0, hash, 0, used);
for (int i = 0; i < used; i++) {
int prev = (capacity + (hash[i] % hashSize()));
int entry = hash[prev];
while (entry != 0) {
prev = entry + 1;
entry = hash[prev];
}
final int insertIdx = (capacity + hashSize() + (i << 1));
hash[prev] = insertIdx;
hash[insertIdx] = i;
}
}
private Value put(int sym, Value value) {
if (used == capacity) {
rehash();
}
int prev = (capacity + (sym % hashSize()));
int entry = hash[prev];
while (entry != 0) {
final int idx = hash[entry];
if (hash[idx] == sym) { // found entry
return NixValue.invalid();
}
prev = entry + 1;
entry = hash[prev];
}
final int insertIdx = (capacity + hashSize() + (used << 1));
hash[prev] = insertIdx;
hash[insertIdx] = used;
hash[used] = sym;
values[used++] = value;
return value;
}
private Value get(int sym) {
int entry = hash[capacity + (sym % hashSize())];
while (entry != 0) {
final int idx = hash[entry];
if (hash[idx] == sym) { // found entry
return values[idx];
}
entry = hash[entry + 1];
}
return NixValue.invalid();
}
public ObjectValue(SymbolTable names) { this.names = names; }
public ObjectValue(SymbolTable names, int sym, Value value) {
this.names = names;
put(sym, value);
}
public Type type() { return Type.OBJECT; }
public int children() { return used; }
public int fields() { return used; }
public Value field(int sym) { return get(sym); }
public Value field(String name) { return get(names.lookup(name)); }
public void accept(Visitor v) { v.visitObject(this); }
public void traverse(ObjectSymbolTraverser ot) {
for (int i = 0; i < used; ++i) {
ot.field(hash[i], values[i]);
}
}
public void traverse(ObjectTraverser ot) {
for (int i = 0; i < used; ++i) {
ot.field(names.inspect(hash[i]), values[i]);
}
}
protected Cursor setLeaf(int sym, Value value) { return put(sym, value); }
public Cursor setArray(int sym) { return put(sym, new ArrayValue(names)); }
public Cursor setObject(int sym) { return put(sym, new ObjectValue(names)); }
protected Cursor setLeaf(String name, Value value) { return put(names.insert(name), value); }
public Cursor setArray(String name) { return put(names.insert(name), new ArrayValue(names)); }
public Cursor setObject(String name) { return put(names.insert(name), new ObjectValue(names)); }
}