Skip to content

Instantly share code, notes, and snippets.

@loganj
Created November 29, 2008 02:00
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save loganj/30152 to your computer and use it in GitHub Desktop.
Save loganj/30152 to your computer and use it in GitHub Desktop.
Bijective function interface and transform collections based thereupon.
/**
* Copyright (C) 2008 Logan Johnson
*
* Licensed 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 loganj.structures;
import com.google.common.base.Function;
public interface Bijective<F, T> extends Function<F,T> {
Bijective<T,F> inverse();
}
/**
* Copyright (C) 2008 Logan Johnson
*
* Licensed 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 loganj.structures;
import com.google.common.base.Function;
import java.util.Iterator;
import java.util.Collection;
class BijectiveCollection<F,T> implements Collection<T> {
final private Collection<F> backingCollection;
final private Bijective<F,T> bijective;
BijectiveCollection(Collection<F> backingCollection, Bijective<F,T> bijective) {
this.backingCollection = backingCollection;
this.bijective = bijective;
}
@Override
public int size() {
return backingCollection.size();
}
@Override
public boolean isEmpty() {
return backingCollection.isEmpty();
}
@Override
public boolean contains(Object o) {
if ( o == null ) {
return false;
}
T to = null;
try {
to = (T)o;
} catch ( ClassCastException e ) {
return false;
}
return backingCollection.contains(bijective.inverse().apply(to));
}
private static class OntoIterator<F,T> implements Iterator<T> {
final private Iterator<F> it;
final private Function<F,T> from;
OntoIterator(Iterator<F> it, Function<F,T> from) {
this.it = it;
this.from = from;
}
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
public T next() {
return from.apply(it.next());
}
@Override
public void remove() {
it.remove();
}
}
@Override
public Iterator<T> iterator() {
return new OntoIterator<F,T>(backingCollection.iterator(), bijective);
}
@Override
public Object[] toArray() {
throw new UnsupportedOperationException();
}
@Override
public <T> T[] toArray(T[] ts) {
throw new UnsupportedOperationException();
}
@Override
public boolean add(T t) {
return backingCollection.add(bijective.inverse().apply(t));
}
@Override
public boolean remove(Object o) {
if ( o == null) {
return false;
}
T cast;
try {
cast = (T)o;
} catch ( ClassCastException e ) {
return false;
}
return backingCollection.remove(bijective.inverse().apply(cast));
}
@Override
public boolean containsAll(Collection<?> objects) {
for ( Object o : objects ) {
if ( !contains(o) ) {
return false;
}
}
return true;
}
@Override
public boolean addAll(Collection<? extends T> ts) {
boolean changed = false;
for ( T t : ts) {
changed |= add(t);
}
return changed;
}
@Override
public boolean retainAll(Collection<?> objects) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(Collection<?> objects) {
boolean changed = false;
for ( Object o : objects ) {
changed |= remove(o);
}
return changed;
}
@Override
public void clear() {
backingCollection.clear();
}
}
/**
* Copyright (C) 2008 Logan Johnson
*
* Licensed 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 loganj.structures;
import com.google.common.base.Function;
import com.google.common.base.Nullable;
import java.util.Map;
import java.util.Set;
import java.util.Collection;
final public class BijectiveMap<FK,K,FV,V> implements Map<K,V> {
final private class InverseEntry implements Map.Entry<FK,FV> {
final private Map.Entry<K,V> entry;
InverseEntry(Entry<K, V> entry) {
this.entry = entry;
}
@Override
public FK getKey() {
return keyBijective.inverse().apply(entry.getKey());
}
@Override
public FV getValue() {
return valueBijective.inverse().apply(entry.getValue());
}
@Override
public FV setValue(FV fv) {
return valueBijective.inverse().apply(entry.setValue(valueBijective.apply(fv)));
}
}
final private class ForwardEntry implements Map.Entry<K,V> {
final private Map.Entry<FK,FV> entry;
ForwardEntry(Entry<FK, FV> entry) {
this.entry = entry;
}
@Override
public K getKey() {
return keyBijective.apply(entry.getKey());
}
@Override
public V getValue() {
return valueBijective.apply(entry.getValue());
}
@Override
public V setValue(V v) {
return valueBijective.apply(entry.setValue(valueBijective.inverse().apply(v)));
}
@Override
public String toString() {
StringBuilder b = new StringBuilder();
b.append(keyBijective.apply(entry.getKey()));
b.append("=");
b.append(valueBijective.apply(entry.getValue()));
return b.toString();
}
}
final private Map<FK,FV> backingMap;
final private Bijective<FK,K> keyBijective;
final private Bijective<FV,V> valueBijective;
final private Set<K> keySet;
final private Set<Entry<K,V>> entrySet;
final private Collection<V> values;
public BijectiveMap(Map<FK, FV> backingMap, Bijective<FK,K> keyBijective, Bijective<FV,V> valueBijective) {
this.backingMap = backingMap;
this.keyBijective = keyBijective;
this.valueBijective = valueBijective;
keySet = new BijectiveSet<FK,K>(backingMap.keySet(), keyBijective );
values = new BijectiveCollection<FV,V>(backingMap.values(), valueBijective);
entrySet = new BijectiveSet<Entry<FK,FV>,Entry<K,V>>(backingMap.entrySet(),
Bijectives.newBijective(
new Function<Entry<FK,FV>,Entry<K,V>>() {
@Override
public Entry<K, V> apply(@Nullable Entry<FK, FV> from) {
return new ForwardEntry(from);
}
},
new Function<Entry<K,V>,Entry<FK,FV>>() {
@Override
public Entry<FK, FV> apply(@Nullable Entry<K, V> from) {
return new InverseEntry(from);
}
})
);
}
@Override
public int size() {
return backingMap.size();
}
@Override
public boolean isEmpty() {
return backingMap.isEmpty();
}
@Override
public boolean containsKey(Object o) {
return keySet.contains(o);
}
@Override
public boolean containsValue(Object o) {
return values.contains(o);
}
@Override
public V get(Object o) {
if ( !containsKey(o) ) {
return null;
}
K cast;
try {
cast = (K)o;
} catch ( ClassCastException e ) {
return null;
}
return valueBijective.apply(backingMap.get(keyBijective.inverse().apply(cast)));
}
@Override
public V put(K k, V v) {
return valueBijective.apply(backingMap.put(keyBijective.inverse().apply(k), valueBijective.inverse().apply(v)));
}
@Override
public V remove(Object o) {
if ( o == null ) {
return null;
}
K cast;
try {
cast = (K)o;
} catch ( ClassCastException e ) {
return null;
}
return valueBijective.apply(backingMap.remove(keyBijective.inverse().apply(cast)));
}
@Override
public void putAll(Map<? extends K, ? extends V> map) {
for ( Map.Entry<? extends K, ? extends V> entry : map.entrySet() ) {
backingMap.put( keyBijective.inverse().apply(entry.getKey()),
valueBijective.inverse().apply(entry.getValue()));
}
}
@Override
public void clear() {
backingMap.clear();
}
@Override
public Set<K> keySet() {
return keySet;
}
@Override
public Collection<V> values() {
return values;
}
@Override
public Set<Entry<K, V>> entrySet() {
return entrySet;
}
}
/**
* Copyright (C) 2008 Logan Johnson
*
* Licensed 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 loganj.structures;
import com.google.common.base.Function;
import com.google.common.base.Nullable;
import com.google.common.base.Functions;
import com.google.common.base.Join;
import com.google.common.collect.Maps;
import java.util.Map;
import java.util.Calendar;
import java.awt.*;
final public class Bijectives {
private Bijectives() {}
public static <F,T> Bijective<F,T> newBijective(Function<F,T> forward, Function<T,F> inverse) {
return new BijectiveImpl<F,T>(forward,inverse);
}
private static final class BijectiveImpl<F,T> implements Bijective<F,T> {
final private Function<F,T> forward;
final private Function<T,F> inverse;
BijectiveImpl(Function<F, T> forward, Function<T, F> inverse) {
this.forward = forward;
this.inverse = inverse;
}
@Override
public Bijective<T, F> inverse() {
return new Bijective<T,F>() {
@Override
public Bijective<F, T> inverse() {
return BijectiveImpl.this;
}
@Override
public F apply(@Nullable T from) {
return inverse.apply(from);
}
};
}
@Override
public T apply(@Nullable F from) {
return forward.apply(from);
}
}
}
/**
* Copyright (C) 2008 Logan Johnson
*
* Licensed 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 loganj.structures;
import java.util.Set;
final public class BijectiveSet<F,T> extends BijectiveCollection<F,T> implements Set<T> {
public BijectiveSet(Set<F> backingSet, Bijective<F,T> bijective) {
super(backingSet, bijective);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment