All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.yahoo.collections.LazyMap Maven / Gradle / Ivy

// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.collections;

import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;

/**
 * @author Simon Thoresen Hult
 */
public abstract class LazyMap implements Map {

    private Map delegate = newEmpty();

    @Override
    public final int size() {
        return delegate.size();
    }

    @Override
    public final boolean isEmpty() {
        return delegate.isEmpty();
    }

    @Override
    public final boolean containsKey(Object key) {
        return delegate.containsKey(key);
    }

    @Override
    public final boolean containsValue(Object value) {
        return delegate.containsValue(value);
    }

    @Override
    public final V get(Object key) {
        return delegate.get(key);
    }

    @Override
    public final V put(K key, V value) {
        return delegate.put(key, value);
    }

    @Override
    public final V remove(Object key) {
        return delegate.remove(key);
    }

    @Override
    public final void putAll(Map m) {
        delegate.putAll(m);
    }

    @Override
    public final void clear() {
        delegate.clear();
    }

    @Override
    public final Set keySet() {
        return delegate.keySet();
    }

    @Override
    public final Collection values() {
        return delegate.values();
    }

    @Override
    public final Set> entrySet() {
        return delegate.entrySet();
    }

    @Override
    public final int hashCode() {
        return delegate.hashCode();
    }

    @Override
    public final boolean equals(Object obj) {
        return obj == this || (obj instanceof Map && delegate.equals(obj));
    }

    private Map newEmpty() {
        return new EmptyMap();
    }

    private Map newSingleton(K key, V value) {
        return new SingletonMap(key, value);
    }

    protected abstract Map newDelegate();

    final Map getDelegate() {
        return delegate;
    }

    class EmptyMap extends AbstractMap {

        @Override
        public V put(K key, V value) {
            delegate = newSingleton(key, value);
            return null;
        }

        @Override
        public void putAll(Map m) {
            switch (m.size()) {
            case 0:
                break;
            case 1:
                Entry entry = m.entrySet().iterator().next();
                put(entry.getKey(), entry.getValue());
                break;
            default:
                delegate = newDelegate();
                delegate.putAll(m);
                break;
            }
        }

        @Override
        public Set> entrySet() {
            return Collections.emptySet();
        }
    }

    class SingletonMap extends AbstractMap {

        final K key;
        V value;

        SingletonMap(K key, V value) {
            this.key = key;
            this.value = value;
        }

        @Override
        public V put(K key, V value) {
            if (containsKey(key)) {
                V oldValue = this.value;
                this.value = value;
                return oldValue;
            } else {
                delegate = newDelegate();
                delegate.put(this.key, this.value);
                return delegate.put(key, value);
            }
        }

        @Override
        public void putAll(Map m) {
            switch (m.size()) {
            case 0:
                break;
            case 1:
                Entry entry = m.entrySet().iterator().next();
                put(entry.getKey(), entry.getValue());
                break;
            default:
                delegate = newDelegate();
                delegate.put(this.key, this.value);
                delegate.putAll(m);
                break;
            }
        }

        @Override
        public Set> entrySet() {
            return new AbstractSet>() {

                @Override
                public Iterator> iterator() {
                    return new Iterator>() {

                        boolean hasNext = true;

                        @Override
                        public boolean hasNext() {
                            return hasNext;
                        }

                        @Override
                        public Entry next() {
                            if (hasNext) {
                                hasNext = false;
                                return new Entry() {

                                    @Override
                                    public K getKey() {
                                        return key;
                                    }

                                    @Override
                                    public V getValue() {
                                        return value;
                                    }

                                    @Override
                                    public V setValue(V value) {
                                        V oldValue = SingletonMap.this.value;
                                        SingletonMap.this.value = value;
                                        return oldValue;
                                    }

                                    @Override
                                    public int hashCode() {
                                        return Objects.hashCode(key) + Objects.hashCode(value) * 31;
                                    }

                                    @Override
                                    public boolean equals(Object obj) {
                                        if (obj == this) {
                                            return true;
                                        }
                                        if (!(obj instanceof Entry)) {
                                            return false;
                                        }
                                        @SuppressWarnings("unchecked")
                                        Entry rhs = (Entry)obj;
                                        if (!Objects.equals(key, rhs.getKey())) {
                                            return false;
                                        }
                                        if (!Objects.equals(value, rhs.getValue())) {
                                            return false;
                                        }
                                        return true;
                                    }
                                };
                            } else {
                                throw new NoSuchElementException();
                            }
                        }

                        @Override
                        public void remove() {
                            if (hasNext) {
                                throw new IllegalStateException();
                            } else {
                                delegate = newEmpty();
                            }
                        }
                    };
                }

                @Override
                public int size() {
                    return 1;
                }
            };
        }
    }

    public static  LazyMap newHashMap() {
        return new LazyMap() {

            @Override
            protected Map newDelegate() {
                return new HashMap<>();
            }
        };
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy