// Path: a-foundation/src/main/java/com/ajjpj/afoundation/function/AFunction1.java
// public interface AFunction1<P, R, E extends Throwable> extends Serializable {
//     R apply(P param) throws E;
// }


import com.ajjpj.afoundation.collection.AEquality;
import com.ajjpj.afoundation.function.AFunction1;
import java.io.Serializable;
import java.util.*;
package com.ajjpj.afoundation.collection.immutable;




/**
 * This is an {@link com.ajjpj.afoundation.collection.immutable.AHashMap} that is specialized for keys of type long, i.e. primitive numbers rather than objects. It duplicates its API
 *  to support both efficient primitive 'long' values and generified 'Long's,
 *
 * @author arno
 */
public class ALongHashMap<V> extends AbstractAMap<Long,V> {
    private static final int LEVEL_INCREMENT = 10;

    transient private Integer cachedHashcode = null; // intentionally not volatile: This class is immutable, so recalculating per thread works

    private static final ALongHashMap EMPTY = new ALongHashMap ();


    /**
     * Returns an empty ALongHashMap instance. Calling this factory method instead of
     *  the constructor allows internal reuse of empty map instances since they are immutable.
     */
    @SuppressWarnings("unchecked")
    public static <V> ALongHashMap<V> empty() {
        return EMPTY;
    }

    public static <V> ALongHashMap<V> fromJavaUtilMap(Map<? extends Number,V> map) {
        ALongHashMap<V> result = empty ();

        for(Map.Entry<? extends Number,V> entry: map.entrySet()) {
            result = result.updated(entry.getKey().longValue (), entry.getValue());
        }

        return result;
    }

    /**
     * Returns an ALongHashMap initialized from separate 'keys' and 'values' collections. Both collections
     *  are iterated exactly once and are expected to have the same size.
     */
    public static <V> ALongHashMap<V> fromKeysAndValues(Iterable<? extends Number> keys, Iterable<V> values) {
        final Iterator<? extends Number> ki = keys.iterator();
        final Iterator<V> vi = values.iterator();

        ALongHashMap<V> result = ALongHashMap.empty ();

        while(ki.hasNext()) {
            final Number key = ki.next();
            final V value = vi.next();

            result = result.updated(key.longValue (), value);
        }
        return result;
    }

    /**
     * Returns an ALongHashMap instance initialized from a collection of
     *  keys and a function. For each element of the <code>keys</code> collection, the function is called once to
     *  determine the corresponding value, and the pair is then stored in the map.
     */
    @SuppressWarnings("unused")
// Path: a-foundation/src/main/java/com/ajjpj/afoundation/function/AFunction1.java
// public interface AFunction1<P, R, E extends Throwable> extends Serializable {
//     R apply(P param) throws E;
// }


// Path: a-foundation/src/main/java/com/ajjpj/afoundation/collection/immutable/ALongHashMap.java
import com.ajjpj.afoundation.collection.AEquality;
import com.ajjpj.afoundation.function.AFunction1;
import java.io.Serializable;
import java.util.*;

package com.ajjpj.afoundation.collection.immutable;




/**
 * This is an {@link com.ajjpj.afoundation.collection.immutable.AHashMap} that is specialized for keys of type long, i.e. primitive numbers rather than objects. It duplicates its API
 *  to support both efficient primitive 'long' values and generified 'Long's,
 *
 * @author arno
 */
public class ALongHashMap<V> extends AbstractAMap<Long,V> {
    private static final int LEVEL_INCREMENT = 10;

    transient private Integer cachedHashcode = null; // intentionally not volatile: This class is immutable, so recalculating per thread works

    private static final ALongHashMap EMPTY = new ALongHashMap ();


    /**
     * Returns an empty ALongHashMap instance. Calling this factory method instead of
     *  the constructor allows internal reuse of empty map instances since they are immutable.
     */
    @SuppressWarnings("unchecked")
    public static <V> ALongHashMap<V> empty() {
        return EMPTY;
    }

    public static <V> ALongHashMap<V> fromJavaUtilMap(Map<? extends Number,V> map) {
        ALongHashMap<V> result = empty ();

        for(Map.Entry<? extends Number,V> entry: map.entrySet()) {
            result = result.updated(entry.getKey().longValue (), entry.getValue());
        }

        return result;
    }

    /**
     * Returns an ALongHashMap initialized from separate 'keys' and 'values' collections. Both collections
     *  are iterated exactly once and are expected to have the same size.
     */
    public static <V> ALongHashMap<V> fromKeysAndValues(Iterable<? extends Number> keys, Iterable<V> values) {
        final Iterator<? extends Number> ki = keys.iterator();
        final Iterator<V> vi = values.iterator();

        ALongHashMap<V> result = ALongHashMap.empty ();

        while(ki.hasNext()) {
            final Number key = ki.next();
            final V value = vi.next();

            result = result.updated(key.longValue (), value);
        }
        return result;
    }

    /**
     * Returns an ALongHashMap instance initialized from a collection of
     *  keys and a function. For each element of the <code>keys</code> collection, the function is called once to
     *  determine the corresponding value, and the pair is then stored in the map.
     */
    @SuppressWarnings("unused")
    public static <K extends Number, V, E extends Throwable> ALongHashMap<V> fromKeysAndFunction(Iterable<K> keys, AFunction1<? super K, ? extends V, E> f) throws E {