package org.basex.query.item.map;
import org.basex.query.QueryException;
import static org.basex.query.QueryText.*;
import org.basex.query.item.AtomType;
import org.basex.query.item.Item;
import org.basex.query.item.SeqType;
import org.basex.query.item.Value;
import org.basex.query.iter.ItemCache;
import org.basex.util.Array;
import org.basex.util.InputInfo;
/**
* A single binding of a {@link Map}.
*
* @author BaseX Team 2005-12, BSD License
* @author Leo Woerteler
*/
final class Leaf extends TrieNode {
/** Hash code of the key, stored for performance. */
final int hash;
/** Key of this binding. */
final Item key;
/** Value of this binding. */
final Value value;
/**
* Constructor.
* @param h hash code of the key
* @param k key
* @param v value
*/
Leaf(final int h, final Item k, final Value v) {
super(1);
hash = h;
key = k;
value = v;
assert verify();
}
@Override
TrieNode insert(final int h, final Item k, final Value v, final int l,
final InputInfo ii) throws QueryException {
// same hash, replace or merge
if(h == hash) return eq(k, key, ii) ?
new Leaf(h, k, v) : new List(hash, key, value, k, v);
// different hash, branch
final TrieNode[] ch = new TrieNode[KIDS];
final int a = key(h, l), b = key(hash, l);
final int used;
if(a != b) {
ch[a] = new Leaf(h, k, v);
ch[b] = this;
used = 1 << a | 1 << b;
} else {
ch[a] = insert(h, k, v, l + 1, ii);
used = 1 << a;
}
return new Branch(ch, used, 2);
}
@Override
TrieNode delete(final int h, final Item k, final int l, final InputInfo ii)
throws QueryException {
return h == hash && eq(key, k, ii) ? null : this;
}
@Override
Value get(final int h, final Item k, final int l, final InputInfo ii)
throws QueryException {
return h == hash && eq(key, k, ii) ? value : null;
}
@Override
boolean contains(final int h, final Item k, final int l,
final InputInfo ii) throws QueryException {
return h == hash && eq(key, k, ii);
}
@Override
StringBuilder toString(final StringBuilder sb, final String ind) {
return sb.append(ind).append("`-- ").append(key).append(
" => ").append(value).append('\n');
}
@Override
TrieNode addAll(final TrieNode o, final int l, final InputInfo ii)
throws QueryException {
return o.add(this, l, ii);
}
@Override
TrieNode add(final Leaf o, final int l, final InputInfo ii)
throws QueryException {
if(hash == o.hash) return eq(key, o.key, ii) ?
this : new List(hash, key, value, o.key, o.value);
final TrieNode[] ch = new TrieNode[KIDS];
final int k = key(hash, l), ok = key(o.hash, l);
final int nu;
// same key? add recursively
if(k == ok) {
ch[k] = add(o, l + 1, ii);
nu = 1 << k;
} else {
ch[k] = this;
ch[ok] = o;
nu = 1 << k | 1 << ok;
}
return new Branch(ch, nu, 2);
}
@Override
TrieNode add(final List o, final int l, final InputInfo ii)
throws QueryException {
// same hash? insert binding
if(hash == o.hash) {
for(int i = 0; i < o.size; i++) {
if(eq(key, o.keys[i], ii)) {
final Item[] ks = o.keys.clone();
final Value[] vs = o.values.clone();
ks[i] = key;
vs[i] = value;
return new List(hash, ks, vs);
}
}
return new List(hash, Array.add(o.keys, key), Array.add(o.values, value));
}
final TrieNode[] ch = new TrieNode[KIDS];
final int k = key(hash, l), ok = key(o.hash, l);
final int nu;
// same key? add recursively
if(k == ok) {
ch[k] = add(o, l + 1, ii);
nu = 1 << k;
} else {
ch[k] = this;
ch[ok] = o;
nu = 1 << k | 1 << ok;
}
return new Branch(ch, nu, o.size + 1);
}
@Override
TrieNode add(final Branch o, final int l, final InputInfo ii)
throws QueryException {
final int k = key(hash, l);
final TrieNode[] ch = o.copyKids();
final TrieNode old = ch[k];
ch[k] = old == null ? this : old.addAll(this, l + 1, ii);
return new Branch(ch, o.used | 1 << k,
o.size + ch[k].size - (old != null ? old.size : 0));
}
@Override
boolean verify() {
try {
return key.hash(null) == hash;
} catch(final QueryException ex) {
return false;
}
}
@Override
void keys(final ItemCache ks) {
ks.add(key);
}
@Override
boolean hasType(final AtomType kt, final SeqType vt) {
return (kt == null || key.type.instanceOf(kt))
&& (vt == null || vt.instance(value));
}
@Override
boolean deep(final InputInfo ii, final TrieNode o) throws QueryException {
return o instanceof Leaf && eq(key, ((Leaf) o).key, ii)
&& deep(value, ((Leaf) o).value, ii);
}
@Override
int hash(final InputInfo ii) throws QueryException {
return 31 * hash + value.hash(ii);
}
@Override
StringBuilder toString(final StringBuilder sb) {
return sb.append(key).append(ASSIGN).append(value).append(", ");
}
}