1 /*******************************************************************************
\r
2 * Copyright (c) 2007- VTT Technical Research Centre of Finland.
\r
3 * All rights reserved. This program and the accompanying materials
\r
4 * are made available under the terms of the Eclipse Public License v1.0
\r
5 * which accompanies this distribution, and is available at
\r
6 * http://www.eclipse.org/legal/epl-v10.html
\r
9 * VTT Technical Research Centre of Finland - initial API and implementation
\r
10 *******************************************************************************/
\r
12 * Created on Jan 21, 2005
\r
14 * Copyright Toni Kalajainen
\r
16 * Licensed under the Apache License, Version 2.0 (the "License");
\r
17 * you may not use this file except in compliance with the License.
\r
18 * You may obtain a copy of the License at
\r
20 * http://www.apache.org/licenses/LICENSE-2.0
\r
22 * Unless required by applicable law or agreed to in writing, software
\r
23 * distributed under the License is distributed on an "AS IS" BASIS,
\r
24 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
25 * See the License for the specific language governing permissions and
\r
26 * limitations under the License.
\r
28 package org.simantics.databoard.util;
\r
30 import java.util.ArrayList;
\r
31 import java.util.Collection;
\r
32 import java.util.Collections;
\r
33 import java.util.HashMap;
\r
34 import java.util.Map;
\r
35 import java.util.Map.Entry;
\r
36 import java.util.Set;
\r
39 * Bijection map is a Map that has no values or keys, only 1:1 mappings
\r
40 * of values. These value/keys will be called with left and right side
\r
43 * Each value can exist only once on a side
\r
45 * @author Toni Kalajainen
\r
47 public class BijectionMap<L, R> {
\r
49 /** The keys of tableLeft are left-side-values and
\r
50 * values are right-side-values */
\r
51 private final Map<L, R> tableLeft = new HashMap<L, R>();
\r
52 /** The keys of tableRight are right-side-values and
\r
53 * values on it are left-side-values */
\r
54 private final Map<R, L> tableRight = new HashMap<R, L>();
\r
56 /** The keys of tableLeft are left-side-values and
\r
57 * values are right-side-values */
\r
58 private final Map<L, R> imTableLeft = Collections.unmodifiableMap(tableLeft);
\r
59 /** The keys of tableRight are right-side-values and
\r
60 * values on it are left-side-values */
\r
61 private final Map<R, L> imTableRight = Collections.unmodifiableMap(tableRight);
\r
63 private final Set<L> imLeftSet = Collections.unmodifiableSet(tableLeft.keySet());
\r
64 private final Set<R> imRightSet = Collections.unmodifiableSet(tableRight.keySet());
\r
66 public BijectionMap() {
\r
70 public BijectionMap(BijectionMap<L, R> copyFrom) {
\r
71 this.tableLeft.putAll(copyFrom.tableLeft);
\r
72 this.tableRight.putAll(copyFrom.tableRight);
\r
75 public void addAll(BijectionMap<L, R> map)
\r
77 for (Entry<L, R> e : map.getEntries())
\r
78 map(e.getKey(), e.getValue());
\r
81 public boolean retainAllLeft(Collection<L> values)
\r
83 boolean result = false;
\r
84 Collection<L> remove = new ArrayList<L>(size());
\r
85 for (L lValue : imLeftSet) {
\r
86 if (!values.contains(lValue)) {
\r
91 if (!remove.isEmpty()) {
\r
92 for (L lValue : remove)
\r
93 removeWithLeft(lValue);
\r
98 public boolean retainAllRight(Collection<R> values)
\r
100 boolean result = false;
\r
101 Collection<R> remove = new ArrayList<R>(size());
\r
102 for (R rValue : imRightSet) {
\r
103 if (!values.contains(rValue)) {
\r
104 remove.add(rValue);
\r
108 if (!remove.isEmpty()) {
\r
109 for (R rValue : remove)
\r
110 removeWithRight(rValue);
\r
115 public Set<Entry<L, R>> getEntries()
\r
117 return tableLeft.entrySet();
\r
120 public boolean containsLeft(L leftValue)
\r
122 return tableLeft.containsKey(leftValue);
\r
125 public boolean containsRight(R rightValue)
\r
127 return tableRight.containsKey(rightValue);
\r
130 public boolean contains(L leftValue, R rightValue)
\r
132 if (leftValue==null || rightValue==null) return false;
\r
133 return rightValue.equals(tableLeft.get(leftValue));
\r
136 public void map(L leftValue, R rightValue)
\r
138 if (leftValue == null || rightValue == null)
\r
139 throw new NullPointerException();
\r
140 // Remove possible old mapping
\r
141 R oldRight = tableLeft.remove(leftValue);
\r
142 if (oldRight != null) {
\r
143 tableRight.remove(oldRight);
\r
145 L oldLeft = tableRight.remove(rightValue);
\r
146 if (oldLeft != null) {
\r
147 tableLeft.remove(oldLeft);
\r
151 tableLeft.put(leftValue, rightValue);
\r
152 tableRight.put(rightValue, leftValue);
\r
155 public boolean isEmpty() {
\r
156 return tableLeft.isEmpty();
\r
161 return tableLeft.size();
\r
164 public L getLeft(R rightValue) {
\r
165 return tableRight.get(rightValue);
\r
168 public R getRight(L leftValue) {
\r
169 return tableLeft.get(leftValue);
\r
172 public R removeWithLeft(L leftValue) {
\r
173 R rightValue = tableLeft.remove(leftValue);
\r
174 if (rightValue!=null)
\r
175 tableRight.remove(rightValue);
\r
179 public L removeWithRight(R rightValue) {
\r
180 L leftValue = tableRight.remove(rightValue);
\r
181 if (leftValue!=null)
\r
182 tableLeft.remove(leftValue);
\r
187 * Get set of left values
\r
189 * @return read-only set
\r
191 public Set<L> getLeftSet() {
\r
196 * Get set of right values
\r
198 * @return read-only set
\r
200 public Set<R> getRightSet() {
\r
205 * Get left-to-right map
\r
207 * @return read only map
\r
209 public Map<L, R> getLeftToRightMap() {
\r
210 return imTableLeft;
\r
214 * Get right-to-left map
\r
216 * @return read only map
\r
218 public Map<R, L> getRightToLeftMap() {
\r
219 return imTableRight;
\r
222 public void clear() {
\r
224 tableRight.clear();
\r
228 public String toString() {
\r
230 StringBuilder sb = new StringBuilder();
\r
232 for (Entry<L, R> e : tableLeft.entrySet())
\r
234 if (count++>0) sb.append(", ");
\r
235 sb.append(e.getKey().toString());
\r
237 sb.append(e.getValue().toString());
\r
240 return sb.toString();
\r
244 public BijectionMap<L, R> clone() {
\r
245 return new BijectionMap<L, R>(this);
\r