SimpleNameMatcher.java

package tools.jackson.core.sym;

import java.util.*;

import tools.jackson.core.util.Named;

/**
 * Basic {@link PropertyNameMatcher} that uses case-sensitive match and does
 * not require (or expect) that names passed as arguments have been
 * {@link String#intern}ed.
 */
public class SimpleNameMatcher
    extends HashedMatcherBase
    implements java.io.Serializable
{
    private static final long serialVersionUID = 1L;

    private SimpleNameMatcher(Locale locale, String[] names, int[] offsets, int mask) {
        super(locale, names, offsets, mask, null, null);
    }

    protected SimpleNameMatcher(SimpleNameMatcher base, String[] nameLookup) {
        super(base, nameLookup);
    }

    protected SimpleNameMatcher(SimpleNameMatcher primary, SimpleNameMatcher secondary) {
        super(primary, secondary);
    }

    /**
     * Factory method for constructing case-sensitive matcher that only supports
     * matching from `String`.
     *
     * @param locale Locale to use (relevant for case-insensitive matchers)
     * @param propertyNames Names to match
     * @param alreadyInterned Whether underlying Strings have been {@code String.intern()}ed or not
     *
     * @return Matcher constructed
     */
    public static SimpleNameMatcher constructFrom(Locale locale,
            List<Named> propertyNames, boolean alreadyInterned) {
        return construct(locale, stringsFromNames(propertyNames, alreadyInterned));
    }

    /**
     * Factory method for constructing case-sensitive matcher that only supports
     * matching from `String`.
     *
     * @param locale Locale to use (relevant for case-insensitive matchers)
     * @param propertyNames Names to match
     *
     * @return Matcher constructed
     */
    public static SimpleNameMatcher construct(Locale locale, List<String> propertyNames)
    {
        final int nameCount = propertyNames.size();
        final int hashSize = _findSize(nameCount);
        final int allocSize = hashSize + (hashSize>>1);

        String[] names = new String[allocSize];
        int[] offsets = new int[allocSize];
        // 20-Dec-2017, tatu: Let's initialize to value "not found" just in case, since `0` would
        //    be valid value, indicating first entry
        Arrays.fill(offsets, PropertyNameMatcher.MATCH_UNKNOWN_NAME); // since we are never called if there's no name involved

        // Alas: cannot easily extract out without tuples or such since names/offsets need resizing...
        final int mask = hashSize-1;
        int spillPtr = names.length;

        for (int i = 0, fcount = propertyNames.size(); i < fcount; ++i) {
            String name = propertyNames.get(i);
            if (name == null) {
                continue;
            }
            int ix = _hash(name.hashCode(), mask);
            if (names[ix] == null) {
                names[ix] = name;
                offsets[ix] = i;
                continue;
            }
            ix = (mask+1) + (ix >> 1);
            if (names[ix] == null) {
                names[ix] = name;
                offsets[ix] = i;
                continue;
            }
            if (names.length == spillPtr) {
                int newLength = names.length + 4;
                names = Arrays.copyOf(names, newLength);
                offsets = Arrays.copyOf(offsets, newLength);
            }
            names[spillPtr] = name;
            offsets[spillPtr] = i;
            ++spillPtr;
        }
        return new SimpleNameMatcher(locale, names, offsets, mask);
    }

    public static SimpleNameMatcher constructCaseInsensitive(Locale locale,
            List<Named> propertyNames, boolean alreadyInterned) {
        return constructCaseInsensitive(locale, stringsFromNames(propertyNames, alreadyInterned));
    }

    public static SimpleNameMatcher constructCaseInsensitive(Locale locale,
            List<String> names)
    {
        return new SimpleNameMatcher(SimpleNameMatcher.construct(locale, names),
                SimpleNameMatcher.construct(locale, _lc(locale, names)));
    }

    // // // Not implemented by this matcher, but not an error to call (caller won't know)

    @Override
    public int matchByQuad(int q1) { return MATCH_UNKNOWN_NAME; }

    @Override
    public int matchByQuad(int q1, int q2) { return MATCH_UNKNOWN_NAME; }

    @Override
    public int matchByQuad(int q1, int q2, int q3) { return MATCH_UNKNOWN_NAME; }

    @Override
    public int matchByQuad(int[] q, int qlen) { return MATCH_UNKNOWN_NAME; }
}