sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1404232 - in /sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection: DerivedMap.java DerivedSet.java
Date Wed, 31 Oct 2012 16:27:09 GMT
Author: desruisseaux
Date: Wed Oct 31 16:27:09 2012
New Revision: 1404232

URL: http://svn.apache.org/viewvc?rev=1404232&view=rev
Log:
Ported DerivedMap, which will be needed for AngleFormat.formatToCharacterIterator implementation.
Will also be needed later for metadata implementation.

Added:
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DerivedMap.java
  (with props)
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DerivedSet.java
  (with props)

Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DerivedMap.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DerivedMap.java?rev=1404232&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DerivedMap.java
(added)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DerivedMap.java
Wed Oct 31 16:27:09 2012
@@ -0,0 +1,333 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.util.collection;
+
+import java.io.Serializable;
+import java.util.AbstractMap;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import org.apache.sis.util.Decorator;
+import org.apache.sis.util.ArgumentChecks;
+
+
+/**
+ * A map whose keys are derived <cite>on-the-fly</cite> from an other map.
+ * Conversions are performed when needed by two methods:
+ *
+ * <ul>
+ *   <li>The iterators over the {@linkplain #keySet() key set} or {@linkplain #entrySet()
entry set}
+ *       obtain the derived values by calls to the {@link #baseToDerived(Object)} method.</li>
+ *   <li>Queries ({@link #get get}, {@link #containsKey containsKey}) and write operations
+ *       ({@link #put put}, {@link #remove remove}) obtain the storage values by calls to
the
+ *       {@link #derivedToBase(Object)} method.</li>
+ * </ul>
+ *
+ * {@section Constraints}
+ * <ul>
+ *   <li>This map does not support {@code null} keys, since {@code null} is used as
a
+ *       sentinel value when no mapping from {@linkplain #base} to {@code this} exists.</li>
+ *   <li>Instances of this class are serializable if their underlying {@linkplain #base}
map
+ *       is serializable.</li>
+ *   <li>This class is not thread-safe.</li>
+ * </ul>
+ *
+ * {@section Performance considerations}
+ * This class does not cache any value, since the {@linkplain #base} map is presumed modifiable.
+ * If the base map is known to be immutable, then sub-classes may consider to cache some
values,
+ * especially the result of the {@link #size()} method.
+ *
+ * @param <BK> The type of keys in the backing map.
+ * @param <K>  The type of keys in this map.
+ * @param <V>  The type of values in both this map and the underlying map.
+ *
+ * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @since   0.3 (derived from geotk-2.0)
+ * @version 0.3
+ * @module
+ */
+@Decorator(Map.class)
+public abstract class DerivedMap<BK,K,V> extends AbstractMap<K,V> implements
Serializable {
+    /**
+     * Serial number for inter-operability with different versions.
+     */
+    private static final long serialVersionUID = -6994867383669885934L;
+
+    /**
+     * The base map whose keys are derived from.
+     *
+     * @see #baseToDerived(Object)
+     * @see #derivedToBase(Object)
+     */
+    protected final Map<BK,V> base;
+
+    /**
+     * Key set. Will be constructed only when first needed.
+     *
+     * @see #keySet()
+     */
+    private transient Set<K> keySet;
+
+    /**
+     * Entry set. Will be constructed only when first needed.
+     *
+     * @see #entrySet()
+     */
+    private transient Set<? extends Map.Entry<K,V>> entrySet;
+
+    /**
+     * The derived key type.
+     */
+    private final Class<K> keyType;
+
+    /**
+     * Creates a new derived map from the specified base map.
+     *
+     * @param base The base map.
+     * @param keyType the type of keys in the derived map.
+     */
+    public DerivedMap(final Map<BK,V> base, final Class<K> keyType) {
+        ArgumentChecks.ensureNonNull("base",    this.base    = base);
+        ArgumentChecks.ensureNonNull("keyType", this.keyType = keyType);
+    }
+
+    /**
+     * Transforms a key from the {@linkplain #base} map to a key in this map.
+     * If there is no key in the derived map for the specified base key,
+     * then this method returns {@code null}.
+     *
+     * @param  key A ley from the {@linkplain #base} map.
+     * @return The key that this view should contains instead of {@code key}, or {@code null}.
+     */
+    protected abstract K baseToDerived(final BK key);
+
+    /**
+     * Transforms a key from this derived map to a key in the {@linkplain #base} map.
+     *
+     * @param  key A key in this map.
+     * @return The key stored in the {@linkplain #base} map.
+     */
+    protected abstract BK derivedToBase(final K key);
+
+    /**
+     * Returns {@code true} if this map contains no key-value mappings.
+     *
+     * @return {@code true} if this map contains no key-value mappings.
+     */
+    @Override
+    public boolean isEmpty() {
+        return base.isEmpty() || entrySet().isEmpty();
+    }
+
+    /**
+     * Returns {@code true} if this map maps one or more keys to this value.
+     * The default implementation delegates directly to the {@linkplain #base} map.
+     *
+     * @return {@code true} if this map maps one or more keys to this value.
+     */
+    @Override
+    public boolean containsValue(final Object value) {
+        return base.containsValue(value);
+    }
+
+    /**
+     * Returns {@code true} if this map contains a mapping for the specified key.
+     * This method first checks if the given element is an instance of {@link #keyType},
+     * then delegates to the {@link #base} map like below:
+     *
+     * {@preformat java
+     *     return base.containsKey(derivedToBase(element));
+     * }
+     *
+     * @param  key key whose presence in this map is to be tested.
+     * @return {@code true} if this map contains a mapping for the specified key.
+     */
+    @Override
+    public boolean containsKey(final Object key) {
+        return keyType.isInstance(key) && base.containsKey(derivedToBase(keyType.cast(key)));
+    }
+
+    /**
+     * Returns the value to which this map maps the specified key.
+     * This method first checks if the given element is an instance of {@link #keyType},
+     * then delegates to the {@link #base} map like below:
+     *
+     * {@preformat java
+     *     return base.get(derivedToBase(element));
+     * }
+     *
+     * @param  key key whose associated value is to be returned.
+     * @return the value to which this map maps the specified key.
+     */
+    @Override
+    public V get(final Object key) {
+        return keyType.isInstance(key) ? base.get(derivedToBase(keyType.cast(key))) : null;
+    }
+
+    /**
+     * Associates the specified value with the specified key in this map.
+     * This method first checks if the given element is non-null,
+     * then delegates to the {@link #base} map like below:
+     *
+     * {@preformat java
+     *     return base.put(derivedToBase(key), value);
+     * }
+     *
+     * @param  key key with which the specified value is to be associated.
+     * @param  value value to be associated with the specified key.
+     * @return previous value associated with specified key, or {@code null}
+     *         if there was no mapping for key.
+     * @throws UnsupportedOperationException if the {@linkplain #base} map doesn't
+     *         supports the {@code put} operation.
+     */
+    @Override
+    public V put(final K key, final V value) throws UnsupportedOperationException {
+        return base.put(derivedToBase(key), value);
+    }
+
+    /**
+     * Removes the mapping for this key from this map if present.
+     * This method first checks if the given element is an instance of {@link #keyType},
+     * then delegates to the {@link #base} map like below:
+     *
+     * {@preformat java
+     *     return base.remove(derivedToBase(element));
+     * }
+     *
+     * @param  key key whose mapping is to be removed from the map.
+     * @return previous value associated with specified key, or {@code null}
+     *         if there was no entry for key.
+     * @throws UnsupportedOperationException if the {@linkplain #base} map doesn't
+     *         supports the {@code remove} operation.
+     */
+    @Override
+    public V remove(final Object key) throws UnsupportedOperationException {
+        return keyType.isInstance(key) ? base.remove(derivedToBase(keyType.cast(key))) :
null;
+    }
+
+    /**
+     * Returns a set view of the keys contained in this map.
+     *
+     * @return a set view of the keys contained in this map.
+     */
+    @Override
+    public Set<K> keySet() {
+        if (keySet == null) {
+            keySet = new KeySet(base.keySet());
+        }
+        return keySet;
+    }
+
+    /**
+     * Returns a collection view of the values contained in this map.
+     *
+     * @return a collection view of the values contained in this map.
+     */
+    @Override
+    public Collection<V> values() {
+        return base.values();
+    }
+
+    /**
+     * Returns a set view of the mappings contained in this map.
+     *
+     * @return a set view of the mappings contained in this map.
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public Set<Map.Entry<K,V>> entrySet() {
+        if (entrySet == null) {
+            entrySet = new EntrySet(base.entrySet());
+        }
+        return (Set<Map.Entry<K,V>>) entrySet; // Safe because read-only.
+    }
+
+    /**
+     * The key set.
+     */
+    @Decorator(Set.class)
+    private final class KeySet extends DerivedSet<BK,K> {
+        private static final long serialVersionUID = -2931806200277420177L;
+
+        public KeySet(final Set<BK> base) {
+            super(base, keyType);
+        }
+
+        @Override
+        protected K baseToDerived(final BK element) {
+            return DerivedMap.this.baseToDerived(element);
+        }
+
+        @Override
+        protected BK derivedToBase(final K element) {
+            return DerivedMap.this.derivedToBase(element);
+        }
+    }
+
+    /**
+     * The entry set.
+     */
+    @Decorator(Set.class)
+    private final class EntrySet extends DerivedSet<Map.Entry<BK,V>, Entry<BK,K,V>>
{
+        private static final long serialVersionUID = -1328083271645313149L;
+
+        @SuppressWarnings({"unchecked","rawtypes"})
+        public EntrySet(final Set<Map.Entry<BK,V>> base) {
+            super(base, (Class) Entry.class);
+        }
+
+        @Override
+        protected Entry<BK,K,V> baseToDerived(final Map.Entry<BK,V> entry) {
+            final K derived = DerivedMap.this.baseToDerived(entry.getKey());
+            return (derived != null) ? new Entry<>(entry, derived) : null;
+        }
+
+        @Override
+        protected Map.Entry<BK,V> derivedToBase(final Entry<BK,K,V> element)
{
+            return element.entry;
+        }
+    }
+
+    /**
+     * The entry element.
+     */
+    @Decorator(Map.Entry.class)
+    private static final class Entry<BK,K,V> implements Map.Entry<K,V> {
+        public final Map.Entry<BK,V> entry;
+        private final K derived;
+
+        public Entry(final Map.Entry<BK,V> entry, final K derived) {
+            this.entry   = entry;
+            this.derived = derived;
+        }
+
+        @Override
+        public K getKey() {
+            return derived;
+        }
+
+        @Override
+        public V getValue() {
+            return entry.getValue();
+        }
+
+        @Override
+        public V setValue(V value) {
+            return entry.setValue(value);
+        }
+    }
+}

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DerivedMap.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DerivedMap.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DerivedSet.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DerivedSet.java?rev=1404232&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DerivedSet.java
(added)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DerivedSet.java
Wed Oct 31 16:27:09 2012
@@ -0,0 +1,275 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.util.collection;
+
+import java.util.Set;
+import java.util.Iterator;
+import java.util.AbstractSet;
+import java.io.Serializable;
+import org.apache.sis.util.Decorator;
+import org.apache.sis.util.ArgumentChecks;
+
+
+/**
+ * A set whose values are derived <cite>on-the-fly</cite> from an other set.
+ * Conversions are performed when needed by two methods:
+ *
+ * <ul>
+ *   <li>The {@linkplain #iterator() iterator} obtain the derived values by calls to
the
+ *       {@link #baseToDerived(Object)} method.</li>
+ *   <li>Queries ({@link #contains contains}) and write operations ({@link #add add},
+ *       {@link #remove remove}) obtain the storage values by calls to the
+ *       {@link #derivedToBase(Object)} method.</li>
+ * </ul>
+ *
+ * {@section Constraints}
+ * <ul>
+ *   <li>This set does not support {@code null} values, since {@code null} is used
as a
+ *       sentinel value when no mapping from {@linkplain #base} to {@code this} exists.</li>
+ *   <li>Instances of this class are serializable if their underlying {@linkplain #base}
set
+ *       is serializable.</li>
+ *   <li>This class performs no synchronization by itself. Nevertheless instances of
this class
+ *       may be thread-safe (depending on the sub-class implementation) if the underlying
+ *       {@linkplain #base} set (including its iterator) is thread-safe.</li>
+ * </ul>
+ *
+ * {@section Performance considerations}
+ * This class does not cache any value, since the {@linkplain #base} set is presumed modifiable.
+ * If the base set is known to be immutable, then sub-classes may consider to cache some
values,
+ * especially the result of the {@link #size()} method.
+ *
+ * @param <B> The type of elements in the backing set.
+ * @param <E> The type of elements in this set.
+ *
+ * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @since   0.3 (derived from geotk-2.0)
+ * @version 0.3
+ * @module
+ */
+@Decorator(Set.class)
+public abstract class DerivedSet<B,E> extends AbstractSet<E> implements CheckedContainer<E>,
Serializable {
+    /**
+     * Serial number for inter-operability with different versions.
+     */
+    private static final long serialVersionUID = -4662336508586424581L;
+
+    /**
+     * The base set whose values are derived from.
+     *
+     * @see #baseToDerived(Object)
+     * @see #derivedToBase(Object)
+     */
+    protected final Set<B> base;
+
+    /**
+     * The derived type.
+     */
+    private final Class<E> derivedType;
+
+    /**
+     * Creates a new derived set from the specified base set.
+     *
+     * @param base The base set.
+     * @param derivedType The type of elements in this derived set.
+     */
+    public DerivedSet(final Set<B> base, final Class<E> derivedType) {
+        ArgumentChecks.ensureNonNull("base",        this.base        = base);
+        ArgumentChecks.ensureNonNull("derivedType", this.derivedType = derivedType);
+    }
+
+    /**
+     * Returns the derived element type.
+     */
+    @Override
+    public Class<E> getElementType() {
+        return derivedType;
+    }
+
+    /**
+     * Transforms a value in the {@linkplain #base} set to a value in this set.
+     * If there is no mapping in the derived set for the specified element,
+     * then this method returns {@code null}.
+     *
+     * @param  element A value in the {@linkplain #base} set.
+     * @return The value that this view should contains instead of {@code element}, or {@code
null}.
+     */
+    protected abstract E baseToDerived(final B element);
+
+    /**
+     * Transforms a value in this set to a value in the {@linkplain #base} set.
+     *
+     * @param  element A value in this set.
+     * @return The value stored in the {@linkplain #base} set.
+     */
+    protected abstract B derivedToBase(final E element);
+
+    /**
+     * Returns an iterator over the elements contained in this set.
+     * The iterator will invokes the {@link #baseToDerived(Object)} method for each element.
+     *
+     * @return an iterator over the elements contained in this set.
+     */
+    @Override
+    public Iterator<E> iterator() {
+        return new Iter(base.iterator());
+    }
+
+    /**
+     * Returns the number of elements in this set. The default implementation counts
+     * the number of elements returned by the {@link #iterator() iterator}.
+     * Subclasses are encouraged to cache this value if they know that the
+     * {@linkplain #base} set is immutable.
+     *
+     * @return the number of elements in this set.
+     */
+    @Override
+    public int size() {
+        int count = 0;
+        for (final Iterator<E> it=iterator(); it.hasNext();) {
+            it.next();
+            count++;
+        }
+        return count;
+    }
+
+    /**
+     * Returns {@code true} if this set contains no elements.
+     *
+     * @return {@code true} if this set contains no elements.
+     */
+    @Override
+    public boolean isEmpty() {
+        return !base.isEmpty() || !iterator().hasNext();
+    }
+
+    /**
+     * Returns {@code true} if this set contains the specified element.
+     * This method first checks if the given element is an instance of {@link #derivedType},
+     * then delegates to the {@link #base} set like below:
+     *
+     * {@preformat java
+     *     return base.contains(derivedToBase(element));
+     * }
+     *
+     * @param  element object to be checked for containment in this set.
+     * @return {@code true} if this set contains the specified element.
+     */
+    @Override
+    public boolean contains(final Object element) {
+        return derivedType.isInstance(element) && base.contains(derivedToBase(derivedType.cast(element)));
+    }
+
+    /**
+     * Ensures that this set contains the specified element.
+     * This method first checks if the given element is non-null,
+     * then delegates to the {@link #base} set like below:
+     *
+     * {@preformat java
+     *     return base.add(derivedToBase(element));
+     * }
+     *
+     * @param  element element whose presence in this set is to be ensured.
+     * @return {@code true} if the set changed as a result of the call.
+     * @throws UnsupportedOperationException if the {@linkplain #base} set doesn't
+     *         supports the {@code add} operation.
+     */
+    @Override
+    public boolean add(final E element) throws UnsupportedOperationException {
+        ArgumentChecks.ensureNonNull("element", element);
+        return base.add(derivedToBase(element));
+    }
+
+    /**
+     * Removes a single instance of the specified element from this set.
+     * This method first checks if the given element is an instance of {@link #derivedType},
+     * then delegates to the {@link #base} set like below:
+     *
+     * {@preformat java
+     *     return base.remove(derivedToBase(element));
+     * }
+     *
+     * @param  element element to be removed from this set, if present.
+     * @return {@code true} if the set contained the specified element.
+     * @throws UnsupportedOperationException if the {@linkplain #base} set doesn't
+     *         supports the {@code remove} operation.
+     */
+    @Override
+    public boolean remove(final Object element) throws UnsupportedOperationException {
+        return derivedType.isInstance(element) && base.remove(derivedToBase(derivedType.cast(element)));
+    }
+
+    /**
+     * Iterates through the elements in the set.
+     */
+    @Decorator(Iterator.class)
+    private final class Iter implements Iterator<E> {
+        /**
+         * The iterator from the {@linkplain DerivedSet#base} set.
+         */
+        private final Iterator<B> iterator;
+
+        /**
+         * The next element to be returned, or {@code null}.
+         */
+        private transient E next;
+
+        /**
+         * The iterator from the {@linkplain DerivedSet#base} set.
+         */
+        public Iter(final Iterator<B> iterator) {
+            this.iterator = iterator;
+        }
+
+        /**
+         * Returns {@code true} if the iteration has more elements.
+         */
+        @Override
+        public boolean hasNext() {
+            while (next == null) {
+                if (!iterator.hasNext()) {
+                    return false;
+                }
+                next = baseToDerived(iterator.next());
+            }
+            return true;
+        }
+
+        /**
+         * Returns the next element in the iteration.
+         */
+        @Override
+        public E next() {
+            E value = next;
+            next = null;
+            while (value == null) {
+                value = baseToDerived(iterator.next());
+            }
+            return value;
+        }
+
+        /**
+         * Removes from the underlying set the last element returned by the iterator.
+         *
+         * @throws UnsupportedOperationException if the {@linkplain #base} set doesn't
+         *         supports the {@code remove} operation.
+         */
+        @Override
+        public void remove() {
+            iterator.remove();
+        }
+    }
+}

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DerivedSet.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DerivedSet.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain



Mime
View raw message