001package components.map;
002
003/**
004 * Layered implementations of secondary methods for {@code Map}.
005 *
006 * @param <K>
007 *            type of {@code Map} domain (key) entries
008 * @param <V>
009 *            type of {@code Map} range (associated value) entries
010 */
011public abstract class MapSecondary<K, V> implements Map<K, V> {
012
013    /*
014     * Protected members ------------------------------------------------------
015     */
016
017    /**
018     * Straightforward implementation of {@code Pair} interface.
019     *
020     * @param <K>
021     *            type of {@code Pair} first entry ({@code Map} key entry)
022     * @param <V>
023     *            type of {@code Pair} second entry ({@code Map} value entry)
024     */
025    protected static final class SimplePair<K, V> implements Pair<K, V> {
026
027        /**
028         * The key.
029         */
030        private final K key;
031        /**
032         * The value.
033         */
034        private final V value;
035
036        /**
037         * Constructor.
038         *
039         * @param key
040         *            the key
041         * @param value
042         *            the value
043         */
044        public SimplePair(K key, V value) {
045            this.key = key;
046            this.value = value;
047        }
048
049        @Override
050        public K key() {
051            return this.key;
052        }
053
054        @Override
055        public V value() {
056            return this.value;
057        }
058
059        @Override
060        public boolean equals(Object obj) {
061            if (obj == this) {
062                return true;
063            }
064            if (obj == null) {
065                return false;
066            }
067            if (!(obj instanceof Pair<?, ?>)) {
068                return false;
069            }
070            Pair<?, ?> pair = (Pair<?, ?>) obj;
071            return this.key.equals(pair.key())
072                    && this.value.equals(pair.value());
073        }
074
075        @Override
076        public int hashCode() {
077            return this.key.hashCode() + this.value.hashCode();
078        }
079
080        @Override
081        public String toString() {
082            return "(" + this.key + "," + this.value + ")";
083        }
084
085    }
086
087    /*
088     * Private members --------------------------------------------------------
089     */
090
091    /**
092     * Reports a key associated with {@code value} in {@code m} if such a key
093     * exists, or {@code null} otherwise.
094     *
095     * @param <K>
096     *            type of {@code Map} domain (key) entries
097     * @param <V>
098     *            type of {@code Map} range (associated value) entries
099     * @param m
100     *            the map in which to look for the given value
101     * @param value
102     *            the value whose associated key is to be reported
103     * @return a key associated with value
104     * @aliases reference returned by {@code keyForMap}, if such a key exists
105     * @ensures <pre>
106     * if value is in RANGE(m)
107     *  then (keyForMap, value) is in m
108     *  else [keyForMap is null]
109     * </pre>
110     */
111    private static <K, V> K keyForMap(Map<K, V> m, V value) {
112        assert m != null : "Violation of: m is not null";
113        assert value != null : "Violation of: value is not null";
114        K foundKey = null;
115        /**
116         * @maintains <pre>
117         * value is not in
118         *  {key: K, val: V
119         *   where ((key, val) is in m  and  key is in entries(~m.seen))
120         * (val)}
121         * </pre>
122         */
123        for (Pair<K, V> pair : m) {
124            if (pair.value().equals(value)) {
125                foundKey = pair.key();
126                break;
127            }
128        }
129        return foundKey;
130    }
131
132    /*
133     * Public members ---------------------------------------------------------
134     */
135
136    /*
137     * Common methods (from Object) -------------------------------------------
138     */
139
140    @Override
141    public final boolean equals(Object obj) {
142        if (obj == this) {
143            return true;
144        }
145        if (obj == null) {
146            return false;
147        }
148        if (!(obj instanceof Map<?, ?>)) {
149            return false;
150        }
151        /*
152         * This feels like it can't be the right way to do this, but it compiles
153         * with only an "unchecked cast" warning (and the cast cannot fail
154         * because of type erasure). Using wildcard parameters prevents the loop
155         * from compiling. So, it's still a question how it should be done!
156         * Also, there is the technical question of whether it is possible to
157         * tell whether two empty Maps (with different K and V) are equal; seems
158         * not.
159         */
160        @SuppressWarnings("unchecked")
161        Map<K, V> m = (Map<K, V>) obj;
162        if (this.size() != m.size()) {
163            return false;
164        }
165        /*
166         * |this| = |m|, so every (key, value) pair in this is also in m iff
167         * this = m.
168         */
169        for (Pair<K, V> pair : this) {
170            if (!m.hasKey(pair.key())) {
171                return false;
172            } else if (!pair.value().equals(m.value(pair.key()))) {
173                return false;
174            }
175        }
176        return true;
177    }
178
179    // CHECKSTYLE: ALLOW THIS METHOD TO BE OVERRIDDEN
180    @Override
181    public int hashCode() {
182        final int a = 37;
183        final int b = 17;
184        int result = 0;
185        /*
186         * This code does not run in O(1) time. Perhaps a better hash function
187         * would be to return the size; there just doesn't seem to be anything
188         * in between!
189         */
190        for (Pair<K, V> pair : this) {
191            result += a * pair.key().hashCode() + b * pair.value().hashCode();
192        }
193        return result;
194    }
195
196    // CHECKSTYLE: ALLOW THIS METHOD TO BE OVERRIDDEN
197    @Override
198    public String toString() {
199        StringBuilder result = new StringBuilder("{");
200        boolean first = true;
201        for (Pair<K, V> pair : this) {
202            if (first) {
203                first = false;
204            } else {
205                result.append(",");
206            }
207            result.append(pair.toString());
208        }
209        result.append("}");
210        return result.toString();
211    }
212
213    /*
214     * Other non-kernel methods -----------------------------------------------
215     */
216
217    // CHECKSTYLE: ALLOW THIS METHOD TO BE OVERRIDDEN
218    @Override
219    public V replaceValue(K key, V value) {
220        assert key != null : "Violation of: key is not null";
221        assert value != null : "Violation of: value is not null";
222        assert this.hasKey(key) : "Violation of: key is in DOMAIN(this)";
223        MapSecondary.Pair<K, V> p = this.remove(key);
224        this.add(p.key(), value);
225        return p.value();
226    }
227
228    // CHECKSTYLE: ALLOW THIS METHOD TO BE OVERRIDDEN
229    @Override
230    public K key(V value) {
231        assert value != null : "Violation of: value is not null";
232        K foundKey = keyForMap(this, value);
233        assert foundKey != null : "Violation of: value is in RANGE(this)";
234        return foundKey;
235    }
236
237    // CHECKSTYLE: ALLOW THIS METHOD TO BE OVERRIDDEN
238    @Override
239    public boolean hasValue(V value) {
240        assert value != null : "Violation of: value is not null";
241        K foundKey = keyForMap(this, value);
242        return foundKey != null;
243    }
244
245    // CHECKSTYLE: ALLOW THIS METHOD TO BE OVERRIDDEN
246    @Override
247    public boolean sharesKeyWith(Map<K, V> m) {
248        assert m != null : "Violation of: m is not null";
249        assert m != this : "Violation of: m is not this";
250        boolean found = false;
251        /**
252         * @maintains <pre>
253         * if key is in entries(~this.seen)
254         * then key is not in DOMAIN(m)
255         * </pre>
256         */
257        for (Pair<K, V> pair : this) {
258            if (m.hasKey(pair.key())) {
259                found = true;
260                break;
261            }
262        }
263        return found;
264    }
265
266    // CHECKSTYLE: ALLOW THIS METHOD TO BE OVERRIDDEN
267    @Override
268    public void combineWith(Map<K, V> m) {
269        assert m != null : "Violation of: m is not null";
270        assert m != this : "Violation of: m is not this";
271        assert !this.sharesKeyWith(m) : "Violation of: "
272                + "DOMAIN(this) intersection DOMAIN(m) = {}";
273        /**
274         * @updates this
275         * @maintains <pre>
276         * this = #this union
277         *  {key: K, value: V
278         *    where ((key, value) is in m  and
279         *          key is in entries(~m.seen))
280         *   ((key, value))}
281         * </pre>
282         * @decreases |~m.unseen|
283         */
284        for (Pair<K, V> pair : m) {
285            this.add(pair.key(), pair.value());
286        }
287        m.clear();
288    }
289
290}