Package com.foundationdb.server.types.texpressions

Source Code of com.foundationdb.server.types.texpressions.TValidatedOverload$InvalidOverloadException

/**
* Copyright (C) 2009-2013 FoundationDB, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package com.foundationdb.server.types.texpressions;

import com.foundationdb.server.types.InputSetFlags;
import com.foundationdb.server.types.TClass;
import com.foundationdb.server.types.TInputSet;
import com.foundationdb.server.types.TOverloadResult;
import com.foundationdb.server.types.TOverload;
import com.foundationdb.server.types.TPreptimeValue;
import com.foundationdb.util.SparseArray;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TValidatedOverload implements TOverload {
    // TResolvable methods (straight delegation)

    @Override
    public String displayName() {
        return overload.displayName();
    }

    @Override
    public String[] registeredNames()
    {
        return overload.registeredNames();
    }

    @Override
    public String id() {
        return overload.id();
    }

    @Override
    public int[] getPriorities() {
        return overload.getPriorities();
    }

    @Override
    public Predicate<List<? extends TPreptimeValue>> isCandidate() {
        Predicate<List<? extends TPreptimeValue>> overloadIsCandidate = overload.isCandidate();
        return (overloadIsCandidate == null)
                ? Predicates.<List<? extends TPreptimeValue>>alwaysTrue()
                : overloadIsCandidate;
    }

    @Override
    public boolean equals(Object obj) {
        return (obj instanceof TOverload) && overload.equals(obj);
    }

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

    // TResolvable methods (cached)

    @Override
    public List<TInputSet> inputSets() {
        return inputSetsCached;
    }

    @Override
    public TOverloadResult resultType() {
        return resultStrategy;
    }

    @Override
    public InputSetFlags exactInputs() {
        return exactInputs;
    }

    // TValidatedResolvable methods

    public TOverload getUnderlying() {
        return overload;
    }

    // TValidatedOverload methods

    public int firstVarargInput() {
        if (varargs == null)
            return -1;
        return inputSetsByPos.size();
    }

    public TInputSet pickingInputSet() {
        return pickingSet;
    }

    public TInputSet varargInputSet() {
        return varargs;
    }

    public boolean isVararg() {
        return varargs != null;
    }

    public boolean coversNInputs(int nInputs) {
        /* no pos           : nInputs = 0
         * POS(N)           : nInputs = N+1
         * REMAINING        : nInputs >= 0
         * POS(N),REMAINING : nInputs >= N+1
         */
        int minSize = inputSetsByPos.size();
        return (varargs == null) ? (nInputs == minSize) : (nInputs >= minSize);
    }

    public int positionalInputs() {
        return inputSetsByPos.size();
    }

    public int inputSetIndexAtPos(int atPosition) {
        if (atPosition < 0)
            throw new IllegalArgumentException("atPosition must be non-negative: " + atPosition);
        if (atPosition >= inputsToInputSetIndex.length) {
            if (!isVararg())
                throw new IllegalArgumentException("out of range for non-vararg: " + atPosition);
            atPosition = inputsToInputSetIndex.length - 1;
        }
        return inputsToInputSetIndex[atPosition];
    }

    public int inputSetIndexCount() {
        return inputsToInputSetIndex.length;
    }

    public TInputSet inputSetAt(int index) {
        if(index >= inputSetsByPos.size()) {
            if(varargs == null) {
                throw new IllegalArgumentException("No such input set: " + index);
            }
            return varargs;
        }
        return inputSetsByPos.get(index);
    }

    public TOverloadResult resultStrategy() {
        return resultStrategy;
    }

    public int firstInput(TInputSet inputSet) {
        int result = inputSet.firstPosition();
        if (result < 0 && inputSet.isPicking())
            result = firstVarargInput();
        assert result >= 0 : result + " in " + inputSet + " within " + this;
        return result;
    }

    public int nextInput(TInputSet inputSet, int i, int max) {
        if (i >= max)
            return -1;
        int result = inputSet.nextPosition(i);
        if (result < 0 && inputSet.coversRemaining())
            result = Math.max(i, inputSetsByPos.size());
        return result;
    }

    public String describeInputs() {
        StringBuilder sb = new StringBuilder();
        buildInputsDescription(sb);
        return sb.toString();
    }

    // Redefine toString

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(overload.displayName()).append('(');
        buildInputsDescription(sb);
        sb.append(") -> ").append(resultStrategy);
        return sb.toString();
    }

    // package-private

    boolean coversExactlyNArgs(int nargs) {
        return (!isVararg()) && inputSetsByPos.size() == nargs;
    }

    TValidatedOverload(TOverload overload) {
        this(overload, overload.inputSets());
    }

    TValidatedOverload(TOverload overload, List<TInputSet> inputSets) {
        TInputSet localVarargInputs = null;
        TInputSet localPickingInputs = null;
        SparseArray<TInputSet> inputSetsArray = new SparseArray<>();
        this.inputSetsCached = new ArrayList<>(inputSets);
        for (TInputSet inputSet : inputSetsCached) {
            if (inputSet.coversRemaining()) {
                if (localVarargInputs != null)
                    throw new InvalidOverloadException("multiple input sets are vararg");
                localVarargInputs = inputSet;
            }
            for (int i = 0, max = inputSet.positionsLength(); i < max; ++i) {
                if (inputSet.covers(i)) {
                    if (inputSetsArray.isDefined(i))
                        throw new InvalidOverloadException("multiple input sets cover input " + i);
                    inputSetsArray.set(i, inputSet);
                }
            }
            if (inputSet.isPicking()) {
                if (localPickingInputs != null)
                    throw new InvalidOverloadException("overloads can't define multiple picking input sets");
                localPickingInputs = inputSet;
            }
        }
        if (!inputSetsArray.isCompactable())
            throw new InvalidOverloadException("not all inputs covered");
        this.overload = overload;
        this.inputSetsByPos = inputSetsArray.toList();
        this.varargs = localVarargInputs;
        this.resultStrategy = overload.resultType();
        this.pickingSet = localPickingInputs;
        this.inputSetDescriptions = createInputSetDescriptions(inputSetsByPos, pickingSet, varargs);
        this.exactInputs = overload.exactInputs();
        this.inputsToInputSetIndex = mapInputsToInputSetIndex(inputSetsByPos, inputSetsCached, varargs);
    }

    private void buildInputsDescription(StringBuilder sb) {
        for (int i = 0, nPos = positionalInputs(), nDesc = inputSetDescriptions.length; i < nDesc; ++i) {
            sb.append(inputSetDescriptions[i]);
            if (i == nPos)
                sb.append("...");
            if (i+1 < nDesc)
                sb.append(", ");
        }
    }

    private static int[] mapInputsToInputSetIndex(List<TInputSet> inputSetsByPos,
                                                  List<TInputSet> inputSetsCached,
                                                  TInputSet varargs)
    {
        int naturalPositions = inputSetsByPos.size();
        int positions = naturalPositions;
        if (varargs != null && varargs.positionsLength() == 0)
            ++positions;
        int[] results = new int[positions];
        Map<TInputSet, Integer> inputSetsToIndex = new HashMap<>(positions);
        int indexCounter = 0;
        for (int i = 0; i < positions; ++i) {
            TInputSet inputSet = (i < naturalPositions) ? inputSetsByPos.get(i) : varargs;
            Integer inputSetIndex = inputSetsToIndex.get(inputSet);
            if (inputSetIndex == null) {
                inputSetIndex = indexCounter++;
                inputSetsToIndex.put(inputSet, inputSetIndex);
            }
            results[i] = inputSetIndex;
        }
        return results;
    }

    private static String[] createInputSetDescriptions(List<TInputSet> inputSetsByPos,
                                                       TInputSet pickingSet, TInputSet varargInputSet)
    {
        int nInputsRaw = inputSetsByPos.size();
        int nInputsExtended = (varargInputSet == null) ? nInputsRaw : (nInputsRaw + 1);
        String[] result = new String[nInputsExtended];
        Map<TInputSet,String> map = new HashMap<>(nInputsRaw);
        int anyCount = 0;
        // if the picking input set is T, it's always T (not T#1 etc)
        if (pickingSet != null && pickingSet.targetType() == null) {
            map.put(pickingSet, "T");
            ++anyCount;
        }
        for (int i = 0; i < nInputsExtended; i++) {
            TInputSet inputSet = (i == nInputsRaw) ? varargInputSet : inputSetsByPos.get(i);
            String description = map.get(inputSet);
            if (description == null) {
                TClass inputTClass = inputSet == null ? null : inputSet.targetType();
                if (inputTClass == null) {
                    description = "T";
                    if (anyCount > 0)
                        description += ('#' + anyCount);
                    ++anyCount;
                } else {
                    description = inputTClass.name().unqualifiedName();
                }
                map.put(inputSet, description);
            }
            result[i] = description;
        }
        return result;
    }
    private final TOverload overload;
    private final List<TInputSet> inputSetsCached;
    private final List<TInputSet> inputSetsByPos;
    private final TOverloadResult resultStrategy;
    private final TInputSet varargs;

    private final TInputSet pickingSet;
    private final InputSetFlags exactInputs;
    private final int[] inputsToInputSetIndex;

    /**
     * A description of each input, indexed by its position. If there is a vararg input, its index is
     * one greater than the 0-indexing of positions.
     */
    private final String[] inputSetDescriptions;

    private static class InvalidOverloadException extends RuntimeException {
        private InvalidOverloadException(String message) {
            super(message);
        }
    }
}
TOP

Related Classes of com.foundationdb.server.types.texpressions.TValidatedOverload$InvalidOverloadException

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.