14
14
15
15
import java .util .HashMap ;
16
16
17
+ import com .facebook .infer .annotation .Assertions ;
18
+ import javax .annotation .Nullable ;
19
+
17
20
/**
18
21
* Implementation of a read-only map in native memory. This will generally be constructed and filled
19
22
* in native code so you shouldn't construct one yourself.
@@ -28,24 +31,177 @@ protected ReadableNativeMap(HybridData hybridData) {
28
31
super (hybridData );
29
32
}
30
33
34
+ private @ Nullable String [] mKeys ;
35
+ private @ Nullable HashMap <String ,Object > mLocalMap ;
36
+ private @ Nullable HashMap <String ,ReadableType > mLocalTypeMap ;
37
+ private static boolean mUseNativeAccessor ;
38
+ private static int mJniCallCounter ;
39
+ public static void setUseNativeAccessor (boolean useNativeAccessor ) {
40
+ mUseNativeAccessor = useNativeAccessor ;
41
+ }
42
+ public static int getJNIPassCounter () {
43
+ return mJniCallCounter ;
44
+ }
45
+
46
+ private HashMap <String ,Object > getLocalMap () {
47
+ // Fast return for the common case
48
+ if (mLocalMap != null ) {
49
+ return mLocalMap ;
50
+ }
51
+ // Check and when necessary get keys atomicaly
52
+ synchronized (this ) {
53
+ if (mKeys == null ) {
54
+ mKeys = Assertions .assertNotNull (importKeys ());
55
+ mJniCallCounter ++;
56
+ }
57
+ if (mLocalMap == null ) {
58
+ Object [] values = Assertions .assertNotNull (importValues ());
59
+ mJniCallCounter ++;
60
+ mLocalMap = new HashMap <>();
61
+ for (int i = 0 ; i < mKeys .length ; i ++) {
62
+ mLocalMap .put (mKeys [i ], values [i ]);
63
+ }
64
+ }
65
+ }
66
+ return mLocalMap ;
67
+ }
68
+ private native String [] importKeys ();
69
+ private native Object [] importValues ();
70
+
71
+ private HashMap <String ,ReadableType > getLocalTypeMap () {
72
+ // Fast and non-blocking return for common case
73
+ if (mLocalTypeMap != null ) {
74
+ return mLocalTypeMap ;
75
+ }
76
+ // Check and when necessary get keys
77
+ synchronized (this ) {
78
+ if (mKeys == null ) {
79
+ mKeys = Assertions .assertNotNull (importKeys ());
80
+ mJniCallCounter ++;
81
+ }
82
+ // check that no other thread has already updated
83
+ if (mLocalTypeMap == null ) {
84
+ Object [] types = Assertions .assertNotNull (importTypes ());
85
+ mJniCallCounter ++;
86
+ mLocalTypeMap = new HashMap <>();
87
+ for (int i = 0 ; i < mKeys .length ; i ++) {
88
+ mLocalTypeMap .put (mKeys [i ], (ReadableType ) types [i ]);
89
+ }
90
+ }
91
+ }
92
+ return mLocalTypeMap ;
93
+ }
94
+ private native Object [] importTypes ();
95
+
31
96
@ Override
32
- public native boolean hasKey (String name );
97
+ public boolean hasKey (String name ) {
98
+ if (mUseNativeAccessor ) {
99
+ mJniCallCounter ++;
100
+ return hasKeyNative (name );
101
+ }
102
+ return getLocalMap ().containsKey (name );
103
+ }
104
+ private native boolean hasKeyNative (String name );
105
+
33
106
@ Override
34
- public native boolean isNull (String name );
107
+ public boolean isNull (String name ) {
108
+ if (mUseNativeAccessor ) {
109
+ mJniCallCounter ++;
110
+ return isNullNative (name );
111
+ }
112
+ if (getLocalMap ().containsKey (name )) {
113
+ return getLocalMap ().get (name ) == null ;
114
+ }
115
+ throw new NoSuchKeyException (name );
116
+ }
117
+ private native boolean isNullNative (String name );
118
+
119
+ private Object getValue (String name ) {
120
+ if (hasKey (name ) && !(isNull (name ))) {
121
+ return Assertions .assertNotNull (getLocalMap ().get (name ));
122
+ }
123
+ throw new NoSuchKeyException (name );
124
+ }
125
+ private @ Nullable Object getNullableValue (String name ) {
126
+ if (hasKey (name )) {
127
+ return getLocalMap ().get (name );
128
+ }
129
+ throw new NoSuchKeyException (name );
130
+ }
131
+
35
132
@ Override
36
- public native boolean getBoolean (String name );
133
+ public boolean getBoolean (String name ) {
134
+ if (mUseNativeAccessor ) {
135
+ mJniCallCounter ++;
136
+ return getBooleanNative (name );
137
+ }
138
+ return ((Boolean ) getValue (name )).booleanValue ();
139
+ }
140
+ private native boolean getBooleanNative (String name );
141
+
37
142
@ Override
38
- public native double getDouble (String name );
143
+ public double getDouble (String name ) {
144
+ if (mUseNativeAccessor ) {
145
+ mJniCallCounter ++;
146
+ return getDoubleNative (name );
147
+ }
148
+ return ((Double ) getValue (name )).doubleValue ();
149
+ }
150
+ private native double getDoubleNative (String name );
151
+
39
152
@ Override
40
- public native int getInt (String name );
153
+ public int getInt (String name ) {
154
+ if (mUseNativeAccessor ) {
155
+ mJniCallCounter ++;
156
+ return getIntNative (name );
157
+ }
158
+ // All numbers coming out of native are doubles, so cast here then truncate
159
+ return ((Double ) getValue (name )).intValue ();
160
+ }
161
+ private native int getIntNative (String name );
162
+
41
163
@ Override
42
- public native String getString (String name );
164
+ public @ Nullable String getString (String name ) {
165
+ if (mUseNativeAccessor ) {
166
+ mJniCallCounter ++;
167
+ return getStringNative (name );
168
+ }
169
+ return (String ) getNullableValue (name );
170
+ }
171
+ private native String getStringNative (String name );
172
+
43
173
@ Override
44
- public native ReadableNativeArray getArray (String name );
174
+ public @ Nullable ReadableArray getArray (String name ) {
175
+ if (mUseNativeAccessor ) {
176
+ mJniCallCounter ++;
177
+ return getArrayNative (name );
178
+ }
179
+ return (ReadableArray ) getNullableValue (name );
180
+ }
181
+ private native ReadableNativeArray getArrayNative (String name );
182
+
45
183
@ Override
46
- public native ReadableNativeMap getMap (String name );
184
+ public @ Nullable ReadableNativeMap getMap (String name ) {
185
+ if (mUseNativeAccessor ) {
186
+ mJniCallCounter ++;
187
+ return getMapNative (name );
188
+ }
189
+ return (ReadableNativeMap ) getNullableValue (name );
190
+ }
191
+ private native ReadableNativeMap getMapNative (String name );
192
+
47
193
@ Override
48
- public native ReadableType getType (String name );
194
+ public ReadableType getType (String name ) {
195
+ if (mUseNativeAccessor ) {
196
+ mJniCallCounter ++;
197
+ return getTypeNative (name );
198
+ }
199
+ if (getLocalTypeMap ().containsKey (name )) {
200
+ return Assertions .assertNotNull (getLocalTypeMap ().get (name ));
201
+ }
202
+ throw new NoSuchKeyException (name );
203
+ }
204
+ private native ReadableType getTypeNative (String name );
49
205
50
206
@ Override
51
207
public Dynamic getDynamic (String name ) {
@@ -59,35 +215,42 @@ public ReadableMapKeySetIterator keySetIterator() {
59
215
60
216
@ Override
61
217
public HashMap <String , Object > toHashMap () {
62
- ReadableMapKeySetIterator iterator = keySetIterator ();
63
- HashMap <String , Object > hashMap = new HashMap <>();
64
-
65
- while (iterator .hasNextKey ()) {
66
- String key = iterator .nextKey ();
67
- switch (getType (key )) {
68
- case Null :
69
- hashMap .put (key , null );
70
- break ;
71
- case Boolean :
72
- hashMap .put (key , getBoolean (key ));
73
- break ;
74
- case Number :
75
- hashMap .put (key , getDouble (key ));
76
- break ;
77
- case String :
78
- hashMap .put (key , getString (key ));
79
- break ;
80
- case Map :
81
- hashMap .put (key , getMap (key ).toHashMap ());
82
- break ;
83
- case Array :
84
- hashMap .put (key , getArray (key ).toArrayList ());
85
- break ;
86
- default :
87
- throw new IllegalArgumentException ("Could not convert object with key: " + key + "." );
88
- }
218
+ if (mUseNativeAccessor ) {
219
+ ReadableMapKeySetIterator iterator = keySetIterator ();
220
+ HashMap <String , Object > hashMap = new HashMap <>();
221
+
222
+ while (iterator .hasNextKey ()) {
223
+ // increment for hasNextKey call
224
+ mJniCallCounter ++;
225
+ String key = iterator .nextKey ();
226
+ // increment for nextKey call
227
+ mJniCallCounter ++;
228
+ switch (getType (key )) {
229
+ case Null :
230
+ hashMap .put (key , null );
231
+ break ;
232
+ case Boolean :
233
+ hashMap .put (key , getBoolean (key ));
234
+ break ;
235
+ case Number :
236
+ hashMap .put (key , getDouble (key ));
237
+ break ;
238
+ case String :
239
+ hashMap .put (key , getString (key ));
240
+ break ;
241
+ case Map :
242
+ hashMap .put (key , Assertions .assertNotNull (getMap (key )).toHashMap ());
243
+ break ;
244
+ case Array :
245
+ hashMap .put (key , Assertions .assertNotNull (getArray (key )).toArrayList ());
246
+ break ;
247
+ default :
248
+ throw new IllegalArgumentException ("Could not convert object with key: " + key + "." );
249
+ }
250
+ }
251
+ return hashMap ;
89
252
}
90
- return hashMap ;
253
+ return getLocalMap () ;
91
254
}
92
255
93
256
/**
0 commit comments