Merge branch 'bug/JAL-2154projectMappings' into merge/develop_bug/JAL-2154projectMappings
[jalview.git] / src / jalview / util / LinkedIdentityHashSet.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.util;
22
23 import java.util.AbstractSet;
24 import java.util.Iterator;
25 import java.util.LinkedHashMap;
26
27 /**
28  * Order preserving Set based on System.identityHashCode() for an object, which
29  * also supports Object->index lookup.
30  * 
31  * @author Jim Procter (2016) based on Evgeniy Dorofeev's response: via
32  *         https://stackoverflow.com/questions/17276658/linkedidentityhashset
33  * 
34  */
35 public class LinkedIdentityHashSet<E> extends AbstractSet<E>
36 {
37   LinkedHashMap<IdentityWrapper, IdentityWrapper> set = new LinkedHashMap<IdentityWrapper, IdentityWrapper>();
38
39   static class IdentityWrapper
40   {
41     Object obj;
42
43     public int p;
44
45     IdentityWrapper(Object obj, int p)
46     {
47       this.obj = obj;
48       this.p = p;
49     }
50
51     @Override
52     public boolean equals(Object obj)
53     {
54       return this.obj == obj;
55     }
56
57     @Override
58     public int hashCode()
59     {
60       return System.identityHashCode(obj);
61     }
62   }
63
64   @Override
65   public boolean add(E e)
66   {
67     IdentityWrapper el = (new IdentityWrapper(e, set.size()));
68     return set.putIfAbsent(el, el) == null;
69   }
70
71   @Override
72   public Iterator<E> iterator()
73   {
74     return new Iterator<E>()
75     {
76       final Iterator<IdentityWrapper> se = set.keySet().iterator();
77
78       @Override
79       public boolean hasNext()
80       {
81         return se.hasNext();
82       }
83
84       @SuppressWarnings("unchecked")
85       @Override
86       public E next()
87       {
88         return (E) se.next().obj;
89       }
90     };
91   }
92
93   @Override
94   public int size()
95   {
96     return set.size();
97   }
98
99   /**
100    * Lookup the index for e in the set
101    * 
102    * @param e
103    * @return position of e in the set when it was added.
104    */
105   public int indexOf(E e)
106   {
107     return set.get(e).p;
108   }
109 }