1 //
2 // ========================================================================
3 // Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // All rights reserved. This program and the accompanying materials
6 // are made available under the terms of the Eclipse Public License v1.0
7 // and Apache License v2.0 which accompanies this distribution.
8 //
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
11 //
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
14 //
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
17 //
18
19 package org.eclipse.jetty.util;
20
21 import java.nio.ByteBuffer;
22 import java.util.AbstractMap;
23 import java.util.Collections;
24 import java.util.Comparator;
25 import java.util.Map;
26 import java.util.Set;
27 import java.util.TreeMap;
28
29 /* ------------------------------------------------------------ */
30 /** Map implementation Optimized for Strings keys..
31 * This String Map has been optimized for mapping small sets of
32 * Strings where the most frequently accessed Strings have been put to
33 * the map first.
34 *
35 * It also has the benefit that it can look up entries by substring or
36 * sections of char and byte arrays. This can prevent many String
37 * objects from being created just to look up in the map.
38 *
39 * This map is NOT synchronized.
40 */
41 public class StringMap<O> extends AbstractMap<String,O>
42 {
43 private final TreeMap<Object, O> _map;
44
45
46 public static final boolean CASE_INSENSTIVE=true;
47
48 /* ------------------------------------------------------------ */
49
50 private final boolean _caseInsensitive;
51
52
53 /* ------------------------------------------------------------ */
54 /** Constructor.
55 */
56 public StringMap()
57 {
58 this(false);
59 }
60
61 /* ------------------------------------------------------------ */
62 /** Constructor.
63 * @param ignoreCase
64 */
65 public StringMap(final boolean ignoreCase)
66 {
67 _caseInsensitive=ignoreCase;
68 _map = new TreeMap<Object,O>(new Comparator<Object>()
69 {
70 @Override
71 public int compare(Object o1, Object o2)
72 {
73 String s1=(o1 instanceof String)?(String)o1:null;
74 ByteBuffer b1=(o1 instanceof ByteBuffer)?(ByteBuffer)o1:null;
75 if (s1==null && b1==null)
76 s1=o1.toString();
77 String s2=(String)o2;
78
79 int n1 = s1==null?b1.remaining():s1.length();
80 int n2 = s2.length();
81 int min = Math.min(n1, n2);
82 for (int i = 0; i < min; i++) {
83 char c1 = s1==null?(char)b1.get(b1.position()+i):s1.charAt(i);
84 char c2 = s2.charAt(i);
85 if (c1 != c2) {
86 if (ignoreCase)
87 {
88 c1 = Character.toUpperCase(c1);
89 c2 = Character.toUpperCase(c2);
90 if (c1 != c2) {
91 c1 = Character.toLowerCase(c1);
92 c2 = Character.toLowerCase(c2);
93 if (c1 != c2) {
94 // No overflow because of numeric promotion
95 return c1 - c2;
96 }
97 }
98 }
99 else
100 return c1 - c2;
101 }
102 }
103 return n1 - n2;
104 }
105 });
106 }
107
108 /* ------------------------------------------------------------ */
109 public boolean isIgnoreCase()
110 {
111 return _caseInsensitive;
112 }
113
114 /* ------------------------------------------------------------ */
115 @Override
116 public O put(String key, O value)
117 {
118 return _map.put(key,value);
119 }
120
121 /* ------------------------------------------------------------ */
122 @Override
123 public O get(Object key)
124 {
125 return _map.get(key);
126 }
127
128 /* ------------------------------------------------------------ */
129 public O get(String key)
130 {
131 return _map.get(key);
132 }
133
134 /* ------------------------------------------------------------ */
135 public O get(String key,int offset,int length)
136 {
137 return _map.get(key.substring(offset,offset+length));
138 }
139
140 /* ------------------------------------------------------------ */
141 public O get(ByteBuffer buffer)
142 {
143 return _map.get(buffer);
144 }
145
146 /* ------------------------------------------------------------ */
147 @Override
148 public O remove(Object key)
149 {
150 return _map.remove(key);
151 }
152
153 /* ------------------------------------------------------------ */
154 public O remove(String key)
155 {
156 return _map.remove(key);
157 }
158
159 /* ------------------------------------------------------------ */
160 @Override
161 public Set<Map.Entry<String,O>> entrySet()
162 {
163 Object o=_map.entrySet();
164 return Collections.unmodifiableSet((Set<Map.Entry<String,O>>)o);
165 }
166
167 /* ------------------------------------------------------------ */
168 @Override
169 public int size()
170 {
171 return _map.size();
172 }
173
174 /* ------------------------------------------------------------ */
175 @Override
176 public boolean isEmpty()
177 {
178 return _map.isEmpty();
179 }
180
181 /* ------------------------------------------------------------ */
182 @Override
183 public boolean containsKey(Object key)
184 {
185 return _map.containsKey(key);
186 }
187
188 /* ------------------------------------------------------------ */
189 @Override
190 public void clear()
191 {
192 _map.clear();
193 }
194
195 }