001/* Copyright (C) 2013 TU Dortmund
002 * This file is part of AutomataLib, http://www.automatalib.net/.
003 * 
004 * AutomataLib is free software; you can redistribute it and/or
005 * modify it under the terms of the GNU Lesser General Public
006 * License version 3.0 as published by the Free Software Foundation.
007 * 
008 * AutomataLib is distributed in the hope that it will be useful,
009 * but WITHOUT ANY WARRANTY; without even the implied warranty of
010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
011 * Lesser General Public License for more details.
012 * 
013 * You should have received a copy of the GNU Lesser General Public
014 * License along with AutomataLib; if not, see
015 * http://www.gnu.de/documents/lgpl.en.html.
016 */
017package net.automatalib.commons.util.mappings;
018
019import java.util.AbstractCollection;
020import java.util.AbstractList;
021import java.util.Collection;
022import java.util.Iterator;
023import java.util.List;
024import java.util.Map;
025
026/**
027 * Collection of various methods dealing with {@link Mapping}s.
028 * 
029 * @author Malte Isberner <malte.isberner@gmail.com>
030 *
031 */
032public abstract class Mappings {
033        
034        private static final Mapping<?,?> NULL_MAPPING = new Mapping<Object,Object>() {
035                @Override
036                public Object get(Object elem) {
037                        return null;
038                }
039        };
040        
041        private static final Mapping<?,?> IDENTITY_MAPPING = new Mapping<Object,Object>() {
042                @Override
043                public Object get(Object elem) {
044                        return elem;
045                }
046        };
047        
048        private static final Mapping<?,String> TOSTRING_MAPPING = new Mapping<Object,String>() {
049                @Override
050                public String get(Object elem) {
051                        return String.valueOf(elem);
052                }
053        };
054        
055        
056        /**
057         * Retrieves the <code>null</code> mapping, which maps each domain value
058         * to <code>null</code>.
059         * @param <D> domain class.
060         * @param <R> range class.
061         * @return the <code>null</code> mapping.
062         */
063        @SuppressWarnings("unchecked")
064        public static <D,R> Mapping<D,R> nullMapping() {
065                return (Mapping<D,R>)NULL_MAPPING;
066        }
067        
068        /**
069         * Retrieves the identity mapping, which maps each domain value
070         * to itself.
071         * @param <T> domain/range class.
072         * @return the identity mapping.
073         */
074        @SuppressWarnings("unchecked")
075        public static <T> Mapping<T,T> identity() {
076                return (Mapping<T,T>)IDENTITY_MAPPING;
077        }
078        
079        /**
080         * Returns a mapping that maps objects to their {@link String} representation,
081         * as obtained by {@link String#valueOf(Object)}.
082         * @return the "<tt>toString()</tt>" mapping
083         */
084        @SuppressWarnings("unchecked")
085        public static <D> Mapping<D,String> toStringMapping() {
086                return (Mapping<D,String>)TOSTRING_MAPPING;
087        }
088        
089        /**
090         * Returns a mapping that maps objects to a supertype representation.
091         * @return the "upcast" mapping
092         */
093        @SuppressWarnings("unchecked")
094        public static <S,T extends S> Mapping<T,S> upcast() {
095                return (Mapping<T,S>)IDENTITY_MAPPING;
096        }
097        
098        /**
099         * Retrieves the composition of two mappings, i.e., that mapping that
100         * results from applying the {@link Mapping#get(Object)} method
101         * consecutively.
102         * @param <D> domain class of the first (and resulting) mapping.
103         * @param <I> intermediate object class, range class of the first and domain
104         * class of the second mapping.
105         * @param <R> range class of the second (and resulting) mapping.
106         * @param first first mapping.
107         * @param second second mapping.
108         * @return the composed mapping.
109         */
110        public static <D,I,R> Mapping<D,R> compose(Mapping<D, ? extends I> first, Mapping<? super I,R> second) {
111                return new MappingComposition<D, I, R>(first, second);
112        }
113        
114
115        /**
116         * Applies a mapping to a collection, resulting in a collection containing
117         * the result of applying the specified mapping to each element in the
118         * collection.
119         * 
120         * Note that more specific properties of the specified collection won't
121         * be preserved: If the given collection is e.g. a set, and the provided
122         * mapping is not bijective, then the resulting collections may contain
123         * some values multiple times.
124         * 
125         * @param <D> domain class.
126         * @param <R> range class.
127         * @param mapping the mapping to apply.
128         * @param coll the collection.
129         * @return the mapped collection.
130         */
131        public static <D,R> Collection<R> apply(final Mapping<? super D,R> mapping, final Collection<? extends D> coll) {
132                return new AbstractCollection<R>() {
133                        @Override
134                        public Iterator<R> iterator() {
135                                return apply(mapping, coll.iterator());
136                        }
137
138                        @Override
139                        public int size() {
140                                return coll.size();
141                        }
142                };
143        }
144        
145        /**
146         * Applies a mapping to a list, resulting in a list containing the result
147         * of applying the specified mapping to each element in the list.
148         * 
149         * @param mapping the mapping to apply.
150         * @param list the list.
151         * @return the mapped list.
152         */
153        public static <D,R> List<R> apply(final Mapping<? super D,R> mapping, final List<? extends D> list) {
154                return new AbstractList<R>() {
155                        /*
156                         * (non-Javadoc)
157                         * @see java.util.AbstractList#get(int)
158                         */
159                        @Override
160                        public R get(int index) {
161                                return mapping.get(list.get(index));
162                        }
163
164                        /*
165                         * (non-Javadoc)
166                         * @see java.util.AbstractCollection#size()
167                         */
168                        @Override
169                        public int size() {
170                                return list.size();
171                        }                       
172                };
173        }
174        
175        /**
176         * Applies a mapping to an iterable. The result is an iterable whose
177         * iterator returns the results of applying the specified mapping
178         * to each of the elements returned by the original iterable.
179         * @param <D> domain class.
180         * @param <R> range clas.
181         * @param mapping the mapping to apply.
182         * @param it the underlying iterable.
183         * @return the mapped iterable.
184         */
185        public static <D,R> Iterable<R> apply(final Mapping<? super D,R> mapping, final Iterable<? extends D> it) {
186                return new Iterable<R>() {
187                        @Override
188                        public Iterator<R> iterator() {
189                                return apply(mapping, it.iterator());
190                        }
191                };
192        }
193        
194        /**
195         * Applies a mapping to an iterator. For the behavior, see
196         * {@link #apply(Mapping, Iterable)}. The resulting iterator supports
197         * each operation which the underlying supports.
198         * 
199         * @param <D> domain class.
200         * @param <R> range class.
201         * @param mapping the mapping to apply.
202         * @param baseIt the underlying iterator.
203         * @return the mapped iterator.
204         */
205        public static <D,R> Iterator<R> apply(Mapping<? super D,R> mapping, Iterator<? extends D> baseIt) {
206                return new MappedIterator<D, R>(mapping, baseIt);
207        }
208        
209        
210        /**
211         * Safely retrieves a value from a mapping. If the mapping is
212         * <code>null</code> or returns a <code>null</code> value, the given
213         * fallback value is returned.  
214         * @param mapping the mapping.
215         * @param key the key.
216         * @param fallback the fallback value to return if either the mapping or the
217         * originally returned value are <code>null</code>.
218         * @return the value returned by the specified mapping, or the fallback value.
219         */
220        public static <D,R> R safeGet(Mapping<? super D,R> mapping, D key, R fallback) {
221                if(mapping == null)
222                        return fallback;
223                R val = mapping.get(key);
224                if(val == null)
225                        return fallback;
226                return val;
227        }
228        
229        public static <D> D idGet(Mapping<D,D> mapping, D key) {
230                return safeGet(mapping, key, key);
231        }
232        
233        public static <D,R> R nullGet(Mapping<? super D,? extends R> mapping, D key) {
234                return safeGet(mapping, key, null);
235        }
236        
237        public static <D,R> Mapping<D,R> fromMap(Map<D,R> map) {
238                return new MapMapping<D,R>(map);
239        }
240
241        
242        
243        /*
244         * Prevent inheritance.
245         */
246        private Mappings() {
247        }
248}