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