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

io.smallrye.config.KeyMap Maven / Gradle / Ivy

package io.smallrye.config;

import java.io.Serializable;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;

import io.smallrye.common.function.Functions;

/**
 * A multi-level key map.
 */
public final class KeyMap extends HashMap> {
    private static final Object NO_VALUE = new Serializable() {
        private static final long serialVersionUID = -6072559389176920349L;
    };

    private static final long serialVersionUID = 3584966224369608557L;

    private KeyMap any;
    @SuppressWarnings("unchecked")
    private V rootValue = (V) NO_VALUE;

    public KeyMap(final int initialCapacity, final float loadFactor) {
        super(initialCapacity, loadFactor);
    }

    public KeyMap(final int initialCapacity) {
        super(initialCapacity);
    }

    public KeyMap() {
    }

    public KeyMap get(final String key, int offs, int len) {
        return get(key.substring(offs, offs + len));
    }

    public KeyMap getAny() {
        return any;
    }

    public KeyMap getOrCreateAny() {
        KeyMap any = this.any;
        if (any == null) {
            any = this.any = new KeyMap<>();
        }
        return any;
    }

    public KeyMap putAny(KeyMap any) {
        KeyMap oldAny = this.any;
        this.any = any;
        return oldAny;
    }

    public KeyMap putAnyIfAbsent(KeyMap any) {
        KeyMap oldAny = this.any;
        if (oldAny == null) {
            this.any = any;
            return null;
        } else {
            return oldAny;
        }
    }

    public boolean hasRootValue() {
        return rootValue != NO_VALUE;
    }

    public V getRootValue() {
        return getRootValueOrDefault(null);
    }

    public V getRootValueOrDefault(final V defaultVal) {
        V rootValue = this.rootValue;
        return rootValue == NO_VALUE ? defaultVal : rootValue;
    }

    public V getOrComputeRootValue(final Supplier supplier) {
        V rootValue = this.rootValue;
        if (rootValue == NO_VALUE) {
            this.rootValue = rootValue = supplier.get();
        }
        return rootValue;
    }

    @SuppressWarnings("unchecked")
    public V removeRootValue() {
        V rootValue = this.rootValue;
        if (rootValue != NO_VALUE) {
            this.rootValue = (V) NO_VALUE;
        }
        return rootValue;
    }

    public V putRootValue(final V rootValue) {
        V old = this.rootValue;
        this.rootValue = rootValue;
        return old == NO_VALUE ? null : old;
    }

    public KeyMap find(final String path) {
        return find(new NameIterator(path));
    }

    public KeyMap find(final NameIterator ni) {
        if (!ni.hasNext()) {
            return this;
        }
        String seg = ni.getNextSegment();
        ni.next();
        KeyMap next = getOrDefault(seg, any);
        return next == null ? null : next.find(ni);
    }

    public KeyMap find(final Iterator iter) {
        if (!iter.hasNext()) {
            return this;
        }
        String seg = iter.next();
        KeyMap next = seg.equals("*") ? any : getOrDefault(seg, any);
        return next == null ? null : next.find(iter);
    }

    public KeyMap find(final Iterable i) {
        return find(i.iterator());
    }

    public KeyMap findOrAdd(final String path) {
        return findOrAdd(new NameIterator(path));
    }

    public KeyMap findOrAdd(final NameIterator ni) {
        if (!ni.hasNext()) {
            return this;
        }
        String seg = ni.getNextSegment();
        ni.next();
        try {
            KeyMap next = seg.equals("*") ? getOrCreateAny() : computeIfAbsent(seg, k -> new KeyMap<>());
            return next.findOrAdd(ni);
        } finally {
            ni.previous();
        }
    }

    public KeyMap findOrAdd(final Iterator iter) {
        if (!iter.hasNext()) {
            return this;
        }
        String seg = iter.next();
        KeyMap next = seg.equals("*") ? getOrCreateAny() : computeIfAbsent(seg, k -> new KeyMap<>());
        return next.findOrAdd(iter);
    }

    public KeyMap findOrAdd(final Iterable i) {
        return findOrAdd(i.iterator());
    }

    public KeyMap findOrAdd(final String... keys) {
        return findOrAdd(keys, 0, keys.length);
    }

    public KeyMap findOrAdd(final String[] keys, int off, int len) {
        String seg = keys[off];
        KeyMap next = seg.equals("*") ? getOrCreateAny() : computeIfAbsent(seg, k -> new KeyMap<>());
        return off + 1 > len - 1 ? next : next.findOrAdd(keys, off + 1, len);
    }

    public V findRootValue(final String path) {
        return findRootValue(new NameIterator(path));
    }

    public V findRootValue(final NameIterator ni) {
        KeyMap result = find(ni);
        return result == null ? null : result.getRootValue();
    }

    public boolean hasRootValue(final String path) {
        return hasRootValue(new NameIterator(path));
    }

    public boolean hasRootValue(final NameIterator ni) {
        KeyMap result = find(ni);
        return result != null && result.hasRootValue();
    }

    public  KeyMap map(P param, BiFunction conversion) {
        return map(param, conversion, new IdentityHashMap<>());
    }

    public  KeyMap map(Function conversion) {
        return map(conversion, Functions.functionBiFunction());
    }

     KeyMap map(P param, BiFunction conversion, IdentityHashMap, KeyMap> cached) {
        if (cached.containsKey(this)) {
            return cached.get(this);
        }
        KeyMap newMap = new KeyMap<>(size());
        cached.put(this, newMap);
        Set>> entries = entrySet();
        for (Entry> entry : entries) {
            newMap.put(entry.getKey(), entry.getValue().map(param, conversion, cached));
        }
        KeyMap any = getAny();
        if (any != null) {
            newMap.putAny(any.map(param, conversion, cached));
        }
        if (hasRootValue()) {
            newMap.putRootValue(conversion.apply(param, getRootValue()));
        }
        return newMap;
    }

    @SuppressWarnings("ResultOfMethodCallIgnored")
    public StringBuilder toString(StringBuilder b) {
        b.append("KeyMap(");
        V rootValue = this.rootValue;
        if (rootValue == NO_VALUE) {
            b.append("no value");
        } else {
            b.append("value=").append(rootValue);
        }
        b.append(") {");
        final Iterator>> iterator = entrySet().iterator();
        KeyMap any = this.any;
        if (iterator.hasNext()) {
            Entry> entry = iterator.next();
            b.append(entry.getKey()).append("=>");
            entry.getValue().toString(b);
            while (iterator.hasNext()) {
                entry = iterator.next();
                b.append(',').append(entry.getKey()).append("=>");
                entry.getValue().toString(b);
            }
            if (any != null) {
                b.append(',').append("(any)=>");
                any.toString(b);
            }
        } else {
            if (any != null) {
                b.append("(any)=>");
                any.toString(b);
            }
        }
        b.append('}');
        return b;
    }

    public String toString() {
        return toString(new StringBuilder()).toString();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy