001 /* JAPI - (Yet another (hopefully) useful) Java API
002 *
003 * Copyright (C) 2004-2006 Christian Hujer
004 *
005 * This program is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU General Public License as
007 * published by the Free Software Foundation; either version 2 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful, but
011 * WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013 * General Public License for more details.
014 *
015 * You should have received a copy of the GNU General Public License
016 * along with this program; if not, write to the Free Software
017 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
018 * 02111-1307, USA.
019 */
020
021 package net.sf.japi.util;
022
023 import java.util.Collection;
024 import java.util.HashSet;
025 import java.util.Iterator;
026 import java.util.Set;
027
028 /** A special Collection class that is like a Map but which allows duplicate keys.
029 * Only duplicate key/value pairs aren't allowed.
030 * The key therefor is named first, the value second.
031 * Uniqueness is gained with Key/Value pairs.
032 * @author <a href="mailto:chris@riedquat.de">Christian Hujer</a>
033 */
034 @SuppressWarnings({"BooleanMethodNameMustStartWithQuestion"})
035 public class Table<T1,T2> {
036
037 /** The pairs of the table. */
038 private Set<Pair<T1,T2>> pairs = new HashSet<Pair<T1,T2>>();
039
040 /** Create a table. */
041 public Table() {
042 }
043
044 /** Completely Clear the table. */
045 public void clear() {
046 pairs.clear();
047 }
048
049 /** Get all firsts that match the second.
050 * @param second second to match
051 * @return all firsts that match second
052 */
053 public Collection<T1> getFirstsBySecond(final T2 second) {
054 final Set<T1> firsts = new HashSet<T1>();
055 for (final Pair<T1, T2> pair : pairs) {
056 final T2 pairSecond = pair.getSecond();
057 if (pairSecond.equals(second)) {
058 firsts.add(pair.getFirst());
059 }
060 }
061 return firsts;
062 }
063
064 /** Get all pairs that match the first.
065 * @param first first to match
066 * @return all pairs that match first
067 */
068 public Collection<Pair<T1,T2>> getPairsByFirst(final T1 first) {
069 final Set<Pair<T1,T2>> pairsByFirst = new HashSet<Pair<T1,T2>>();
070 for (Pair<T1, T2> pair : pairs) {
071 final T1 pairFirst = pair.getFirst();
072 if (pairFirst.equals(first)) {
073 pairsByFirst.add(pair);
074 }
075 }
076 return pairsByFirst;
077 }
078
079 /** Get all pairs that match the second.
080 * @param second second to match
081 * @return all pairs that match second
082 */
083 public Collection<Pair<T1,T2>> getPairsBySecond(final T2 second) {
084 final Set<Pair<T1,T2>> pairsBySecond = new HashSet<Pair<T1,T2>>();
085 for (Pair<T1, T2> pair : pairs) {
086 final T2 pairSecond = pair.getSecond();
087 if (pairSecond.equals(second)) {
088 pairsBySecond.add(pair);
089 }
090 }
091 return pairsBySecond;
092 }
093
094 /** Get all seconds that match the first.
095 * @param first first to match
096 * @return all seconds that match first
097 */
098 public Collection<T2> getSecondsByFirst(final T1 first) {
099 final Set<T2> seconds = new HashSet<T2>();
100 for (final Pair<T1, T2> pair : pairs) {
101 final T1 pairFirst = pair.getFirst();
102 if (pairFirst.equals(first)) {
103 seconds.add(pair.getSecond());
104 }
105 }
106 return seconds;
107 }
108
109 /** Put a pair into the table.
110 * @param pair pair to put into the table
111 * @return <code>true</code> if the table did not already contain that <var>pair</var>, otherwise <code>false</code>
112 */
113 public boolean putPair(final Pair<T1,T2> pair) {
114 return pairs.add(pair);
115 }
116
117 /** Put a pair into the table.
118 * @param t1 first of pair
119 * @param t2 second of pair
120 * @return <code>true</code> if the table did not already contain that <var>pair</var>, otherwise <code>false</code>
121 */
122 public boolean putPair(final T1 t1, final T2 t2) {
123 return pairs.add(new Pair<T1,T2>(t1, t2));
124 }
125
126 /** Remove all pairs that match a first.
127 * @param first first to match
128 * @return whether a matching pair was removed
129 * @retval <code>true</code> if at least one pair was removed
130 * @retval <code>false</code> if no matching pairs were found
131 */
132 public boolean removeAllFirst(final T1 first) {
133 boolean ret = false;
134 //noinspection ForLoopWithMissingComponent
135 for (final Iterator<Pair<T1,T2>> it = pairs.iterator(); it.hasNext();) {
136 final Pair<T1,T2> pair = it.next();
137 final T1 pairFirst = pair.getFirst();
138 if (pairFirst.equals(first)) {
139 it.remove();
140 ret = true;
141 }
142 }
143 return ret;
144 }
145
146 /** Remove all pairs that match a second.
147 * @param second second to match
148 * @return whether a matching pair was removed
149 * @retval <code>true</code> if at least one pair was removed
150 * @retval <code>false</code> if no matching pairs were found
151 */
152 public boolean removeAllSecond(final T2 second) {
153 boolean ret = false;
154 //noinspection ForLoopWithMissingComponent
155 for (final Iterator<Pair<T1,T2>> it = pairs.iterator(); it.hasNext();) {
156 final Pair<T1,T2> pair = it.next();
157 final T2 pairSecond = pair.getSecond();
158 if (pairSecond.equals(second)) {
159 it.remove();
160 ret = true;
161 }
162 }
163 return ret;
164 }
165
166 /** Remove a pair from the table.
167 * @param pair pair to remove
168 * @return <code>true</code> if the table contained the <var>pair</var>, thus the <var>pair</var> was successfully removed, otherwise <code>false</code>
169 */
170 public boolean removePair(final Pair<T1,T2> pair) {
171 return pairs.remove(pair);
172 }
173
174 /** Remove a pair into the table.
175 * @param t1 first of pair
176 * @param t2 second of pair
177 * @return <code>true</code> if the table did not already contain that <var>pair</var>, otherwise <code>false</code>
178 */
179 public boolean removePair(final T1 t1, final T2 t2) {
180 return pairs.remove(new Pair<T1,T2>(t1, t2));
181 }
182
183 /** Get the size of the table.
184 * @return size of the table
185 */
186 public int size() {
187 return pairs.size();
188 }
189
190 } // class Table