001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.quercus.env;
031:
032: import java.util.*;
033:
034: /**
035: * Case-insensitive method mapping
036: */
037: public class MethodMap<V> {
038: private Entry<V>[] _entries = new Entry[16];
039: private int _size;
040:
041: public void put(char[] buffer, int length, V value) {
042: if (_entries.length <= _size * 4)
043: resize();
044:
045: int hash = hash(buffer, length);
046:
047: char[] key = new char[length];
048: System.arraycopy(buffer, 0, key, 0, length);
049:
050: int bucket = hash & (_entries.length - 1);
051:
052: Entry<V> entry;
053: for (entry = _entries[bucket]; entry != null; entry = entry._next) {
054: if (match(entry._key, key, key.length)) {
055: entry._value = value;
056:
057: return;
058: }
059: }
060:
061: entry = new Entry<V>(buffer, value);
062:
063: entry._next = _entries[bucket];
064: _entries[bucket] = entry;
065: _size++;
066:
067: }
068:
069: public boolean containsKey(String key) {
070: return get(key) != null;
071: }
072:
073: public V get(int hash, char[] buffer, int length) {
074: int bucket = hash & (_entries.length - 1);
075:
076: for (Entry<V> entry = _entries[bucket]; entry != null; entry = entry._next) {
077: char[] key = entry._key;
078:
079: if (match(key, buffer, length))
080: return entry._value;
081: }
082:
083: return null;
084: }
085:
086: public void put(String keyString, V value) {
087: char[] key = keyString.toCharArray();
088:
089: put(key, key.length, value);
090: }
091:
092: public V get(String keyString) {
093: char[] key = keyString.toCharArray();
094: int hash = hash(key, key.length);
095:
096: return get(hash, key, key.length);
097: }
098:
099: public Iterable<V> values() {
100: return new ValueIterator(_entries);
101: }
102:
103: private boolean match(char[] a, char[] b, int length) {
104: if (a.length != length)
105: return false;
106:
107: for (int i = length - 1; i >= 0; i--) {
108: int chA = a[i];
109: int chB = b[i];
110:
111: if (chA == chB) {
112: }
113: /*
114: else if ((chA & ~0x20) != (chB & ~0x20))
115: return false;
116: */
117: else {
118: if ('A' <= chA && chA <= 'Z')
119: chA += 'a' - 'A';
120:
121: if ('A' <= chB && chB <= 'Z')
122: chB += 'a' - 'A';
123:
124: if (chA != chB)
125: return false;
126: }
127: }
128:
129: return true;
130: }
131:
132: private void resize() {
133: Entry<V>[] newEntries = new Entry[2 * _entries.length];
134:
135: for (int i = 0; i < _entries.length; i++) {
136: Entry<V> entry = _entries[i];
137: while (entry != null) {
138: Entry<V> next = entry._next;
139:
140: int hash = hash(entry._key, entry._key.length);
141: int bucket = hash & (newEntries.length - 1);
142:
143: entry._next = newEntries[bucket];
144: newEntries[bucket] = entry;
145:
146: entry = next;
147: }
148: }
149:
150: _entries = newEntries;
151: }
152:
153: public static int hash(char[] buffer, int length) {
154: int hash = 17;
155:
156: for (length--; length >= 0; length--) {
157: int ch = buffer[length];
158:
159: if ('A' <= ch && ch <= 'Z')
160: ch += 'a' - 'A';
161:
162: hash = 65537 * hash + ch;
163: }
164:
165: return hash;
166: }
167:
168: public static int hash(String string) {
169: int hash = 17;
170:
171: int length = string.length();
172: for (length--; length >= 0; length--) {
173: int ch = string.charAt(length);
174:
175: if ('A' <= ch && ch <= 'Z')
176: ch += 'a' - 'A';
177:
178: hash = 65537 * hash + ch;
179: }
180:
181: return hash;
182: }
183:
184: final static class Entry<V> {
185: final char[] _key;
186: V _value;
187:
188: Entry<V> _next;
189:
190: Entry(char[] key, V value) {
191: _key = key;
192: _value = value;
193: }
194: }
195:
196: final static class ValueIterator<V> implements Iterable<V>,
197: Iterator<V> {
198: int _index;
199: Entry<V>[] _entries;
200: Entry<V> _next;
201:
202: public ValueIterator(Entry<V>[] entries) {
203: _entries = entries;
204:
205: getNext();
206: }
207:
208: private void getNext() {
209: Entry<V> entry = _next == null ? null : _next._next;
210:
211: while (entry == null && _index < _entries.length
212: && (entry = _entries[_index++]) == null) {
213: }
214:
215: _next = entry;
216: }
217:
218: public boolean hasNext() {
219: return _next != null;
220: }
221:
222: public V next() {
223: V value = _next._value;
224:
225: getNext();
226:
227: return value;
228: }
229:
230: public Iterator<V> iterator() {
231: return this ;
232: }
233:
234: public void remove() {
235: throw new UnsupportedOperationException();
236: }
237: }
238: }
|