My favorites | Sign in
Project Home Downloads Wiki Issues Source
Checkout   Browse   Changes    
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
/*
* Copyright 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

package com.google.gwt.user.client.ui;

import com.google.gwt.core.client.JavaScriptObject;

import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* Special-case Map implementation which imposes limits on the types of keys
* that can be used in return for much faster speed. In specific, only strings
* that could be added to a JavaScript object as keys are valid.
*/

class FastStringMap<T> extends AbstractMap<String, T> {
private static class ImplMapEntry<T> implements Map.Entry<String, T> {

private String key;

private T value;

ImplMapEntry(String key, T value) {
this.key = key;
this.value = value;
}

@Override
public boolean equals(Object a) {
if (a instanceof Map.Entry) {
Map.Entry<?, ?> s = (Map.Entry<?, ?>) a;
if (equalsWithNullCheck(key, s.getKey())
&& equalsWithNullCheck(value, s.getValue())) {
return true;
}
}
return false;
}

// strip prefix from key
public String getKey() {
return key;
}

public T getValue() {
return value;
}

@Override
public int hashCode() {
int keyHash = 0;
int valueHash = 0;
if (key != null) {
keyHash = key.hashCode();
}
if (value != null) {
valueHash = value.hashCode();
}
return keyHash ^ valueHash;
}

public T setValue(T object) {
T old = value;
value = object;
return old;
}

private boolean equalsWithNullCheck(Object a, Object b) {
if (a == b) {
return true;
} else if (a == null) {
return false;
} else {
return a.equals(b);
}
}
}

/*
* Accesses need to be prefixed with ':' to prevent conflict with built-in
* JavaScript properties.
*/
private JavaScriptObject map;

public FastStringMap() {
init();
}

@Override
public void clear() {
init();
}

@Override
public boolean containsKey(Object key) {
return containsKey(keyMustBeString(key), map);
}

@Override
public boolean containsValue(Object arg0) {
return values().contains(arg0);
}

@Override
public Set<Map.Entry<String, T>> entrySet() {
return new AbstractSet<Map.Entry<String, T>>() {

@Override
public boolean contains(Object key) {
Map.Entry<?, ?> s = (Map.Entry<?, ?>) key;
Object value = get(s.getKey());
if (value == null) {
return value == s.getValue();
} else {
return value.equals(s.getValue());
}
}

@Override
public Iterator<Map.Entry<String, T>> iterator() {

Iterator<Map.Entry<String, T>> custom = new Iterator<Map.Entry<String, T>>() {
Iterator<String> keys = keySet().iterator();

public boolean hasNext() {
return keys.hasNext();
}

public Map.Entry<String, T> next() {
String key = keys.next();
return new ImplMapEntry<T>(key, get(key));
}

public void remove() {
keys.remove();
}
};
return custom;
}

@Override
public int size() {
return FastStringMap.this.size();
}

};
}

@Override
public T get(Object key) {
return get(keyMustBeString(key));
}

// Prepend ':' to avoid conflicts with built-in Object properties.
public native T get(String key) /*-{
return this.@com.google.gwt.user.client.ui.FastStringMap::map[':' + key];
}-*/;

@Override
public boolean isEmpty() {
return size() == 0;
}

@Override
public Set<String> keySet() {
return new AbstractSet<String>() {
@Override
public boolean contains(Object key) {
return containsKey(key);
}

@Override
public Iterator<String> iterator() {
List<String> l = new ArrayList<String>();
addAllKeysFromJavascriptObject(l, map);
return l.iterator();
}

@Override
public int size() {
return FastStringMap.this.size();
}
};
}

// Prepend ':' to avoid conflicts with built-in Object properties.
@Override
public native T put(String key, T value) /*-{
key = ':' + key;
var map = this.@com.google.gwt.user.client.ui.FastStringMap::map;
var previous = map[key];
map[key] = value;
return previous;
}-*/;

@Override
public void putAll(Map<? extends String, ? extends T> arg0) {
for (Map.Entry<? extends String, ? extends T> entry : arg0.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}

@Override
public T remove(Object key) {
return remove(keyMustBeString(key));
}

// only count keys with ':' prefix
@Override
public native int size() /*-{
var value = this.@com.google.gwt.user.client.ui.FastStringMap::map;
var count = 0;
for(var key in value) {
if (key.charAt(0) == ':') ++count;
}
return count;
}-*/;

@Override
public Collection<T> values() {
List<T> values = new ArrayList<T>();
addAllValuesFromJavascriptObject(values, map);
return values;
}

// only count keys with ':' prefix
private native void addAllKeysFromJavascriptObject(Collection<String> s,
JavaScriptObject javaScriptObject) /*-{
for(var key in javaScriptObject) {
if (key.charAt(0) != ':') continue;
s.@java.util.Collection::add(Ljava/lang/Object;)(key.substring(1));
}
}-*/;

// only count keys with ':' prefix
private native void addAllValuesFromJavascriptObject(Collection<T> s,
JavaScriptObject javaScriptObject) /*-{
for(var key in javaScriptObject) {
if (key.charAt(0) != ':') continue;
var value = javaScriptObject[key];
s.@java.util.Collection::add(Ljava/lang/Object;)(value);
}
}-*/;

// Prepend ':' to avoid conflicts with built-in Object properties.
private native boolean containsKey(String key, JavaScriptObject obj)/*-{
return (':' + key) in obj;
}-*/;

private native void init() /*-{
this.@com.google.gwt.user.client.ui.FastStringMap::map = [];
}-*/;

private String keyMustBeString(Object key) {
if (key instanceof String) {
return (String) key;
} else {
throw new IllegalArgumentException(this.getClass().getName()
+ " can only have Strings as keys, not" + key);
}
}

// Prepend ':' to avoid conflicts with built-in Object properties.
private native T remove(String key) /*-{
key = ':' + key;
var map = this.@com.google.gwt.user.client.ui.FastStringMap::map;
var previous = map[key];
delete map[key];
return previous;
}-*/;
}

Change log

r5739 by rj...@google.com on Jul 15, 2009   Diff
Tagging the 1.7.0 release
Go to: 
Project members, sign in to write a code review

Older revisions

r5660 by fabb...@google.com on Jul 2, 2009   Diff
Creating 1.7 branch from 1.6
r3732 by sco...@google.com on Oct 9, 2008   Diff
Creating 1.6 release branch based on
trunk@3683.

r2487 by sco...@google.com on Apr 17, 2008   Diff
Updates to take advantage of allowing
undefined in Java code.

Review by: spoon (pair prog)
All revisions of this file

File info

Size: 7375 bytes, 291 lines

File properties

svn:mime-type
text/x-java
svn:eol-style
native
Powered by Google Project Hosting