mirror of
https://github.com/jetty/jetty.project.git
synced 2025-03-03 04:19:12 +00:00
jetty-9 made Trie abstract and added TreeTrie for the HttpParser cache to save space
This commit is contained in:
parent
3efcc2af41
commit
25324b666c
@ -22,6 +22,7 @@ import java.nio.ByteBuffer;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.util.ArrayTrie;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.Trie;
|
||||
@ -32,8 +33,8 @@ import org.eclipse.jetty.util.Trie;
|
||||
*/
|
||||
public class HttpField
|
||||
{
|
||||
public final static Trie<HttpField> CACHE = new Trie<>(768);
|
||||
public final static Trie<HttpField> CONTENT_TYPE = new Trie<>(512);
|
||||
public final static Trie<HttpField> CACHE = new ArrayTrie<>(768);
|
||||
public final static Trie<HttpField> CONTENT_TYPE = new ArrayTrie<>(512);
|
||||
|
||||
static
|
||||
{
|
||||
|
@ -20,6 +20,7 @@ package org.eclipse.jetty.http;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.util.ArrayTrie;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.Trie;
|
||||
|
||||
@ -112,7 +113,7 @@ public enum HttpHeader
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public final static Trie<HttpHeader> CACHE= new Trie<>(512);
|
||||
public final static Trie<HttpHeader> CACHE= new ArrayTrie<>(512);
|
||||
static
|
||||
{
|
||||
for (HttpHeader header : HttpHeader.values())
|
||||
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.http;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import org.eclipse.jetty.util.ArrayTrie;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Trie;
|
||||
|
||||
@ -44,7 +45,7 @@ public enum HttpHeaderValue
|
||||
UNKNOWN("::UNKNOWN::");
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public final static Trie<HttpHeaderValue> CACHE= new Trie<HttpHeaderValue>();
|
||||
public final static Trie<HttpHeaderValue> CACHE= new ArrayTrie<HttpHeaderValue>();
|
||||
static
|
||||
{
|
||||
for (HttpHeaderValue value : HttpHeaderValue.values())
|
||||
|
@ -20,6 +20,7 @@ package org.eclipse.jetty.http;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.util.ArrayTrie;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.Trie;
|
||||
|
||||
@ -113,7 +114,7 @@ public enum HttpMethod
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public final static Trie<HttpMethod> CACHE= new Trie<HttpMethod>();
|
||||
public final static Trie<HttpMethod> CACHE= new ArrayTrie<HttpMethod>();
|
||||
static
|
||||
{
|
||||
for (HttpMethod method : HttpMethod.values())
|
||||
|
@ -24,8 +24,8 @@ import java.nio.ByteBuffer;
|
||||
import org.eclipse.jetty.http.HttpTokens.EndOfContent;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.TreeTrie;
|
||||
import org.eclipse.jetty.util.Trie;
|
||||
import org.eclipse.jetty.util.Utf8StringBuilder;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
@ -87,7 +87,7 @@ public class HttpParser
|
||||
private int _chunkPosition;
|
||||
private boolean _headResponse;
|
||||
private ByteBuffer _contentChunk;
|
||||
private final Trie<HttpField> _connectionFields=new Trie<>(512);
|
||||
private final Trie<HttpField> _connectionFields=new TreeTrie<>();
|
||||
|
||||
private int _length;
|
||||
private final StringBuilder _string=new StringBuilder();
|
||||
|
@ -20,6 +20,7 @@ package org.eclipse.jetty.http;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.util.ArrayTrie;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Trie;
|
||||
|
||||
@ -34,7 +35,7 @@ public enum HttpScheme
|
||||
WSS("wss");
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public final static Trie<HttpScheme> CACHE= new Trie<HttpScheme>();
|
||||
public final static Trie<HttpScheme> CACHE= new ArrayTrie<HttpScheme>();
|
||||
static
|
||||
{
|
||||
for (HttpScheme version : HttpScheme.values())
|
||||
|
@ -20,6 +20,7 @@ package org.eclipse.jetty.http;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.util.ArrayTrie;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.Trie;
|
||||
|
||||
@ -33,7 +34,7 @@ public enum HttpVersion
|
||||
HTTP_2_0("HTTP/2.0",20);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public final static Trie<HttpVersion> CACHE= new Trie<HttpVersion>();
|
||||
public final static Trie<HttpVersion> CACHE= new ArrayTrie<HttpVersion>();
|
||||
static
|
||||
{
|
||||
for (HttpVersion version : HttpVersion.values())
|
||||
|
@ -27,6 +27,7 @@ import java.util.Map;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import org.eclipse.jetty.util.ArrayTrie;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.Trie;
|
||||
@ -109,8 +110,8 @@ public class MimeTypes
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private static final Logger LOG = Log.getLogger(MimeTypes.class);
|
||||
public final static Trie<MimeTypes.Type> CACHE= new Trie<>(512);
|
||||
private final static Trie<ByteBuffer> TYPES= new Trie<ByteBuffer>(512);
|
||||
public final static Trie<MimeTypes.Type> CACHE= new ArrayTrie<>(512);
|
||||
private final static Trie<ByteBuffer> TYPES= new ArrayTrie<ByteBuffer>(512);
|
||||
private final static Map<String,String> __dftMimeMap = new HashMap<String,String>();
|
||||
private final static Map<String,String> __encodings = new HashMap<String,String>();
|
||||
|
||||
|
@ -23,7 +23,6 @@ import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.jetty.http.HttpParser.State;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
|
@ -22,7 +22,6 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
|
@ -69,7 +69,6 @@ import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler.Context;
|
||||
import org.eclipse.jetty.server.session.AbstractSession;
|
||||
import org.eclipse.jetty.server.session.AbstractSessionManager;
|
||||
import org.eclipse.jetty.util.Attributes;
|
||||
import org.eclipse.jetty.util.AttributesMap;
|
||||
import org.eclipse.jetty.util.MultiException;
|
||||
|
@ -20,7 +20,6 @@ package org.eclipse.jetty.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
import java.nio.channels.IllegalSelectorException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
@ -24,7 +24,6 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.EventListener;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -53,8 +53,8 @@ import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.MultiPartInputStreamParser;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.StdErrLog;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.log.StdErrLog;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
|
@ -42,9 +42,7 @@ import org.eclipse.jetty.server.ConnectorStatistics;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -446,10 +446,10 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
||||
if (resource!=null && resource.exists() && !resource.isDirectory())
|
||||
{
|
||||
// Tell caches that response may vary by accept-encoding
|
||||
response.setHeader(HttpHeaders.VARY.asString(),HttpHeaders.ACCEPT_ENCODING.asString());
|
||||
response.setHeader(HttpHeader.VARY.asString(),HttpHeader.ACCEPT_ENCODING.asString());
|
||||
|
||||
// Does the client accept gzip?
|
||||
String accept=request.getHeader(HttpHeaders.ACCEPT_ENCODING.asString());
|
||||
String accept=request.getHeader(HttpHeader.ACCEPT_ENCODING.asString());
|
||||
if (accept!=null && accept.indexOf("gzip")>=0)
|
||||
gzip=true;
|
||||
}
|
||||
|
@ -29,11 +29,11 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.HttpTester;
|
||||
import org.eclipse.jetty.servlet.DefaultServlet;
|
||||
import org.eclipse.jetty.servlet.FilterHolder;
|
||||
import org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper;
|
||||
import org.eclipse.jetty.servlets.gzip.GzipTester;
|
||||
import org.eclipse.jetty.testing.HttpTester;
|
||||
import org.eclipse.jetty.toolchain.test.TestingDir;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
@ -117,8 +117,8 @@ public class GzipFilterDefaultTest
|
||||
try
|
||||
{
|
||||
tester.start();
|
||||
HttpTester http = tester.assertIsResponseGzipCompressed("file.txt");
|
||||
Assert.assertEquals("Accept-Encoding",http.getHeader("Vary"));
|
||||
HttpTester.Response http = tester.assertIsResponseGzipCompressed("file.txt");
|
||||
Assert.assertEquals("Accept-Encoding",http.get("Vary"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
@ -141,8 +141,8 @@ public class GzipFilterDefaultTest
|
||||
try
|
||||
{
|
||||
tester.start();
|
||||
HttpTester http = tester.assertIsResponseGzipCompressed("file.txt");
|
||||
Assert.assertEquals("Accept-Encoding",http.getHeader("Vary"));
|
||||
HttpTester.Response http = tester.assertIsResponseGzipCompressed("file.txt");
|
||||
Assert.assertEquals("Accept-Encoding",http.get("Vary"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
@ -165,8 +165,8 @@ public class GzipFilterDefaultTest
|
||||
try
|
||||
{
|
||||
tester.start();
|
||||
HttpTester http = tester.assertIsResponseGzipCompressed("file.txt");
|
||||
Assert.assertEquals("Accept-Encoding",http.getHeader("Vary"));
|
||||
HttpTester.Response http = tester.assertIsResponseGzipCompressed("file.txt");
|
||||
Assert.assertEquals("Accept-Encoding",http.get("Vary"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
@ -189,8 +189,8 @@ public class GzipFilterDefaultTest
|
||||
try
|
||||
{
|
||||
tester.start();
|
||||
HttpTester http = tester.assertIsResponseGzipCompressed("file.txt");
|
||||
Assert.assertEquals("Accept-Encoding",http.getHeader("Vary"));
|
||||
HttpTester.Response http = tester.assertIsResponseGzipCompressed("file.txt");
|
||||
Assert.assertEquals("Accept-Encoding",http.get("Vary"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
@ -212,8 +212,8 @@ public class GzipFilterDefaultTest
|
||||
try
|
||||
{
|
||||
tester.start();
|
||||
HttpTester http = tester.assertIsResponseNotGzipCompressed("file.txt", filesize, HttpStatus.OK_200);
|
||||
Assert.assertEquals("Accept-Encoding",http.getHeader("Vary"));
|
||||
HttpTester.Response http = tester.assertIsResponseNotGzipCompressed("file.txt", filesize, HttpStatus.OK_200);
|
||||
Assert.assertEquals("Accept-Encoding",http.get("Vary"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
@ -235,8 +235,8 @@ public class GzipFilterDefaultTest
|
||||
try
|
||||
{
|
||||
tester.start();
|
||||
HttpTester http = tester.assertIsResponseNotGzipCompressed("file.mp3", filesize, HttpStatus.OK_200);
|
||||
Assert.assertNull(http.getHeader("Vary"));
|
||||
HttpTester.Response http = tester.assertIsResponseNotGzipCompressed("file.mp3", filesize, HttpStatus.OK_200);
|
||||
Assert.assertNull(http.get("Vary"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -73,12 +73,12 @@ public class GzipTester
|
||||
// DOES NOT WORK IN WINDOWS - this.testdir.ensureEmpty();
|
||||
}
|
||||
|
||||
public HttpTester assertIsResponseGzipCompressed(String filename) throws Exception
|
||||
public HttpTester.Response assertIsResponseGzipCompressed(String filename) throws Exception
|
||||
{
|
||||
return assertIsResponseGzipCompressed(filename,filename);
|
||||
}
|
||||
|
||||
public HttpTester assertIsResponseGzipCompressed(String requestedFilename, String serverFilename) throws Exception
|
||||
public HttpTester.Response assertIsResponseGzipCompressed(String requestedFilename, String serverFilename) throws Exception
|
||||
{
|
||||
// System.err.printf("[GzipTester] requesting /context/%s%n",requestedFilename);
|
||||
HttpTester.Request request = HttpTester.newRequest();
|
||||
@ -237,7 +237,7 @@ public class GzipTester
|
||||
* passing -1 will disable the Content-Length assertion)
|
||||
* @throws Exception
|
||||
*/
|
||||
public HttpTester assertIsResponseNotGzipCompressed(String filename, int expectedFilesize, int status) throws Exception
|
||||
public HttpTester.Response assertIsResponseNotGzipCompressed(String filename, int expectedFilesize, int status) throws Exception
|
||||
{
|
||||
String uri = "/context/"+filename;
|
||||
HttpTester.Response response = executeRequest(uri);
|
||||
|
400
jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTrie.java
Normal file
400
jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTrie.java
Normal file
@ -0,0 +1,400 @@
|
||||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 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.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** A Trie String lookup data structure.
|
||||
* @param <V>
|
||||
*/
|
||||
public class ArrayTrie<V> implements Trie<V>
|
||||
{
|
||||
/**
|
||||
* The Size of a Trie row is how many characters can be looked
|
||||
* up directly without going to a big index. This is set at
|
||||
* 32 to cover case insensitive alphabet and a few other common
|
||||
* characters.
|
||||
*/
|
||||
private static final int ROW_SIZE = 32;
|
||||
|
||||
/**
|
||||
* The index lookup table, this maps a character as a byte
|
||||
* (ISO-8859-1 or UTF8) to an index within a Trie row
|
||||
*/
|
||||
private static final int[] __lookup =
|
||||
{ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
/*0*/-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
/*1*/-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 30,
|
||||
/*2*/31, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, -1, 27, -1, -1,
|
||||
/*3*/-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 28, 29, -1, -1, -1, -1,
|
||||
/*4*/-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
/*5*/15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
|
||||
/*6*/-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
/*7*/15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* The first ROW_SIZE entries are for row 0, then next ROW_SIZE
|
||||
* entries are for row 1 etc. So in general instead of using
|
||||
* _rows[row][index], we use _rows[row*ROW_SIZE+index] to look up
|
||||
* the next row for a given character.
|
||||
*
|
||||
* The array is of characters rather than integers to save space.
|
||||
*/
|
||||
private final char[] _rowIndex;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* A big index for each row.
|
||||
* If a character outside of the lookup map is needed,
|
||||
* then a big index will be created for the row, with
|
||||
* 256 entries, one for each possible byte.
|
||||
*/
|
||||
private char[][] _bigIndex;
|
||||
|
||||
/**
|
||||
* The number of rows allocated
|
||||
*/
|
||||
private char _rows;
|
||||
|
||||
public ArrayTrie()
|
||||
{
|
||||
this(128);
|
||||
}
|
||||
|
||||
public ArrayTrie(int capacityInNodes)
|
||||
{
|
||||
_value=new Object[capacityInNodes];
|
||||
_rowIndex=new char[capacityInNodes*32];
|
||||
_key=new String[capacityInNodes];
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public boolean put(String s, V v)
|
||||
{
|
||||
int t=0;
|
||||
int k;
|
||||
int limit = s.length();
|
||||
for(k=0; k < limit; k++)
|
||||
{
|
||||
char c=s.charAt(k);
|
||||
|
||||
int index=__lookup[c&0x7f];
|
||||
if (index>=0)
|
||||
{
|
||||
int idx=t*ROW_SIZE+index;
|
||||
t=_rowIndex[idx];
|
||||
if (t==0)
|
||||
{
|
||||
if (_rows==_value.length)
|
||||
return false;
|
||||
t=_rowIndex[idx]=++_rows;
|
||||
}
|
||||
}
|
||||
else if (c>127)
|
||||
throw new IllegalArgumentException("non ascii character");
|
||||
else
|
||||
{
|
||||
if (_bigIndex==null)
|
||||
_bigIndex=new char[_value.length][];
|
||||
char[] big=_bigIndex[t];
|
||||
if (big==null)
|
||||
big=_bigIndex[t]=new char[128];
|
||||
t=big[c];
|
||||
if (t==0)
|
||||
{
|
||||
if (_rows==_value.length)
|
||||
return false;
|
||||
t=big[c]=++_rows;
|
||||
}
|
||||
}
|
||||
}
|
||||
_key[t]=v==null?null:s;
|
||||
V old=(V)_value[t];
|
||||
_value[t] = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public boolean put(V v)
|
||||
{
|
||||
return put(v.toString(),v);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public V remove(String s)
|
||||
{
|
||||
V o=get(s);
|
||||
put(s,null);
|
||||
return o;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public V get(String s)
|
||||
{
|
||||
int t = 0;
|
||||
int len = s.length();
|
||||
for(int i=0; i < len; i++)
|
||||
{
|
||||
char c=s.charAt(i);
|
||||
int index=__lookup[c&0x7f];
|
||||
if (index>=0)
|
||||
{
|
||||
int idx=t*ROW_SIZE+index;
|
||||
t=_rowIndex[idx];
|
||||
if (t==0)
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
char[] big = _bigIndex==null?null:_bigIndex[t];
|
||||
if (big==null)
|
||||
return null;
|
||||
t=big[c];
|
||||
if (t==0)
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return (V)_value[t];
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public V get(ByteBuffer b,int offset,int len)
|
||||
{
|
||||
int t = 0;
|
||||
for(int i=0; i < len; i++)
|
||||
{
|
||||
byte c=b.get(offset+i);
|
||||
int index=__lookup[c&0x7f];
|
||||
if (index>=0)
|
||||
{
|
||||
int idx=t*ROW_SIZE+index;
|
||||
t=_rowIndex[idx];
|
||||
if (t==0)
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
char[] big = _bigIndex==null?null:_bigIndex[t];
|
||||
if (big==null)
|
||||
return null;
|
||||
t=big[c];
|
||||
if (t==0)
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return (V)_value[t];
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public V getBest(byte[] b,int offset,int len)
|
||||
{
|
||||
return getBest(0,b,offset,len);
|
||||
}
|
||||
|
||||
private V getBest(int t,byte[] b,int offset,int len)
|
||||
{
|
||||
for(int i=0; i < len; i++)
|
||||
{
|
||||
byte c=b[offset+i];
|
||||
int index=__lookup[c&0x7f];
|
||||
if (index>=0)
|
||||
{
|
||||
int idx=t*ROW_SIZE+index;
|
||||
t=_rowIndex[idx];
|
||||
if (t==0)
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
char[] big = _bigIndex==null?null:_bigIndex[t];
|
||||
if (big==null)
|
||||
return null;
|
||||
t=big[c];
|
||||
if (t==0)
|
||||
return null;
|
||||
}
|
||||
|
||||
// Is the next Trie is a match
|
||||
if (_key[t]!=null)
|
||||
{
|
||||
// Recurse so we can remember this possibility
|
||||
V best=getBest(t,b,offset+i+1,len-i-1);
|
||||
if (best!=null)
|
||||
return best;
|
||||
return (V)_value[t];
|
||||
}
|
||||
}
|
||||
return (V)_value[t];
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public V getBest(ByteBuffer b,int offset,int len)
|
||||
{
|
||||
if (b.hasArray())
|
||||
return getBest(0,b.array(),b.arrayOffset()+b.position()+offset,len);
|
||||
return getBest(0,b,offset,len);
|
||||
}
|
||||
|
||||
private V getBest(int t,ByteBuffer b,int offset,int len)
|
||||
{
|
||||
int pos=b.position()+offset;
|
||||
for(int i=0; i < len; i++)
|
||||
{
|
||||
byte c=b.get(pos++);
|
||||
int index=__lookup[c&0x7f];
|
||||
if (index>=0)
|
||||
{
|
||||
int idx=t*ROW_SIZE+index;
|
||||
t=_rowIndex[idx];
|
||||
if (t==0)
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
char[] big = _bigIndex==null?null:_bigIndex[t];
|
||||
if (big==null)
|
||||
return null;
|
||||
t=big[c];
|
||||
if (t==0)
|
||||
return null;
|
||||
}
|
||||
|
||||
// Is the next Trie is a match
|
||||
if (_key[t]!=null)
|
||||
{
|
||||
// Recurse so we can remember this possibility
|
||||
V best=getBest(t,b,offset+i+1,len-i-1);
|
||||
if (best!=null)
|
||||
return best;
|
||||
return (V)_value[t];
|
||||
}
|
||||
}
|
||||
return (V)_value[t];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder buf = new StringBuilder();
|
||||
toString(buf,0);
|
||||
|
||||
if (buf.length()==0)
|
||||
return "{}";
|
||||
|
||||
buf.setCharAt(0,'{');
|
||||
buf.append('}');
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
|
||||
private <V> void toString(Appendable out, int t)
|
||||
{
|
||||
if (_value[t]!=null)
|
||||
{
|
||||
try
|
||||
{
|
||||
out.append(',');
|
||||
out.append(_key[t]);
|
||||
out.append('=');
|
||||
out.append(_value[t].toString());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0; i < ROW_SIZE; i++)
|
||||
{
|
||||
int idx=t*ROW_SIZE+i;
|
||||
if (_rowIndex[idx] != 0)
|
||||
toString(out,_rowIndex[idx]);
|
||||
}
|
||||
|
||||
char[] big = _bigIndex==null?null:_bigIndex[t];
|
||||
if (big!=null)
|
||||
{
|
||||
for (int i:big)
|
||||
if (i!=0)
|
||||
toString(out,i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> keySet()
|
||||
{
|
||||
Set<String> keys = new HashSet<>();
|
||||
keySet(keys,0);
|
||||
return keys;
|
||||
}
|
||||
|
||||
private void keySet(Set<String> set, int t)
|
||||
{
|
||||
if (_value[t]!=null)
|
||||
set.add(_key[t]);
|
||||
|
||||
for(int i=0; i < ROW_SIZE; i++)
|
||||
{
|
||||
int idx=t*ROW_SIZE+i;
|
||||
if (_rowIndex[idx] != 0)
|
||||
keySet(set,_rowIndex[idx]);
|
||||
}
|
||||
|
||||
char[] big = _bigIndex==null?null:_bigIndex[t];
|
||||
if (big!=null)
|
||||
{
|
||||
for (int i:big)
|
||||
if (i!=0)
|
||||
keySet(set,i);
|
||||
}
|
||||
}
|
||||
}
|
335
jetty-util/src/main/java/org/eclipse/jetty/util/TreeTrie.java
Normal file
335
jetty-util/src/main/java/org/eclipse/jetty/util/TreeTrie.java
Normal file
@ -0,0 +1,335 @@
|
||||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 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.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class TreeTrie<V> implements Trie<V>
|
||||
{
|
||||
private static final int[] __lookup =
|
||||
{ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
/*0*/-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
/*1*/-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 30,
|
||||
/*2*/31, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, -1, 27, -1, -1,
|
||||
/*3*/-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 28, 29, -1, -1, -1, -1,
|
||||
/*4*/-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
/*5*/15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
|
||||
/*6*/-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
/*7*/15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
|
||||
};
|
||||
private static final int INDEX = 32;
|
||||
private final TreeTrie<V>[] _nextIndex;
|
||||
private final List<TreeTrie<V>> _nextOther=new ArrayList<>();
|
||||
private final char _c;
|
||||
private String _key;
|
||||
private V _value;
|
||||
|
||||
public TreeTrie()
|
||||
{
|
||||
_nextIndex = new TreeTrie[INDEX];
|
||||
_c=0;
|
||||
}
|
||||
|
||||
private TreeTrie(char c)
|
||||
{
|
||||
_nextIndex = new TreeTrie[INDEX];
|
||||
this._c=c;
|
||||
}
|
||||
|
||||
public boolean put(V v)
|
||||
{
|
||||
return put(v.toString(),v);
|
||||
}
|
||||
|
||||
public boolean put(String s, V v)
|
||||
{
|
||||
TreeTrie<V> t = this;
|
||||
int k;
|
||||
int limit = s.length();
|
||||
for(k=0; k < limit; k++)
|
||||
{
|
||||
char c=s.charAt(k);
|
||||
|
||||
int index=c>=0&&c<0x7f?__lookup[c]:-1;
|
||||
if (index>=0)
|
||||
{
|
||||
if (t._nextIndex[index] == null)
|
||||
t._nextIndex[index] = new TreeTrie<V>(c);
|
||||
t = t._nextIndex[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
TreeTrie<V> n=null;
|
||||
for (int i=t._nextOther.size();i-->0;)
|
||||
{
|
||||
n=t._nextOther.get(i);
|
||||
if (n._c==c)
|
||||
break;
|
||||
n=null;
|
||||
}
|
||||
if (n==null)
|
||||
{
|
||||
n=new TreeTrie<V>(c);
|
||||
t._nextOther.add(n);
|
||||
}
|
||||
t=n;
|
||||
}
|
||||
}
|
||||
t._key=v==null?null:s;
|
||||
V old=t._value;
|
||||
t._value = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
public V remove(String s)
|
||||
{
|
||||
V o=get(s);
|
||||
put(s,null);
|
||||
return o;
|
||||
}
|
||||
|
||||
public V get(String s)
|
||||
{
|
||||
TreeTrie<V> t = this;
|
||||
int len = s.length();
|
||||
for(int i=0; i < len; i++)
|
||||
{
|
||||
char c=s.charAt(i);
|
||||
int index=c>=0&&c<0x7f?__lookup[c]:-1;
|
||||
if (index>=0)
|
||||
{
|
||||
if (t._nextIndex[index] == null)
|
||||
return null;
|
||||
t = t._nextIndex[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
TreeTrie<V> n=null;
|
||||
for (int j=t._nextOther.size();j-->0;)
|
||||
{
|
||||
n=t._nextOther.get(j);
|
||||
if (n._c==c)
|
||||
break;
|
||||
n=null;
|
||||
}
|
||||
if (n==null)
|
||||
return null;
|
||||
t=n;
|
||||
}
|
||||
}
|
||||
return t._value;
|
||||
}
|
||||
|
||||
public V get(ByteBuffer b,int offset,int len)
|
||||
{
|
||||
TreeTrie<V> t = this;
|
||||
for(int i=0; i < len; i++)
|
||||
{
|
||||
byte c=b.get(offset+i);
|
||||
int index=c>=0&&c<0x7f?__lookup[c]:-1;
|
||||
if (index>=0)
|
||||
{
|
||||
if (t._nextIndex[index] == null)
|
||||
return null;
|
||||
t = t._nextIndex[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
TreeTrie<V> n=null;
|
||||
for (int j=t._nextOther.size();j-->0;)
|
||||
{
|
||||
n=t._nextOther.get(j);
|
||||
if (n._c==c)
|
||||
break;
|
||||
n=null;
|
||||
}
|
||||
if (n==null)
|
||||
return null;
|
||||
t=n;
|
||||
}
|
||||
}
|
||||
return t._value;
|
||||
}
|
||||
|
||||
public V getBest(byte[] b,int offset,int len)
|
||||
{
|
||||
TreeTrie<V> t = this;
|
||||
for(int i=0; i < len; i++)
|
||||
{
|
||||
byte c=b[offset+i];
|
||||
int index=c>=0&&c<0x7f?__lookup[c]:-1;
|
||||
if (index>=0)
|
||||
{
|
||||
if (t._nextIndex[index] == null)
|
||||
return null;
|
||||
t = t._nextIndex[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
TreeTrie<V> n=null;
|
||||
for (int j=t._nextOther.size();j-->0;)
|
||||
{
|
||||
n=t._nextOther.get(j);
|
||||
if (n._c==c)
|
||||
break;
|
||||
n=null;
|
||||
}
|
||||
if (n==null)
|
||||
return null;
|
||||
t=n;
|
||||
}
|
||||
|
||||
// Is the next Trie is a match
|
||||
if (t._key!=null)
|
||||
{
|
||||
// Recurse so we can remember this possibility
|
||||
V best=t.getBest(b,offset+i+1,len-i-1);
|
||||
if (best!=null)
|
||||
return best;
|
||||
return t._value;
|
||||
}
|
||||
}
|
||||
return t._value;
|
||||
}
|
||||
|
||||
public V getBest(ByteBuffer b,int offset,int len)
|
||||
{
|
||||
if (b.hasArray())
|
||||
return getBest(b.array(),b.arrayOffset()+b.position()+offset,len);
|
||||
return getBestByteBuffer(b,offset,len);
|
||||
}
|
||||
|
||||
private V getBestByteBuffer(ByteBuffer b,int offset,int len)
|
||||
{
|
||||
TreeTrie<V> t = this;
|
||||
int pos=b.position()+offset;
|
||||
for(int i=0; i < len; i++)
|
||||
{
|
||||
byte c=b.get(pos++);
|
||||
int index=c>=0&&c<0x7f?__lookup[c]:-1;
|
||||
if (index>=0)
|
||||
{
|
||||
if (t._nextIndex[index] == null)
|
||||
return null;
|
||||
t = t._nextIndex[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
TreeTrie<V> n=null;
|
||||
for (int j=t._nextOther.size();j-->0;)
|
||||
{
|
||||
n=t._nextOther.get(j);
|
||||
if (n._c==c)
|
||||
break;
|
||||
n=null;
|
||||
}
|
||||
if (n==null)
|
||||
return null;
|
||||
t=n;
|
||||
}
|
||||
|
||||
// Is the next Trie is a match
|
||||
if (t._key!=null)
|
||||
{
|
||||
// Recurse so we can remember this possibility
|
||||
V best=t.getBest(b,offset+i+1,len-i-1);
|
||||
if (best!=null)
|
||||
return best;
|
||||
return t._value;
|
||||
}
|
||||
}
|
||||
return t._value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder buf = new StringBuilder();
|
||||
toString(buf,this);
|
||||
|
||||
if (buf.length()==0)
|
||||
return "{}";
|
||||
|
||||
buf.setCharAt(0,'{');
|
||||
buf.append('}');
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
|
||||
private static <V> void toString(Appendable out, TreeTrie<V> t)
|
||||
{
|
||||
if (t != null)
|
||||
{
|
||||
if (t._value!=null)
|
||||
{
|
||||
try
|
||||
{
|
||||
out.append(',');
|
||||
out.append(t._key);
|
||||
out.append('=');
|
||||
out.append(t._value.toString());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0; i < INDEX; i++)
|
||||
{
|
||||
if (t._nextIndex[i] != null)
|
||||
toString(out,t._nextIndex[i]);
|
||||
}
|
||||
for (int i=t._nextOther.size();i-->0;)
|
||||
toString(out,t._nextOther.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
public Set<String> keySet()
|
||||
{
|
||||
Set<String> keys = new HashSet<>();
|
||||
keySet(keys,this);
|
||||
return keys;
|
||||
}
|
||||
|
||||
private static <V> void keySet(Set<String> set, TreeTrie<V> t)
|
||||
{
|
||||
if (t != null)
|
||||
{
|
||||
if (t._key!=null)
|
||||
set.add(t._key);
|
||||
|
||||
for(int i=0; i < INDEX; i++)
|
||||
{
|
||||
if (t._nextIndex[i] != null)
|
||||
keySet(set,t._nextIndex[i]);
|
||||
}
|
||||
for (int i=t._nextOther.size();i-->0;)
|
||||
keySet(set,t._nextOther.get(i));
|
||||
}
|
||||
}
|
||||
}
|
@ -18,10 +18,7 @@
|
||||
|
||||
package org.eclipse.jetty.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
@ -29,185 +26,33 @@ import java.util.Set;
|
||||
/** A Trie String lookup data structure.
|
||||
* @param <V>
|
||||
*/
|
||||
public class Trie<V>
|
||||
public interface Trie<V>
|
||||
{
|
||||
/**
|
||||
* The Size of a Trie row is how many characters can be looked
|
||||
* up directly without going to a big index. This is set at
|
||||
* 32 to cover case insensitive alphabet and a few other common
|
||||
* characters.
|
||||
*/
|
||||
private static final int ROW_SIZE = 32;
|
||||
|
||||
/**
|
||||
* The index lookup table, this maps a character as a byte
|
||||
* (ISO-8859-1 or UTF8) to an index within a Trie row
|
||||
*/
|
||||
private static final int[] __lookup =
|
||||
{ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
/*0*/-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
/*1*/-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 30,
|
||||
/*2*/31, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, -1, 27, -1, -1,
|
||||
/*3*/-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 28, 29, -1, -1, -1, -1,
|
||||
/*4*/-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
/*5*/15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
|
||||
/*6*/-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
/*7*/15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* The first ROW_SIZE entries are for row 0, then next ROW_SIZE
|
||||
* entries are for row 1 etc. So in general instead of using
|
||||
* _rows[row][index], we use _rows[row*ROW_SIZE+index] to look up
|
||||
* the next row for a given character.
|
||||
*
|
||||
* The array is of characters rather than integers to save space.
|
||||
*/
|
||||
private final char[] _rowIndex;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* A big index for each row.
|
||||
* If a character outside of the lookup map is needed,
|
||||
* then a big index will be created for the row, with
|
||||
* 256 entries, one for each possible byte.
|
||||
*/
|
||||
private char[][] _bigIndex;
|
||||
|
||||
/**
|
||||
* The number of rows allocated
|
||||
*/
|
||||
private char _rows;
|
||||
|
||||
public Trie()
|
||||
{
|
||||
this(128);
|
||||
}
|
||||
|
||||
public Trie(int capacityInNodes)
|
||||
{
|
||||
_value=new Object[capacityInNodes];
|
||||
_rowIndex=new char[capacityInNodes*32];
|
||||
_key=new String[capacityInNodes];
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Put and entry into the Trie
|
||||
* @param s The key for the entry
|
||||
* @param v The value of the entry
|
||||
* @return True if the Trie had capacity to add the field.
|
||||
*/
|
||||
public boolean put(String s, V v)
|
||||
{
|
||||
int t=0;
|
||||
int k;
|
||||
int limit = s.length();
|
||||
for(k=0; k < limit; k++)
|
||||
{
|
||||
char c=s.charAt(k);
|
||||
|
||||
int index=__lookup[c&0x7f];
|
||||
if (index>=0)
|
||||
{
|
||||
int idx=t*ROW_SIZE+index;
|
||||
t=_rowIndex[idx];
|
||||
if (t==0)
|
||||
{
|
||||
if (_rows==_value.length)
|
||||
return false;
|
||||
t=_rowIndex[idx]=++_rows;
|
||||
}
|
||||
}
|
||||
else if (c>127)
|
||||
throw new IllegalArgumentException("non ascii character");
|
||||
else
|
||||
{
|
||||
if (_bigIndex==null)
|
||||
_bigIndex=new char[_value.length][];
|
||||
char[] big=_bigIndex[t];
|
||||
if (big==null)
|
||||
big=_bigIndex[t]=new char[128];
|
||||
t=big[c];
|
||||
if (t==0)
|
||||
{
|
||||
if (_rows==_value.length)
|
||||
return false;
|
||||
t=big[c]=++_rows;
|
||||
}
|
||||
}
|
||||
}
|
||||
_key[t]=v==null?null:s;
|
||||
V old=(V)_value[t];
|
||||
_value[t] = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public boolean put(String s, V v);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Put a value as both a key and a value.
|
||||
* @param v
|
||||
* @return
|
||||
* @param v The value and key
|
||||
* @return True if the Trie had capacity to add the field.
|
||||
*/
|
||||
public boolean put(V v)
|
||||
{
|
||||
return put(v.toString(),v);
|
||||
}
|
||||
|
||||
public V remove(String s)
|
||||
{
|
||||
V o=get(s);
|
||||
put(s,null);
|
||||
return o;
|
||||
}
|
||||
public boolean put(V v);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public V remove(String s);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get and exact match from a String key
|
||||
* @param s The key
|
||||
* @return
|
||||
*/
|
||||
public V get(String s)
|
||||
{
|
||||
int t = 0;
|
||||
int len = s.length();
|
||||
for(int i=0; i < len; i++)
|
||||
{
|
||||
char c=s.charAt(i);
|
||||
int index=__lookup[c&0x7f];
|
||||
if (index>=0)
|
||||
{
|
||||
int idx=t*ROW_SIZE+index;
|
||||
t=_rowIndex[idx];
|
||||
if (t==0)
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
char[] big = _bigIndex==null?null:_bigIndex[t];
|
||||
if (big==null)
|
||||
return null;
|
||||
t=big[c];
|
||||
if (t==0)
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return (V)_value[t];
|
||||
}
|
||||
|
||||
public V get(String s);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get and exact match from a segment of a ByteBuufer as key
|
||||
* @param b The buffer
|
||||
@ -215,32 +60,7 @@ public class Trie<V>
|
||||
* @param len the length of the key
|
||||
* @return The value or null if not found
|
||||
*/
|
||||
public V get(ByteBuffer b,int offset,int len)
|
||||
{
|
||||
int t = 0;
|
||||
for(int i=0; i < len; i++)
|
||||
{
|
||||
byte c=b.get(offset+i);
|
||||
int index=__lookup[c&0x7f];
|
||||
if (index>=0)
|
||||
{
|
||||
int idx=t*ROW_SIZE+index;
|
||||
t=_rowIndex[idx];
|
||||
if (t==0)
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
char[] big = _bigIndex==null?null:_bigIndex[t];
|
||||
if (big==null)
|
||||
return null;
|
||||
t=big[c];
|
||||
if (t==0)
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return (V)_value[t];
|
||||
}
|
||||
public V get(ByteBuffer b,int offset,int len);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the best match from key in a byte array.
|
||||
@ -250,46 +70,7 @@ public class Trie<V>
|
||||
* @param len the length of the key
|
||||
* @return The value or null if not found
|
||||
*/
|
||||
public V getBest(byte[] b,int offset,int len)
|
||||
{
|
||||
return getBest(0,b,offset,len);
|
||||
}
|
||||
|
||||
private V getBest(int t,byte[] b,int offset,int len)
|
||||
{
|
||||
for(int i=0; i < len; i++)
|
||||
{
|
||||
byte c=b[offset+i];
|
||||
int index=__lookup[c&0x7f];
|
||||
if (index>=0)
|
||||
{
|
||||
int idx=t*ROW_SIZE+index;
|
||||
t=_rowIndex[idx];
|
||||
if (t==0)
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
char[] big = _bigIndex==null?null:_bigIndex[t];
|
||||
if (big==null)
|
||||
return null;
|
||||
t=big[c];
|
||||
if (t==0)
|
||||
return null;
|
||||
}
|
||||
|
||||
// Is the next Trie is a match
|
||||
if (_key[t]!=null)
|
||||
{
|
||||
// Recurse so we can remember this possibility
|
||||
V best=getBest(t,b,offset+i+1,len-i-1);
|
||||
if (best!=null)
|
||||
return best;
|
||||
return (V)_value[t];
|
||||
}
|
||||
}
|
||||
return (V)_value[t];
|
||||
}
|
||||
public V getBest(byte[] b,int offset,int len);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the best match from key in a byte buffer.
|
||||
@ -299,127 +80,8 @@ public class Trie<V>
|
||||
* @param len the length of the key
|
||||
* @return The value or null if not found
|
||||
*/
|
||||
public V getBest(ByteBuffer b,int offset,int len)
|
||||
{
|
||||
if (b.hasArray())
|
||||
return getBest(0,b.array(),b.arrayOffset()+b.position()+offset,len);
|
||||
return getBest(0,b,offset,len);
|
||||
}
|
||||
|
||||
private V getBest(int t,ByteBuffer b,int offset,int len)
|
||||
{
|
||||
int pos=b.position()+offset;
|
||||
for(int i=0; i < len; i++)
|
||||
{
|
||||
byte c=b.get(pos++);
|
||||
int index=__lookup[c&0x7f];
|
||||
if (index>=0)
|
||||
{
|
||||
int idx=t*ROW_SIZE+index;
|
||||
t=_rowIndex[idx];
|
||||
if (t==0)
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
char[] big = _bigIndex==null?null:_bigIndex[t];
|
||||
if (big==null)
|
||||
return null;
|
||||
t=big[c];
|
||||
if (t==0)
|
||||
return null;
|
||||
}
|
||||
|
||||
// Is the next Trie is a match
|
||||
if (_key[t]!=null)
|
||||
{
|
||||
// Recurse so we can remember this possibility
|
||||
V best=getBest(t,b,offset+i+1,len-i-1);
|
||||
if (best!=null)
|
||||
return best;
|
||||
return (V)_value[t];
|
||||
}
|
||||
}
|
||||
return (V)_value[t];
|
||||
}
|
||||
|
||||
|
||||
|
||||
public V getBest(ByteBuffer b,int offset,int len);
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder buf = new StringBuilder();
|
||||
toString(buf,0);
|
||||
|
||||
if (buf.length()==0)
|
||||
return "{}";
|
||||
|
||||
buf.setCharAt(0,'{');
|
||||
buf.append('}');
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
|
||||
private <V> void toString(Appendable out, int t)
|
||||
{
|
||||
if (_value[t]!=null)
|
||||
{
|
||||
try
|
||||
{
|
||||
out.append(',');
|
||||
out.append(_key[t]);
|
||||
out.append('=');
|
||||
out.append(_value[t].toString());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0; i < ROW_SIZE; i++)
|
||||
{
|
||||
int idx=t*ROW_SIZE+i;
|
||||
if (_rowIndex[idx] != 0)
|
||||
toString(out,_rowIndex[idx]);
|
||||
}
|
||||
|
||||
char[] big = _bigIndex==null?null:_bigIndex[t];
|
||||
if (big!=null)
|
||||
{
|
||||
for (int i:big)
|
||||
if (i!=0)
|
||||
toString(out,i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Set<String> keySet()
|
||||
{
|
||||
Set<String> keys = new HashSet<>();
|
||||
keySet(keys,0);
|
||||
return keys;
|
||||
}
|
||||
|
||||
private void keySet(Set<String> set, int t)
|
||||
{
|
||||
if (_value[t]!=null)
|
||||
set.add(_key[t]);
|
||||
|
||||
for(int i=0; i < ROW_SIZE; i++)
|
||||
{
|
||||
int idx=t*ROW_SIZE+i;
|
||||
if (_rowIndex[idx] != 0)
|
||||
keySet(set,_rowIndex[idx]);
|
||||
}
|
||||
|
||||
char[] big = _bigIndex==null?null:_bigIndex[t];
|
||||
if (big!=null)
|
||||
{
|
||||
for (int i:big)
|
||||
if (i!=0)
|
||||
keySet(set,i);
|
||||
}
|
||||
}
|
||||
/* ------------------------------------------------------------ */
|
||||
public Set<String> keySet();
|
||||
}
|
||||
|
@ -19,7 +19,6 @@
|
||||
package org.eclipse.jetty.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
@ -24,7 +24,6 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -35,8 +35,6 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.StringReader;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.servlet.MultipartConfigElement;
|
||||
@ -44,9 +42,7 @@ import javax.servlet.ServletException;
|
||||
import javax.servlet.http.Part;
|
||||
|
||||
import org.eclipse.jetty.util.MultiPartInputStreamParser.MultiPart;
|
||||
import org.hamcrest.core.IsNot;
|
||||
import org.junit.Test;
|
||||
import org.hamcrest.core.IsNot;
|
||||
|
||||
/**
|
||||
* MultiPartInputStreamTest
|
||||
|
@ -18,7 +18,9 @@
|
||||
|
||||
package org.eclipse.jetty.util;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -20,14 +20,35 @@ package org.eclipse.jetty.util;
|
||||
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
|
||||
@RunWith(value = Parameterized.class)
|
||||
public class TrieTest
|
||||
{
|
||||
Trie<Integer> trie = new Trie<>();
|
||||
@Parameterized.Parameters
|
||||
public static Collection<Object[]> data()
|
||||
{
|
||||
Object[][] data = new Object[][]{
|
||||
{new ArrayTrie<String>()},
|
||||
{new TreeTrie<Integer>()}
|
||||
};
|
||||
return Arrays.asList(data);
|
||||
}
|
||||
|
||||
Trie<Integer> trie;
|
||||
|
||||
public TrieTest(Trie<Integer> t)
|
||||
{
|
||||
trie=t;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before()
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
package org.eclipse.jetty.util.resource;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -18,6 +18,8 @@
|
||||
|
||||
package org.eclipse.jetty.util.thread;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
@ -28,8 +30,6 @@ import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@RunWith(AdvancedRunner.class)
|
||||
public class QueuedThreadPoolTest
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user