org.eclipse.jetty.util.ArrayTernaryTrie Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jetty-util Show documentation
Show all versions of jetty-util Show documentation
Utility classes for Jetty
//
// ========================================================================
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.util;
import java.nio.ByteBuffer;
import java.util.HashSet;
import java.util.Set;
/* ------------------------------------------------------------ */
/** A Ternary Trie String lookup data structure.
* This Trie is of a fixed size and cannot grow (which can be a good thing with regards to DOS when used as a cache).
* @param
*/
public class ArrayTernaryTrie extends AbstractTrie
{
private static int LO=1;
private static int EQ=2;
private static int HI=3;
/**
* The Size of a Trie row is the char, and the low, equal and high
* child pointers
*/
private static final int ROW_SIZE = 4;
/**
* The Trie rows in a single array which allows a lookup of row,character
* to the next row in the Trie. This is actually a 2 dimensional
* array that has been flattened to achieve locality of reference.
*/
private final char[] _tree;
/**
* The key (if any) for a Trie row.
* A row may be a leaf, a node or both in the Trie tree.
*/
private final String[] _key;
/**
* The value (if any) for a Trie row.
* A row may be a leaf, a node or both in the Trie tree.
*/
private final Object[] _value;
/**
* The number of rows allocated
*/
private char _rows;
public ArrayTernaryTrie()
{
this(128);
}
public ArrayTernaryTrie(boolean insensitive)
{
this(insensitive,128);
}
public ArrayTernaryTrie(int capacityInNodes)
{
this(true,capacityInNodes);
}
public ArrayTernaryTrie(boolean insensitive, int capacityInNodes)
{
super(insensitive);
_value=new Object[capacityInNodes];
_tree=new char[capacityInNodes*ROW_SIZE];
_key=new String[capacityInNodes];
}
/* ------------------------------------------------------------ */
/** Copy Trie and change capacity by a factor
* @param trie
* @param factor
*/
public ArrayTernaryTrie(ArrayTernaryTrie trie, double factor)
{
this(trie.isCaseInsensitive(),(int)(trie._value.length*factor));
_rows=trie._rows;
System.arraycopy(trie._value,0,_value,0,trie._value.length);
System.arraycopy(trie._tree,0,_tree,0,trie._tree.length);
System.arraycopy(trie._key,0,_key,0,trie._key.length);
}
/* ------------------------------------------------------------ */
@Override
public boolean put(String s, V v)
{
int last=EQ;
int t=_tree[last];
int k;
int limit = s.length();
int node=0;
for(k=0; k < limit; k++)
{
char c=s.charAt(k);
if(isCaseInsensitive() && c<128)
c=StringUtil.lowercases[c];
while (true)
{
if (t==0)
{
node=t=++_rows;
if (_rows>=_key.length)
{
_rows--;
return false;
}
int row=ROW_SIZE*t;
_tree[row]=c;
_tree[last]=(char)t;
last=row+EQ;
}
int row=ROW_SIZE*t;
char n=_tree[row];
int diff=n-c;
if (diff==0)
{
node=t;
t=_tree[last=(row+EQ)];
break;
}
if (diff<0)
t=_tree[last=(row+LO)];
else
t=_tree[last=(row+HI)];
}
}
_key[node]=v==null?null:s;
_value[node] = v;
return true;
}
/* ------------------------------------------------------------ */
@Override
public V get(String s,int offset, int length)
{
int t = _tree[EQ];
int len = length;
int i=0;
while(i keySet()
{
Set keys = new HashSet<>();
for (int r=1;r<=_rows;r++)
{
if (_key[r]!=null && _value[r]!=null)
keys.add(_key[r]);
}
return keys;
}
@Override
public boolean isFull()
{
return _rows+1==_key.length;
}
public void dump()
{
for (int r=0;r<=_rows;r++)
{
char c=_tree[r*ROW_SIZE+0];
System.err.printf("%4d [%s,%d,%d,%d] %s:%s%n",
r,
(c<' '||c>127)?(""+(int)c):"'"+c+"'",
(int)_tree[r*ROW_SIZE+LO],
(int)_tree[r*ROW_SIZE+EQ],
(int)_tree[r*ROW_SIZE+HI],
_key[r],
_value[r]);
}
}
}