View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.math4.legacy.linear;
18  
19  import java.util.ConcurrentModificationException;
20  import java.util.HashMap;
21  import java.util.HashSet;
22  import java.util.Map;
23  import java.util.NoSuchElementException;
24  import java.util.Random;
25  import java.util.Set;
26  import java.util.Map.Entry;
27  
28  import org.apache.commons.math4.legacy.core.Field;
29  import org.apache.commons.math4.legacy.core.dfp.Dfp;
30  import org.apache.commons.math4.legacy.core.dfp.DfpField;
31  import org.junit.Assert;
32  import org.junit.Before;
33  import org.junit.Test;
34  
35  
36  @SuppressWarnings("boxing")
37  public class OpenIntToFieldTest {
38  
39      private Map<Integer, Dfp> javaMap = new HashMap<>();
40      private DfpField field = Dfp25.getField();
41  
42      @Before
43      public void setUp() {
44          javaMap.put(50, Dfp25.of(100.0));
45          javaMap.put(75, Dfp25.of(75.0));
46          javaMap.put(25, Dfp25.of(500.0));
47          javaMap.put(Integer.MAX_VALUE, Dfp25.of(Integer.MAX_VALUE));
48          javaMap.put(0, Dfp25.of(-1.0));
49          javaMap.put(1, Dfp25.of(0.0));
50          javaMap.put(33, Dfp25.of(-0.1));
51          javaMap.put(23234234, Dfp25.of(-242343.0));
52          javaMap.put(23321, Dfp25.of (Integer.MIN_VALUE));
53          javaMap.put(-4444, Dfp25.of(332.0));
54          javaMap.put(-1, Dfp25.of(-2323.0));
55          javaMap.put(Integer.MIN_VALUE, Dfp25.of(44.0));
56  
57          /* Add a few more to cause the table to rehash */
58          javaMap.putAll(generate());
59      }
60  
61      private Map<Integer, Dfp> generate() {
62          Map<Integer, Dfp> map = new HashMap<>();
63          Random r = new Random();
64          double dd = 0;
65          for (int i = 0; i < 2000; ++i) {
66              dd = r.nextDouble();
67          }
68          map.put(r.nextInt(), Dfp25.of(dd));
69          return map;
70      }
71  
72      private OpenIntToFieldHashMap<Dfp> createFromJavaMap(Field<Dfp> field) {
73          OpenIntToFieldHashMap<Dfp> map = new OpenIntToFieldHashMap<>(field);
74          for (Map.Entry<Integer, Dfp> mapEntry : javaMap.entrySet()) {
75              map.put(mapEntry.getKey(), mapEntry.getValue());
76          }
77          return map;
78      }
79  
80      @Test
81      public void testPutAndGetWith0ExpectedSize() {
82          OpenIntToFieldHashMap<Dfp> map = new OpenIntToFieldHashMap<>(field,0);
83          assertPutAndGet(map);
84      }
85  
86      @Test
87      public void testPutAndGetWithExpectedSize() {
88          OpenIntToFieldHashMap<Dfp> map = new OpenIntToFieldHashMap<>(field,500);
89          assertPutAndGet(map);
90      }
91  
92      @Test
93      public void testPutAndGet() {
94          OpenIntToFieldHashMap<Dfp> map = new OpenIntToFieldHashMap<>(field);
95          assertPutAndGet(map);
96      }
97  
98      private void assertPutAndGet(OpenIntToFieldHashMap<Dfp> map) {
99          assertPutAndGet(map, 0, new HashSet<>());
100     }
101 
102     private void assertPutAndGet(OpenIntToFieldHashMap<Dfp> map, int mapSize,
103             Set<Integer> keysInMap) {
104         Assert.assertEquals(mapSize, map.size());
105         for (Map.Entry<Integer, Dfp> mapEntry : javaMap.entrySet()) {
106             map.put(mapEntry.getKey(), mapEntry.getValue());
107             if (!keysInMap.contains(mapEntry.getKey())) {
108                 ++mapSize;
109             }
110             Assert.assertEquals(mapSize, map.size());
111             Assert.assertEquals(mapEntry.getValue(), map.get(mapEntry.getKey()));
112         }
113     }
114 
115     @Test
116     public void testPutAbsentOnExisting() {
117         OpenIntToFieldHashMap<Dfp> map = createFromJavaMap(field);
118         int size = javaMap.size();
119         for (Map.Entry<Integer, Dfp> mapEntry : generateAbsent().entrySet()) {
120             map.put(mapEntry.getKey(), mapEntry.getValue());
121             Assert.assertEquals(++size, map.size());
122             Assert.assertEquals(mapEntry.getValue(), map.get(mapEntry.getKey()));
123         }
124     }
125 
126     @Test
127     public void testPutOnExisting() {
128         OpenIntToFieldHashMap<Dfp> map = createFromJavaMap(field);
129         for (Map.Entry<Integer, Dfp> mapEntry : javaMap.entrySet()) {
130             map.put(mapEntry.getKey(), mapEntry.getValue());
131             Assert.assertEquals(javaMap.size(), map.size());
132             Assert.assertEquals(mapEntry.getValue(), map.get(mapEntry.getKey()));
133         }
134     }
135 
136     @Test
137     public void testGetAbsent() {
138         Map<Integer, Dfp> generated = generateAbsent();
139         OpenIntToFieldHashMap<Dfp> map = createFromJavaMap(field);
140 
141         for (Map.Entry<Integer, Dfp> mapEntry : generated.entrySet()) {
142             Assert.assertTrue(field.getZero().equals(map.get(mapEntry.getKey())));
143         }
144     }
145 
146     @Test
147     public void testGetFromEmpty() {
148         OpenIntToFieldHashMap<Dfp> map = new OpenIntToFieldHashMap<>(field);
149         Assert.assertEquals(field.getZero(), map.get(5));
150         Assert.assertEquals(field.getZero(), map.get(0));
151         Assert.assertEquals(field.getZero(), map.get(50));
152     }
153 
154     @Test
155     public void testRemove() {
156         OpenIntToFieldHashMap<Dfp> map = createFromJavaMap(field);
157         int mapSize = javaMap.size();
158         Assert.assertEquals(mapSize, map.size());
159         for (Map.Entry<Integer, Dfp> mapEntry : javaMap.entrySet()) {
160             map.remove(mapEntry.getKey());
161             Assert.assertEquals(--mapSize, map.size());
162             Assert.assertEquals(field.getZero(), map.get(mapEntry.getKey()));
163         }
164 
165         /* Ensure that put and get still work correctly after removals */
166         assertPutAndGet(map);
167     }
168 
169     /* This time only remove some entries */
170     @Test
171     public void testRemove2() {
172         OpenIntToFieldHashMap<Dfp> map = createFromJavaMap(field);
173         int mapSize = javaMap.size();
174         int count = 0;
175         Set<Integer> keysInMap = new HashSet<>(javaMap.keySet());
176         for (Map.Entry<Integer, Dfp> mapEntry : javaMap.entrySet()) {
177             keysInMap.remove(mapEntry.getKey());
178             map.remove(mapEntry.getKey());
179             Assert.assertEquals(--mapSize, map.size());
180             Assert.assertEquals(field.getZero(), map.get(mapEntry.getKey()));
181             if (count++ > 5) {
182                 break;
183             }
184         }
185 
186         /* Ensure that put and get still work correctly after removals */
187         assertPutAndGet(map, mapSize, keysInMap);
188     }
189 
190     @Test
191     public void testRemoveFromEmpty() {
192         OpenIntToFieldHashMap<Dfp> map = new OpenIntToFieldHashMap<>(field);
193         Assert.assertEquals(field.getZero(), map.remove(50));
194     }
195 
196     @Test
197     public void testRemoveAbsent() {
198         Map<Integer, Dfp> generated = generateAbsent();
199 
200         OpenIntToFieldHashMap<Dfp> map = createFromJavaMap(field);
201         int mapSize = map.size();
202 
203         for (Map.Entry<Integer, Dfp> mapEntry : generated.entrySet()) {
204             map.remove(mapEntry.getKey());
205             Assert.assertEquals(mapSize, map.size());
206             Assert.assertEquals(field.getZero(), map.get(mapEntry.getKey()));
207         }
208     }
209 
210     /**
211      * Returns a map with at least 100 elements where each element is absent from javaMap.
212      */
213     private Map<Integer, Dfp> generateAbsent() {
214         Map<Integer, Dfp> generated = new HashMap<>();
215         do {
216             generated.putAll(generate());
217             for (Integer key : javaMap.keySet()) {
218                 generated.remove(key);
219             }
220         } while (generated.size() < 100);
221         return generated;
222     }
223 
224     @Test
225     public void testCopy() {
226         OpenIntToFieldHashMap<Dfp> copy =
227             new OpenIntToFieldHashMap<>(createFromJavaMap(field));
228         Assert.assertEquals(javaMap.size(), copy.size());
229 
230         for (Map.Entry<Integer, Dfp> mapEntry : javaMap.entrySet()) {
231             Assert.assertEquals(mapEntry.getValue(), copy.get(mapEntry.getKey()));
232         }
233     }
234 
235     @Test
236     public void testContainsKey() {
237         OpenIntToFieldHashMap<Dfp> map = createFromJavaMap(field);
238         for (Entry<Integer, Dfp> mapEntry : javaMap.entrySet()) {
239             Assert.assertTrue(map.containsKey(mapEntry.getKey()));
240         }
241         for (Map.Entry<Integer, Dfp> mapEntry : generateAbsent().entrySet()) {
242             Assert.assertFalse(map.containsKey(mapEntry.getKey()));
243         }
244         for (Entry<Integer, Dfp> mapEntry : javaMap.entrySet()) {
245             int key = mapEntry.getKey();
246             Assert.assertTrue(map.containsKey(key));
247             map.remove(key);
248             Assert.assertFalse(map.containsKey(key));
249         }
250     }
251 
252     @Test
253     public void testIterator() {
254         OpenIntToFieldHashMap<Dfp> map = createFromJavaMap(field);
255         OpenIntToFieldHashMap<Dfp>.Iterator iterator = map.iterator();
256         for (int i = 0; i < map.size(); ++i) {
257             Assert.assertTrue(iterator.hasNext());
258             iterator.advance();
259             int key = iterator.key();
260             Assert.assertTrue(map.containsKey(key));
261             Assert.assertEquals(javaMap.get(key), map.get(key));
262             Assert.assertEquals(javaMap.get(key), iterator.value());
263             Assert.assertTrue(javaMap.containsKey(key));
264         }
265         Assert.assertFalse(iterator.hasNext());
266         try {
267             iterator.advance();
268             Assert.fail("an exception should have been thrown");
269         } catch (NoSuchElementException nsee) {
270             // expected
271         }
272     }
273 
274     @Test
275     public void testConcurrentModification() {
276         OpenIntToFieldHashMap<Dfp> map = createFromJavaMap(field);
277         OpenIntToFieldHashMap<Dfp>.Iterator iterator = map.iterator();
278         map.put(3, Dfp25.of(3));
279         try {
280             iterator.advance();
281             Assert.fail("an exception should have been thrown");
282         } catch (ConcurrentModificationException cme) {
283             // expected
284         }
285     }
286 
287     /**
288      * Regression test for a bug in findInsertionIndex where the hashing in the second probing
289      * loop was inconsistent with the first causing duplicate keys after the right sequence
290      * of puts and removes.
291      */
292     @Test
293     public void testPutKeysWithCollisions() {
294         OpenIntToFieldHashMap<Dfp> map = new OpenIntToFieldHashMap<>(field);
295         int key1 = -1996012590;
296         Dfp value1 = Dfp25.of(1);
297         map.put(key1, value1);
298         int key2 = 835099822;
299         map.put(key2, value1);
300         int key3 = 1008859686;
301         map.put(key3, value1);
302         Assert.assertEquals(value1, map.get(key3));
303         Assert.assertEquals(3, map.size());
304 
305         map.remove(key2);
306         Dfp value2 = Dfp25.of(2);
307         map.put(key3, value2);
308         Assert.assertEquals(value2, map.get(key3));
309         Assert.assertEquals(2, map.size());
310     }
311 
312     /**
313      * Similar to testPutKeysWithCollisions() but exercises the codepaths in a slightly
314      * different manner.
315      */
316     @Test
317     public void testPutKeysWithCollision2() {
318         OpenIntToFieldHashMap<Dfp> map = new OpenIntToFieldHashMap<>(field);
319         int key1 = 837989881;
320         Dfp value1 = Dfp25.of(1);
321         map.put(key1, value1);
322         int key2 = 476463321;
323         map.put(key2, value1);
324         Assert.assertEquals(2, map.size());
325         Assert.assertEquals(value1, map.get(key2));
326 
327         map.remove(key1);
328         Dfp value2 = Dfp25.of(2);
329         map.put(key2, value2);
330         Assert.assertEquals(1, map.size());
331         Assert.assertEquals(value2, map.get(key2));
332     }
333 }