View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 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 }