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

net.sf.saxon.functions.Minimax Maven / Gradle / Ivy

There is a newer version: 12.5
Show newest version
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2015 Saxonica Limited.
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package net.sf.saxon.functions;

import net.sf.saxon.expr.*;
import net.sf.saxon.expr.parser.ContextItemStaticInfo;
import net.sf.saxon.expr.parser.ExpressionVisitor;
import net.sf.saxon.expr.sort.AtomicComparer;
import net.sf.saxon.expr.sort.DescendingComparer;
import net.sf.saxon.expr.sort.GenericAtomicComparer;
import net.sf.saxon.lib.ConversionRules;
import net.sf.saxon.om.Sequence;
import net.sf.saxon.om.SequenceIterator;
import net.sf.saxon.om.ZeroOrOne;
import net.sf.saxon.trace.ExpressionPresenter;
import net.sf.saxon.trans.Err;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.type.*;
import net.sf.saxon.value.*;

import java.util.Properties;


/**
 * This class implements the min() and max() functions, with the collation argument already known.
 */

public abstract class Minimax extends CollatingFunctionFixed {


    private PlainType argumentType = BuiltInAtomicType.ANY_ATOMIC;
    private boolean ignoreNaN = false;


    /**
     * Method to be implemented in subclasses to indicate whether the function implements
     * fn:min() or fn:max()
     * @return true if this is the fn:max() function
     */

    public abstract boolean isMaxFunction();

    /**
     * Indicate whether NaN values should be ignored. For the external min() and max() function, a
     * NaN value in the input causes the result to be NaN. Internally, however, min() and max() are also
     * used in such a way that NaN values should be ignored. This is the case for internally-generated min() and max()
     * functions used to support general comparisons.
     *
     * @param ignore true if NaN values are to be ignored when computing the min or max.
     */

    public void setIgnoreNaN(boolean ignore) {
        ignoreNaN = ignore;
    }

    /**
     * Test whether NaN values are to be ignored
     *
     * @return true if NaN values are to be ignored. This is the case for internally-generated min() and max()
     *         functions used to support general comparisons
     */

    public boolean isIgnoreNaN() {
        return ignoreNaN;
    }


    public AtomicComparer getComparer() {
        return getPreAllocatedAtomicComparer();
    }

    public PlainType getArgumentType() {
        return argumentType;
    }

    /**
     * Static analysis: preallocate a comparer if possible
     */

    @Override
    public void supplyTypeInformation(ExpressionVisitor visitor, ContextItemStaticInfo contextItemType, Expression[] arguments) throws XPathException {
        ItemType type = arguments[0].getItemType();
        argumentType = type.getAtomizedItemType();
        if (argumentType instanceof AtomicType) {
            if (argumentType == BuiltInAtomicType.UNTYPED_ATOMIC) {
                argumentType = BuiltInAtomicType.DOUBLE;
            }
            preAllocateComparer((AtomicType) argumentType, (AtomicType) argumentType, visitor.getStaticContext(), false);
        }
    }

    /**
     * Determine the cardinality of the function.
     */

    public int getCardinality(Expression[] arguments) {
        if (!Cardinality.allowsZero(arguments[0].getCardinality())) {
            return StaticProperty.EXACTLY_ONE;
        } else {
            return StaticProperty.ALLOWS_ZERO_OR_ONE;
        }
    }

    @Override
    public Expression makeOptimizedFunctionCall(ExpressionVisitor visitor, ContextItemStaticInfo contextInfo, Expression... arguments) throws XPathException {
        // test for a singleton: this often happens after (A call(XPathContext context, Sequence[] arguments) throws XPathException {
        return new ZeroOrOne(
            minimax(arguments[0].iterate(), isMaxFunction(), getAtomicComparer(context), ignoreNaN, context));
    }

    @Override
    public void exportAttributes(ExpressionPresenter out) {
        super.exportAttributes(out);
        if (ignoreNaN) {
            out.emitAttribute("flags", "i");
        }
    }

    @Override
    public void importAttributes(Properties attributes) throws XPathException {
        super.importAttributes(attributes);
        String flags = attributes.getProperty("flags");
        if (flags != null && flags.contains("i")) {
            setIgnoreNaN(true);
        }
    }


    /**
     * Concrete subclass to define the fn:min() function
     */

    public static class Min extends Minimax {
        public boolean isMaxFunction() {
            return false;
        }
    }

    /**
     * Concrete subclass to define the fn:max() function
     */

    public static class Max extends Minimax {
        public boolean isMaxFunction() {
            return true;
        }
    }

}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy