OperationFunctions.java
/*
* SPDX-FileCopyrightText: none
* SPDX-License-Identifier: CC0-1.0
*/
package gov.nist.secauto.metaschema.core.metapath.function; // NOPMD - intentional
import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IBase64BinaryItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IBooleanItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDateItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDateTimeItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDayTimeDurationItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDecimalItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDurationItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IIntegerItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.INumericItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IYearMonthDurationItem;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.Duration;
import java.time.Period;
import java.time.ZonedDateTime;
import java.time.temporal.TemporalAmount;
import java.util.Set;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
public final class OperationFunctions { // NOPMD - intentional
@NonNull
public static final Set<Class<? extends IAnyAtomicItem>> AGGREGATE_MATH_TYPES = ObjectUtils.notNull(Set.of(
IDayTimeDurationItem.class,
IYearMonthDurationItem.class,
INumericItem.class));
private OperationFunctions() {
// disable
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-add-yearMonthDuration-to-date">op:add-yearMonthDuration-to-date</a>.
*
* @param instant
* a point in time
* @param duration
* the duration to add
* @return the result of adding the duration to the date
*/
@NonNull
public static IDateItem opAddYearMonthDurationToDate(@NonNull IDateItem instant,
@NonNull IYearMonthDurationItem duration) {
return addDurationToDate(instant.asZonedDateTime(), duration.asPeriod());
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-add-dayTimeDuration-to-date">op:add-dayTimeDuration-to-date</a>.
*
* @param instant
* a point in time
* @param duration
* the duration to add
* @return the result of adding the duration to the date
*/
@NonNull
public static IDateItem opAddDayTimeDurationToDate(@NonNull IDateItem instant,
@NonNull IDayTimeDurationItem duration) {
return addDurationToDate(instant.asZonedDateTime(), duration.asDuration());
}
@NonNull
private static IDateItem addDurationToDate(@NonNull ZonedDateTime dateTime, @NonNull TemporalAmount duration) {
ZonedDateTime result;
try {
result = dateTime.plus(duration);
} catch (ArithmeticException ex) {
throw new ArithmeticFunctionException(ArithmeticFunctionException.OVERFLOW_UNDERFLOW_ERROR, ex);
}
assert result != null;
return IDateItem.valueOf(result);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-add-yearMonthDurations">op:add-yearMonthDurations</a>.
*
* @param arg1
* the first duration
* @param arg2
* the second duration
* @return the sum of two duration values
*/
@NonNull
public static IYearMonthDurationItem opAddYearMonthDurations(
@NonNull IYearMonthDurationItem arg1,
@NonNull IYearMonthDurationItem arg2) {
Period duration1 = arg1.asPeriod();
Period duration2 = arg2.asPeriod();
Period result;
try {
result = duration1.plus(duration2);
} catch (ArithmeticException ex) {
throw new ArithmeticFunctionException(ArithmeticFunctionException.OVERFLOW_UNDERFLOW_ERROR, ex);
}
assert result != null;
return IYearMonthDurationItem.valueOf(result);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-add-dayTimeDurations">op:add-dayTimeDurations</a>.
*
* @param arg1
* the first duration
* @param arg2
* the second duration
* @return the sum of two duration values
*/
@NonNull
public static IDayTimeDurationItem opAddDayTimeDurations(
@NonNull IDayTimeDurationItem arg1,
@NonNull IDayTimeDurationItem arg2) {
Duration duration1 = arg1.asDuration();
Duration duration2 = arg2.asDuration();
Duration result;
try {
result = duration1.plus(duration2);
} catch (ArithmeticException ex) {
throw new ArithmeticFunctionException(ArithmeticFunctionException.OVERFLOW_UNDERFLOW_ERROR, ex);
}
assert result != null;
return IDayTimeDurationItem.valueOf(result);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-add-yearMonthDuration-to-dateTime">op:add-yearMonthDuration-to-dateTime</a>.
*
* @param instant
* a point in time
* @param duration
* the duration to add
* @return the result of adding the duration to the date
*/
@NonNull
public static IDateTimeItem opAddYearMonthDurationToDateTime(
@NonNull IDateTimeItem instant,
@NonNull IYearMonthDurationItem duration) {
ZonedDateTime result;
try {
result = instant.asZonedDateTime().plus(duration.asPeriod());
} catch (ArithmeticException ex) {
throw new ArithmeticFunctionException(ArithmeticFunctionException.OVERFLOW_UNDERFLOW_ERROR, ex);
}
assert result != null;
return IDateTimeItem.valueOf(result);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-add-dayTimeDuration-to-dateTime">op:add-dayTimeDuration-to-dateTime</a>.
*
* @param instant
* a point in time
* @param duration
* the duration to add
* @return the result of adding the duration to the date
*/
@NonNull
public static IDateTimeItem opAddDayTimeDurationToDateTime(
@NonNull IDateTimeItem instant,
@NonNull IDayTimeDurationItem duration) {
ZonedDateTime result;
try {
result = instant.asZonedDateTime().plus(duration.asDuration());
} catch (ArithmeticException ex) {
throw new ArithmeticFunctionException(ArithmeticFunctionException.OVERFLOW_UNDERFLOW_ERROR, ex);
}
assert result != null;
return IDateTimeItem.valueOf(result);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-subtract-dates">op:subtract-dates</a>.
*
* @param date1
* the first point in time
* @param date2
* the second point in time
* @return the elapsed time between the starting instant and ending instant
*/
@NonNull
public static IDayTimeDurationItem opSubtractDates(@NonNull IDateItem date1, @NonNull IDateItem date2) {
return between(date1.asZonedDateTime(), date2.asZonedDateTime());
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-subtract-yearMonthDuration-from-date">op:subtract-yearMonthDuration-from-date</a>.
*
* @param date
* a point in time
* @param duration
* the duration to subtract
* @return the result of subtracting the duration from the date
*/
@NonNull
public static IDateItem opSubtractYearMonthDurationFromDate(
@NonNull IDateItem date,
@NonNull IYearMonthDurationItem duration) {
return subtractDurationFromDate(date.asZonedDateTime(), duration.asPeriod());
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-subtract-dayTimeDuration-from-date">op:subtract-dayTimeDuration-from-date</a>.
*
* @param date
* a point in time
* @param duration
* the duration to subtract
* @return the result of subtracting the duration from the date
*/
@NonNull
public static IDateItem opSubtractDayTimeDurationFromDate(
@NonNull IDateItem date,
@NonNull IDayTimeDurationItem duration) {
return subtractDurationFromDate(date.asZonedDateTime(), duration.asDuration());
}
@NonNull
private static IDateItem subtractDurationFromDate(
@NonNull ZonedDateTime dateTime,
@NonNull TemporalAmount duration) {
@SuppressWarnings("null")
@NonNull
ZonedDateTime result = dateTime.minus(duration);
return IDateItem.valueOf(result);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-subtract-yearMonthDurations">op:subtract-yearMonthDurations</a>.
*
* @param arg1
* the first duration
* @param arg2
* the second duration
* @return the result of subtracting the second duration from the first
*/
@NonNull
public static IYearMonthDurationItem opSubtractYearMonthDurations(
@NonNull IYearMonthDurationItem arg1,
@NonNull IYearMonthDurationItem arg2) {
Period duration1 = arg1.asPeriod();
Period duration2 = arg2.asPeriod();
@SuppressWarnings("null")
@NonNull
Period duration = duration1.minus(duration2);
return IYearMonthDurationItem.valueOf(duration);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-subtract-dayTimeDurations">op:subtract-dayTimeDurations</a>.
*
* @param arg1
* the first duration
* @param arg2
* the second duration
* @return the result of subtracting the second duration from the first
*/
@NonNull
public static IDayTimeDurationItem opSubtractDayTimeDurations(
@NonNull IDayTimeDurationItem arg1,
@NonNull IDayTimeDurationItem arg2) {
Duration duration1 = arg1.asDuration();
Duration duration2 = arg2.asDuration();
@SuppressWarnings("null")
@NonNull
Duration duration = duration1.minus(duration2);
return IDayTimeDurationItem.valueOf(duration);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-subtract-dateTimes">op:subtract-dateTimes</a>.
*
* @param time1
* the first point in time
* @param time2
* the second point in time
* @return the duration the occurred between the two points in time
*/
@NonNull
public static IDayTimeDurationItem opSubtractDateTimes(@NonNull IDateTimeItem time1, @NonNull IDateTimeItem time2) {
return between(time1.asZonedDateTime(), time2.asZonedDateTime());
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-subtract-dateTimes">op:subtract-dateTimes</a>.
*
* @param time1
* the first point in time
* @param time2
* the second point in time
* @return the duration the occurred between the two points in time
*/
@NonNull
private static IDayTimeDurationItem between(@NonNull ZonedDateTime time1, @NonNull ZonedDateTime time2) {
@SuppressWarnings("null")
@NonNull
Duration between = Duration.between(time1, time2);
return IDayTimeDurationItem.valueOf(between);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-subtract-yearMonthDuration-from-dateTime">op:subtract-yearMonthDuration-from-dateTime</a>.
*
* @param moment
* a point in time
* @param duration
* the duration to subtract
* @return the result of subtracting the duration from a point in time
*/
@NonNull
public static IDateTimeItem opSubtractYearMonthDurationFromDateTime(
@NonNull IDateTimeItem moment,
@NonNull IYearMonthDurationItem duration) {
@SuppressWarnings("null")
@NonNull
ZonedDateTime dateTime = moment.asZonedDateTime().minus(duration.asPeriod());
return IDateTimeItem.valueOf(dateTime);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-subtract-dayTimeDuration-from-dateTime">op:subtract-dayTimeDuration-from-dateTime</a>.
*
* @param moment
* a point in time
* @param duration
* the duration to subtract
* @return the result of subtracting the duration from a point in time
*/
@NonNull
public static IDateTimeItem opSubtractDayTimeDurationFromDateTime(
@NonNull IDateTimeItem moment,
@NonNull IDayTimeDurationItem duration) {
@SuppressWarnings("null")
@NonNull
ZonedDateTime dateTime = moment.asZonedDateTime().plus(duration.asDuration());
return IDateTimeItem.valueOf(dateTime);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-multiply-yearMonthDuration">op:multiply-yearMonthDuration</a>.
*
* @param arg1
* the duration value
* @param arg2
* the number to multiply by
* @return the result of multiplying a {@link IYearMonthDurationItem} by a
* number
*/
@NonNull
public static IYearMonthDurationItem opMultiplyYearMonthDuration(
@NonNull IYearMonthDurationItem arg1,
@NonNull INumericItem arg2) {
int arg2Int;
try {
arg2Int = FunctionUtils.asInteger(arg2.round());
} catch (ArithmeticException ex) {
throw new ArithmeticFunctionException(ArithmeticFunctionException.OVERFLOW_UNDERFLOW_ERROR, ex);
}
@SuppressWarnings("null")
@NonNull
Period period = arg1.asPeriod().multipliedBy(arg2Int);
return IYearMonthDurationItem.valueOf(period);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-multiply-dayTimeDuration">op:multiply-dayTimeDuration</a>.
*
* @param arg1
* the duration value
* @param arg2
* the number to multiply by
* @return the result of multiplying a {@link IDayTimeDurationItem} by a number
*/
@NonNull
public static IDayTimeDurationItem opMultiplyDayTimeDuration(
@NonNull IDayTimeDurationItem arg1,
@NonNull INumericItem arg2) {
long arg2Long;
try {
arg2Long = FunctionUtils.asLong(arg2.round());
} catch (ArithmeticException ex) {
throw new ArithmeticFunctionException(ArithmeticFunctionException.OVERFLOW_UNDERFLOW_ERROR, ex);
}
@SuppressWarnings("null")
@NonNull
Duration duration = arg1.asDuration().multipliedBy(arg2Long);
return IDayTimeDurationItem.valueOf(duration);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-divide-yearMonthDuration">op:divide-yearMonthDuration</a>.
*
* @param arg1
* the duration value
* @param arg2
* the number to divide by
* @return the result of dividing a {@link IYearMonthDurationItem} by a number
*/
@NonNull
public static IYearMonthDurationItem opDivideYearMonthDuration(
@NonNull IYearMonthDurationItem arg1,
@NonNull INumericItem arg2) {
IIntegerItem totalMonths = IIntegerItem.valueOf(arg1.asPeriod().toTotalMonths());
IIntegerItem result = opNumericIntegerDivide(totalMonths, arg2);
int months;
try {
months = FunctionUtils.asInteger(result.asInteger());
} catch (ArithmeticException ex) {
throw new DateTimeFunctionException(DateTimeFunctionException.DURATION_OVERFLOW_UNDERFLOW_ERROR,
"Overflow/underflow in duration operation.", ex);
}
int years = months / 12;
months = months % 12;
return IYearMonthDurationItem.valueOf(years, months);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-divide-dayTimeDuration">op:divide-dayTimeDuration</a>.
*
* @param arg1
* the duration value
* @param arg2
* the number to divide by
* @return the result of dividing a {@link IDayTimeDurationItem} by a number
*/
@NonNull
public static IDayTimeDurationItem opDivideDayTimeDuration(
@NonNull IDayTimeDurationItem arg1,
@NonNull INumericItem arg2) {
try {
@SuppressWarnings("null")
@NonNull
Duration duration = arg1.asDuration().dividedBy(FunctionUtils.asLong(arg2.round()));
return IDayTimeDurationItem.valueOf(duration);
} catch (ArithmeticException ex) {
throw new ArithmeticFunctionException(ArithmeticFunctionException.DIVISION_BY_ZERO, "Division by zero", ex);
}
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-divide-dayTimeDuration-by-dayTimeDuration">op:divide-dayTimeDuration-by-dayTimeDuration</a>.
*
* @param arg1
* the first duration value
* @param arg2
* the second duration value
* @return the ratio of two {@link IDayTimeDurationItem} values, as a decimal
* number
*/
@NonNull
public static IDecimalItem opDivideDayTimeDurationByDayTimeDuration(
@NonNull IDayTimeDurationItem arg1,
@NonNull IDayTimeDurationItem arg2) {
return IDecimalItem.cast(
opNumericDivide(
IDecimalItem.valueOf(arg1.asSeconds()),
IDecimalItem.valueOf(arg2.asSeconds())));
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-date-equal">op:date-equal</a>.
*
* @param arg1
* the first value
* @param arg2
* the second value
* @return {@code true} if the first argument is the same instant in time as the
* second, or {@code false} otherwise
*/
@NonNull
public static IBooleanItem opDateEqual(@NonNull IDateItem arg1, @NonNull IDateItem arg2) {
return IBooleanItem.valueOf(arg1.asZonedDateTime().equals(arg2.asZonedDateTime()));
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-dateTime-equal">op:dateTime-equal</a>.
*
* @param arg1
* the first value
* @param arg2
* the second value
* @return {@code true} if the first argument is the same instant in time as the
* second, or {@code false} otherwise
*/
@NonNull
public static IBooleanItem opDateTimeEqual(@NonNull IDateTimeItem arg1, @NonNull IDateTimeItem arg2) {
return IBooleanItem.valueOf(arg1.asZonedDateTime().equals(arg2.asZonedDateTime()));
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-duration-equal">op:duration-equal</a>.
*
* @param arg1
* the first value
* @param arg2
* the second value
* @return {@code true} if the first argument is the same duration as the
* second, or {@code false} otherwise
*/
@NonNull
public static IBooleanItem opDurationEqual(@NonNull IDurationItem arg1, @NonNull IDurationItem arg2) {
return IBooleanItem.valueOf(arg1.compareTo(arg2) == 0);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-base64Binary-equal">op:base64Binary-equal</a>.
*
* @param arg1
* the first value
* @param arg2
* the second value
* @return {@code true} if the first argument is equal to the second, or
* {@code false} otherwise
*/
@NonNull
public static IBooleanItem opBase64BinaryEqual(@NonNull IBase64BinaryItem arg1, @NonNull IBase64BinaryItem arg2) {
return IBooleanItem.valueOf(arg1.asByteBuffer().equals(arg2.asByteBuffer()));
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-date-greater-than">op:date-greater-than</a>.
*
* @param arg1
* the first value
* @param arg2
* the second value
* @return {@code true} if the first argument is a later instant in time than
* the second, or {@code false} otherwise
*/
@NonNull
public static IBooleanItem opDateGreaterThan(@NonNull IDateItem arg1, @NonNull IDateItem arg2) {
return IBooleanItem.valueOf(arg1.asZonedDateTime().compareTo(arg2.asZonedDateTime()) > 0);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-dateTime-greater-than">op:dateTime-greater-than</a>.
*
* @param arg1
* the first value
* @param arg2
* the second value
* @return {@code true} if the first argument is a later instant in time than
* the second, or {@code false} otherwise
*/
@NonNull
public static IBooleanItem opDateTimeGreaterThan(@NonNull IDateTimeItem arg1, @NonNull IDateTimeItem arg2) {
return IBooleanItem.valueOf(arg1.asZonedDateTime().compareTo(arg2.asZonedDateTime()) > 0);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-yearMonthDuration-greater-than">op:yearMonthDuration-greater-than</a>.
*
* @param arg1
* the first value
* @param arg2
* the second value
* @return {@code true} if the first argument is a longer duration than the
* second, or {@code false} otherwise
*/
@NonNull
public static IBooleanItem opYearMonthDurationGreaterThan(
@NonNull IYearMonthDurationItem arg1,
@NonNull IYearMonthDurationItem arg2) {
Period p1 = arg1.asPeriod();
Period p2 = arg2.asPeriod();
// this is only an approximation
return IBooleanItem.valueOf(p1.toTotalMonths() > p2.toTotalMonths());
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-dayTimeDuration-greater-than">op:dayTimeDuration-greater-than</a>.
*
* @param arg1
* the first value
* @param arg2
* the second value
* @return {@code true} if the first argument is a longer duration than the
* second, or {@code false} otherwise
*/
@NonNull
public static IBooleanItem opDayTimeDurationGreaterThan(
@NonNull IDayTimeDurationItem arg1,
@NonNull IDayTimeDurationItem arg2) {
return IBooleanItem.valueOf(arg1.compareTo(arg2) > 0);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-base64Binary-greater-than">op:base64Binary-greater-than</a>.
*
* @param arg1
* the first value
* @param arg2
* the second value
* @return {@code true} if the first argument is greater than the second, or
* {@code false} otherwise
*/
@NonNull
public static IBooleanItem opBase64BinaryGreaterThan(
@NonNull IBase64BinaryItem arg1,
@NonNull IBase64BinaryItem arg2) {
return IBooleanItem.valueOf(arg1.compareTo(arg2) > 0);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-date-less-than">op:date-less-than</a>.
*
* @param arg1
* the first value
* @param arg2
* the second value
* @return {@code true} if the first argument is an earlier instant in time than
* the second, or {@code false} otherwise
*/
@NonNull
public static IBooleanItem opDateLessThan(
@NonNull IDateItem arg1,
@NonNull IDateItem arg2) {
return IBooleanItem.valueOf(arg1.asZonedDateTime().compareTo(arg2.asZonedDateTime()) < 0);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-dateTime-less-than">op:dateTime-less-than</a>.
*
* @param arg1
* the first value
* @param arg2
* the second value
* @return {@code true} if the first argument is an earlier instant in time than
* the second, or {@code false} otherwise
*/
@NonNull
public static IBooleanItem opDateTimeLessThan(
@NonNull IDateTimeItem arg1,
@NonNull IDateTimeItem arg2) {
return IBooleanItem.valueOf(arg1.asZonedDateTime().compareTo(arg2.asZonedDateTime()) < 0);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-yearMonthDuration-less-than">op:yearMonthDuration-less-than</a>.
*
* @param arg1
* the first value
* @param arg2
* the second value
* @return {@code true} if the first argument is a shorter duration than the
* second, or {@code false} otherwise
*/
@NonNull
public static IBooleanItem opYearMonthDurationLessThan(@NonNull IYearMonthDurationItem arg1,
@NonNull IYearMonthDurationItem arg2) {
Period p1 = arg1.asPeriod();
Period p2 = arg2.asPeriod();
// this is only an approximation
return IBooleanItem.valueOf(p1.toTotalMonths() < p2.toTotalMonths());
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-dayTimeDuration-less-than">op:dayTimeDuration-less-than</a>.
*
* @param arg1
* the first value
* @param arg2
* the second value
* @return {@code true} if the first argument is a shorter duration than the
* second, or {@code false} otherwise
*/
@NonNull
public static IBooleanItem opDayTimeDurationLessThan(
@NonNull IDayTimeDurationItem arg1,
@NonNull IDayTimeDurationItem arg2) {
return IBooleanItem.valueOf(arg1.compareTo(arg2) < 0);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-base64Binary-less-than">op:base64Binary-less-than</a>.
*
* @param arg1
* the first value
* @param arg2
* the second value
* @return {@code true} if the first argument is less than the second, or
* {@code false} otherwise
*/
@NonNull
public static IBooleanItem opBase64BinaryLessThan(
@NonNull IBase64BinaryItem arg1,
@NonNull IBase64BinaryItem arg2) {
return IBooleanItem.valueOf(arg1.compareTo(arg2) < 0);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-numeric-add">op:numeric-add</a>.
*
* @param left
* the first number
* @param right
* the second number
* @return the result of adding the second number to the first number
*/
@NonNull
public static INumericItem opNumericAdd(@NonNull INumericItem left, @NonNull INumericItem right) {
INumericItem retval;
if (left instanceof IIntegerItem || right instanceof IIntegerItem) {
// create an integer result
BigInteger integerLeft = left.asInteger();
BigInteger integerRight = right.asInteger();
@SuppressWarnings("null")
@NonNull
BigInteger result = integerLeft.add(integerRight);
retval = IIntegerItem.valueOf(result);
} else {
// create a decimal result
BigDecimal decimalLeft = left.asDecimal();
BigDecimal decimalRight = right.asDecimal();
@SuppressWarnings("null")
@NonNull
BigDecimal result = decimalLeft.add(decimalRight, FunctionUtils.MATH_CONTEXT);
retval = IDecimalItem.valueOf(result);
}
return retval;
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-numeric-subtract">op:numeric-subtract</a>.
*
* @param left
* the first number
* @param right
* the second number
* @return the result of subtracting the second number from the first number
*/
@NonNull
public static INumericItem opNumericSubtract(@NonNull INumericItem left, @NonNull INumericItem right) {
INumericItem retval;
if (left instanceof IIntegerItem || right instanceof IIntegerItem) {
// create an integer result
BigInteger integerLeft = left.asInteger();
BigInteger integerRight = right.asInteger();
@SuppressWarnings("null")
@NonNull
BigInteger result = integerLeft.subtract(integerRight);
retval = IIntegerItem.valueOf(result);
} else {
// create a decimal result
BigDecimal decimalLeft = left.asDecimal();
BigDecimal decimalRight = right.asDecimal();
@SuppressWarnings("null")
@NonNull
BigDecimal result = decimalLeft.subtract(decimalRight, FunctionUtils.MATH_CONTEXT);
retval = IDecimalItem.valueOf(result);
}
return retval;
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-numeric-multiply">op:numeric-multiply</a>.
*
* @param left
* the first number
* @param right
* the second number
* @return the result of multiplying the first number by the second number
*/
@NonNull
public static INumericItem opNumericMultiply(@NonNull INumericItem left, @NonNull INumericItem right) {
INumericItem retval;
if (left instanceof IIntegerItem || right instanceof IIntegerItem) {
// create an integer result
@SuppressWarnings("null")
@NonNull
BigInteger result = left.asInteger().multiply(right.asInteger());
retval = IIntegerItem.valueOf(result);
} else {
// create a decimal result
BigDecimal decimalLeft = left.asDecimal();
BigDecimal decimalRight = right.asDecimal();
@SuppressWarnings("null")
@NonNull
BigDecimal result = decimalLeft.multiply(decimalRight, FunctionUtils.MATH_CONTEXT);
retval = IDecimalItem.valueOf(result);
}
return retval;
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-numeric-divide">op:numeric-divide</a>.
*
* @param dividend
* the number to be divided
* @param divisor
* the number to divide by
* @return the quotient
*/
@NonNull
public static IDecimalItem opNumericDivide(@NonNull INumericItem dividend, @NonNull INumericItem divisor) {
// create a decimal result
BigDecimal decimalDivisor = divisor.asDecimal();
if (BigDecimal.ZERO.equals(decimalDivisor)) {
throw new ArithmeticFunctionException(ArithmeticFunctionException.DIVISION_BY_ZERO,
ArithmeticFunctionException.DIVISION_BY_ZERO_MESSAGE);
}
BigDecimal decimalDividend = dividend.asDecimal();
@SuppressWarnings("null")
@NonNull
BigDecimal result = decimalDividend.divide(decimalDivisor, FunctionUtils.MATH_CONTEXT);
return IDecimalItem.valueOf(result);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-numeric-integer-divide">op:numeric-integer-divide</a>.
*
* @param dividend
* the number to be divided
* @param divisor
* the number to divide by
* @return the quotient
*/
@NonNull
public static IIntegerItem opNumericIntegerDivide(@NonNull INumericItem dividend, @NonNull INumericItem divisor) {
IIntegerItem retval;
if (dividend instanceof IIntegerItem || divisor instanceof IIntegerItem) {
// create an integer result
BigInteger integerDivisor = divisor.asInteger();
if (BigInteger.ZERO.equals(integerDivisor)) {
throw new ArithmeticFunctionException(ArithmeticFunctionException.DIVISION_BY_ZERO,
ArithmeticFunctionException.DIVISION_BY_ZERO_MESSAGE);
}
@SuppressWarnings("null")
@NonNull
BigInteger result = dividend.asInteger().divide(integerDivisor);
retval = IIntegerItem.valueOf(result);
} else {
// create a decimal result
BigDecimal decimalDivisor = divisor.asDecimal();
if (BigDecimal.ZERO.equals(decimalDivisor)) {
throw new ArithmeticFunctionException(ArithmeticFunctionException.DIVISION_BY_ZERO,
ArithmeticFunctionException.DIVISION_BY_ZERO_MESSAGE);
}
BigDecimal decimalDividend = dividend.asDecimal();
@SuppressWarnings("null")
@NonNull
BigInteger result
= decimalDividend.divideToIntegralValue(decimalDivisor, FunctionUtils.MATH_CONTEXT).toBigInteger();
retval = IIntegerItem.valueOf(result);
}
return retval;
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-numeric-mod">op:numeric-mod</a>.
*
* @param dividend
* the number to be divided
* @param divisor
* the number to divide by
* @return the remainder
*/
@NonNull
public static INumericItem opNumericMod(@NonNull INumericItem dividend, @NonNull INumericItem divisor) {
BigDecimal decimalDivisor = divisor.asDecimal();
if (BigDecimal.ZERO.equals(decimalDivisor)) {
throw new ArithmeticFunctionException(ArithmeticFunctionException.DIVISION_BY_ZERO,
ArithmeticFunctionException.DIVISION_BY_ZERO_MESSAGE);
}
BigDecimal decimalDividend = dividend.asDecimal();
INumericItem retval;
if (BigDecimal.ZERO.equals(decimalDividend)) {
retval = dividend;
} else {
@SuppressWarnings("null")
@NonNull
BigDecimal result = decimalDividend.remainder(decimalDivisor, FunctionUtils.MATH_CONTEXT);
retval = IDecimalItem.valueOf(result);
}
return retval;
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-numeric-unary-minus">op:numeric-unary-minus</a>.
*
* @param item
* the number whose sign is to be reversed
* @return the number with a reversed sign
*/
@NonNull
public static INumericItem opNumericUnaryMinus(@NonNull INumericItem item) {
INumericItem retval;
if (item instanceof IIntegerItem) {
// create a decimal result
BigInteger integer = item.asInteger();
@SuppressWarnings("null")
@NonNull
BigInteger result = integer.negate();
retval = IIntegerItem.valueOf(result);
} else if (item instanceof IDecimalItem) {
// create a decimal result
BigDecimal decimal = item.asDecimal();
@SuppressWarnings("null")
@NonNull
BigDecimal result = decimal.negate(FunctionUtils.MATH_CONTEXT);
retval = IDecimalItem.valueOf(result);
} else {
throw new InvalidTypeMetapathException(item);
}
return retval;
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-numeric-equal">op:numeric-equal</a>.
*
* @param arg1
* the first number to check for equality
* @param arg2
* the second number to check for equality
* @return {@code true} if the numbers are numerically equal or {@code false}
* otherwise
*/
@NonNull
public static IBooleanItem opNumericEqual(@Nullable INumericItem arg1, @Nullable INumericItem arg2) {
IBooleanItem retval;
if (arg1 == null || arg2 == null) {
retval = IBooleanItem.FALSE;
} else if (arg1 instanceof IIntegerItem || arg2 instanceof IIntegerItem) {
retval = IBooleanItem.valueOf(arg1.asInteger().equals(arg2.asInteger()));
} else {
retval = IBooleanItem.valueOf(arg1.asDecimal().equals(arg2.asDecimal()));
}
return retval;
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-numeric-greater-than">op:numeric-greater-than</a>.
*
* @param arg1
* the first number to check
* @param arg2
* the second number to check
* @return {@code true} if the first number is greater than or equal to the
* second, or {@code false} otherwise
*/
@NonNull
public static IBooleanItem opNumericGreaterThan(@Nullable INumericItem arg1, @Nullable INumericItem arg2) {
IBooleanItem retval;
if (arg1 == null || arg2 == null) {
retval = IBooleanItem.FALSE;
} else if (arg1 instanceof IIntegerItem || arg2 instanceof IIntegerItem) {
int result = arg1.asInteger().compareTo(arg2.asInteger());
retval = IBooleanItem.valueOf(result > 0);
} else {
int result = arg1.asDecimal().compareTo(arg2.asDecimal());
retval = IBooleanItem.valueOf(result > 0);
}
return retval;
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-numeric-less-than">op:numeric-less-than</a>.
*
* @param arg1
* the first number to check
* @param arg2
* the second number to check
* @return {@code true} if the first number is less than or equal to the second,
* or {@code false} otherwise
*/
@NonNull
public static IBooleanItem opNumericLessThan(@Nullable INumericItem arg1, @Nullable INumericItem arg2) {
IBooleanItem retval;
if (arg1 == null || arg2 == null) {
retval = IBooleanItem.FALSE;
} else if (arg1 instanceof IIntegerItem || arg2 instanceof IIntegerItem) {
int result = arg1.asInteger().compareTo(arg2.asInteger());
retval = IBooleanItem.valueOf(result < 0);
} else {
int result = arg1.asDecimal().compareTo(arg2.asDecimal());
retval = IBooleanItem.valueOf(result < 0);
}
return retval;
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-boolean-equal">op:boolean-equal</a>.
*
* @param arg1
* the first boolean to check
* @param arg2
* the second boolean to check
* @return {@code true} if the first boolean is equal to the second, or
* {@code false} otherwise
*/
@NonNull
public static IBooleanItem opBooleanEqual(@Nullable IBooleanItem arg1, @Nullable IBooleanItem arg2) {
boolean left = arg1 != null && arg1.toBoolean();
boolean right = arg2 != null && arg2.toBoolean();
return IBooleanItem.valueOf(left == right);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-boolean-greater-than">op:boolean-greater-than</a>.
*
* @param arg1
* the first boolean to check
* @param arg2
* the second boolean to check
* @return {@code true} if the first argument is {@link IBooleanItem#TRUE} and
* the second is {@link IBooleanItem#FALSE}, or {@code false} otherwise
*/
@NonNull
public static IBooleanItem opBooleanGreaterThan(@Nullable IBooleanItem arg1, @Nullable IBooleanItem arg2) {
boolean left = arg1 != null && arg1.toBoolean();
boolean right = arg2 != null && arg2.toBoolean();
return IBooleanItem.valueOf(left && !right);
}
/**
* Based on XPath 3.1 <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-boolean-less-than">op:boolean-less-than</a>.
*
* @param arg1
* the first boolean to check
* @param arg2
* the second boolean to check
* @return {@code true} if the first argument is {@link IBooleanItem#FALSE} and
* the second is {@link IBooleanItem#TRUE}, or {@code false} otherwise
*/
@NonNull
public static IBooleanItem opBooleanLessThan(@Nullable IBooleanItem arg1, @Nullable IBooleanItem arg2) {
boolean left = arg1 != null && arg1.toBoolean();
boolean right = arg2 != null && arg2.toBoolean();
return IBooleanItem.valueOf(!left && right);
}
}