/****************************************************************************** * Copyright (c) 2016 Oracle * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Konstantin Komissarchik - initial implementation and ongoing maintenance ******************************************************************************/ package org.eclipse.sapphire.util; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.eclipse.sapphire.Filter; /** * @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a> */ public final class MapFactory<K,V> { private Filter<Map.Entry<K,V>> filter; private K firstKey = null; private V firstValue = null; private Map<K,V> map = null; private boolean exported = false; private MapFactory() {} public static <K,V> Map<K,V> empty() { return Collections.emptyMap(); } public static <K,V> Map<K,V> singleton( final K key, final V value ) { return Collections.singletonMap( key, value ); } public static <K,V> Map<K,V> unmodifiable( final Map<K,V> map ) { return MapFactory.<K,V>start().add( map ).result(); } public static <K,V> MapFactory<K,V> start() { return new MapFactory<K,V>(); } public MapFactory<K,V> filter( final Filter<Map.Entry<K,V>> filter ) { if( this.exported ) { throw new IllegalStateException(); } this.filter = filter; if( this.filter != null ) { if( this.map != null ) { for( Iterator<Map.Entry<K,V>> itr = this.map.entrySet().iterator(); itr.hasNext(); ) { if( ! this.filter.allows( itr.next() ) ) { itr.remove(); } } final int size = this.map.size(); if( size == 1 ) { final Map.Entry<K,V> firstEntry = this.map.entrySet().iterator().next(); this.firstKey = firstEntry.getKey(); this.firstValue = firstEntry.getValue(); this.map = null; } else if( size == 0 ) { this.map = null; } } else if( this.firstKey != null ) { if( ! this.filter.allows( new Entry<K,V>( this.firstKey, this.firstValue ) ) ) { this.firstKey = null; this.firstValue = null; } } } return this; } public MapFactory<K,V> add( final K key, final V value ) { if( this.exported ) { throw new IllegalStateException(); } if( key != null && ( this.filter == null || this.filter.allows( new Entry<K,V>( key, value ) ) ) ) { if( this.map != null ) { this.map.put( key, value ); } else if( this.firstKey != null ) { this.map = new HashMap<K,V>(); this.map.put( this.firstKey, this.firstValue ); this.map.put( key, value ); this.firstKey = null; this.firstValue = null; } else { this.firstKey = key; this.firstValue = value; } } return this; } public MapFactory<K,V> add( final Map<K,V> map ) { if( map != null ) { for( Map.Entry<K,V> entry : map.entrySet() ) { add( entry.getKey(), entry.getValue() ); } } return this; } public V remove( final K key ) { V removed = null; if( this.map != null ) { removed = this.map.remove( key ); if( this.map.size() == 1 ) { final Map.Entry<K,V> entry = this.map.entrySet().iterator().next(); this.firstKey = entry.getKey(); this.firstValue = entry.getValue(); this.map = null; } } else if( this.firstKey != null && this.firstKey.equals( key ) ) { removed = this.firstValue; this.firstKey = null; this.firstValue = null; } return removed; } public V get( final K key ) { V value = null; if( this.map != null ) { value = this.map.get( key ); } else if( this.firstKey != null && this.firstKey.equals( key ) ) { value = this.firstValue; } return value; } public boolean contains( final K key ) { return containsKey( key ); } public boolean containsKey( final K key ) { boolean contains = false; if( this.map != null ) { contains = this.map.containsKey( key ); } else if( this.firstKey != null && this.firstKey.equals( key ) ) { contains = true; } return contains; } public boolean containsValue( final V value ) { boolean contains = false; if( this.map != null ) { contains = this.map.containsValue( value ); } else if( this.firstValue != null && this.firstValue.equals( value ) ) { contains = true; } return contains; } public int size() { final int size; if( this.map != null ) { size = this.map.size(); } else if( this.firstKey != null) { size = 1; } else { size = 0; } return size; } public Map<K,V> result() { if( this.exported ) { throw new IllegalStateException(); } this.exported = true; if( this.map != null ) { return Collections.unmodifiableMap( this.map ); } else if( this.firstKey != null ) { return Collections.singletonMap( this.firstKey, this.firstValue ); } else { return Collections.emptyMap(); } } private static final class Entry<K,V> implements Map.Entry<K,V> { private final K key; private final V value; public Entry( K key, final V value ) { this.key = key; this.value = value; } public K getKey() { return this.key; } public V getValue() { return this.value; } public V setValue( final V value ) { throw new UnsupportedOperationException(); } } }