alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (NativeNumber.java)

This example Java source code file (NativeNumber.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

classcastexception, function, infinity, methodhandle, nan, nativenumber, object, override, property, propertymap, scriptobject, string, text, undefined, util, wrapfilter

The NativeNumber.java Java example source code

/*
 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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 General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package jdk.nashorn.internal.objects;

import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.JSType.isRepresentableAsInt;
import static jdk.nashorn.internal.runtime.JSType.isRepresentableAsLong;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import static jdk.nashorn.internal.lookup.Lookup.MH;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.text.NumberFormat;
import java.util.Locale;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;

/**
 * ECMA 15.7 Number Objects.
 *
 */
@ScriptClass("Number")
public final class NativeNumber extends ScriptObject {

    static final MethodHandle WRAPFILTER = findWrapFilter();

    /** ECMA 15.7.3.2 largest positive finite value */
    @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT, where = Where.CONSTRUCTOR)
    public static final double MAX_VALUE = Double.MAX_VALUE;

    /** ECMA 15.7.3.3 smallest positive finite value */
    @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT, where = Where.CONSTRUCTOR)
    public static final double MIN_VALUE = Double.MIN_VALUE;

    /** ECMA 15.7.3.4 NaN */
    @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT, where = Where.CONSTRUCTOR)
    public static final double NaN = Double.NaN;

    /** ECMA 15.7.3.5 negative infinity */
    @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT, where = Where.CONSTRUCTOR)
    public static final double NEGATIVE_INFINITY = Double.NEGATIVE_INFINITY;

    /** ECMA 15.7.3.5 positive infinity */
    @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT, where = Where.CONSTRUCTOR)
    public static final double POSITIVE_INFINITY = Double.POSITIVE_INFINITY;

    private final double  value;
    private final boolean isInt;
    private final boolean isLong;

    // initialized by nasgen
    private static PropertyMap $nasgenmap$;

    static PropertyMap getInitialMap() {
        return $nasgenmap$;
    }

    private NativeNumber(final double value, final ScriptObject proto, final PropertyMap map) {
        super(proto, map);
        this.value = value;
        this.isInt  = isRepresentableAsInt(value);
        this.isLong = isRepresentableAsLong(value);
    }

    NativeNumber(final double value, final Global global) {
        this(value, global.getNumberPrototype(), global.getNumberMap());
    }

    private NativeNumber(final double value) {
        this(value, Global.instance());
    }


    @Override
    public String safeToString() {
        return "[Number " + toString() + "]";
    }

    @Override
    public String toString() {
        return Double.toString(getValue());
    }

    /**
     * Get the value of this Number
     * @return a {@code double} representing the Number value
     */
    public double getValue() {
        return doubleValue();
    }

    /**
     * Get the value of this Number
     * @return a {@code double} representing the Number value
     */
    public double doubleValue() {
        return value;
    }

    /**
     * Get the value of this Number as a {@code int}
     * @return an {@code int} representing the Number value
     * @throws ClassCastException If number is not representable as an {@code int}
     */
    public int intValue() throws ClassCastException {
        if (isInt) {
            return (int)value;
        }
        throw new ClassCastException();
    }

    /**
     * Get the value of this Number as a {@code long}
     * @return a {@code long} representing the Number value
     * @throws ClassCastException If number is not representable as an {@code long}
     */
    public long longValue() throws ClassCastException {
        if (isLong) {
            return (long)value;
        }
        throw new ClassCastException();
    }

    @Override
    public String getClassName() {
        return "Number";
    }

    /**
     * ECMA 15.7.2 - The Number constructor
     *
     * @param newObj is this Number instantiated with the new operator
     * @param self   self reference
     * @param args   value of number
     * @return the Number instance (internally represented as a {@code NativeNumber})
     */
    @Constructor(arity = 1)
    public static Object constructor(final boolean newObj, final Object self, final Object... args) {
        final double num = (args.length > 0) ? JSType.toNumber(args[0]) : 0.0;

        return newObj? new NativeNumber(num) : num;
    }

    /**
     * ECMA 15.7.4.5 Number.prototype.toFixed (fractionDigits)
     *
     * @param self           self reference
     * @param fractionDigits how many digits should be after the decimal point, 0 if undefined
     *
     * @return number in decimal fixed point notation
     */
    @Function(attributes = Attribute.NOT_ENUMERABLE)
    public static Object toFixed(final Object self, final Object fractionDigits) {
        final int f = JSType.toInteger(fractionDigits);
        if (f < 0 || f > 20) {
            throw rangeError("invalid.fraction.digits", "toFixed");
        }

        final double x = getNumberValue(self);
        if (Double.isNaN(x)) {
            return "NaN";
        }

        if (Math.abs(x) >= 1e21) {
            return JSType.toString(x);
        }

        final NumberFormat format = NumberFormat.getNumberInstance(Locale.US);
        format.setMinimumFractionDigits(f);
        format.setMaximumFractionDigits(f);
        format.setGroupingUsed(false);

        return format.format(x);
    }

    /**
     * ECMA 15.7.4.6 Number.prototype.toExponential (fractionDigits)
     *
     * @param self           self reference
     * @param fractionDigits how many digital should be after the significand's decimal point. If undefined, use as many as necessary to uniquely specify number.
     *
     * @return number in decimal exponential notation
     */
    @Function(attributes = Attribute.NOT_ENUMERABLE)
    public static Object toExponential(final Object self, final Object fractionDigits) {
        final double  x         = getNumberValue(self);
        final boolean trimZeros = fractionDigits == UNDEFINED;
        final int     f         = trimZeros ? 16 : JSType.toInteger(fractionDigits);

        if (Double.isNaN(x)) {
            return "NaN";
        } else if (Double.isInfinite(x)) {
            return x > 0? "Infinity" : "-Infinity";
        }

        if (fractionDigits != UNDEFINED && (f < 0 || f > 20)) {
            throw rangeError("invalid.fraction.digits", "toExponential");
        }

        final String res = String.format(Locale.US, "%1." + f + "e", x);
        return fixExponent(res, trimZeros);
    }

    /**
     * ECMA 15.7.4.7 Number.prototype.toPrecision (precision)
     *
     * @param self      self reference
     * @param precision use {@code precision - 1} digits after the significand's decimal point or call {@link NativeDate#toString} if undefined
     *
     * @return number in decimal exponentiation notation or decimal fixed notation depending on {@code precision}
     */
    @Function(attributes = Attribute.NOT_ENUMERABLE)
    public static Object toPrecision(final Object self, final Object precision) {
        final double x = getNumberValue(self);
        if (precision == UNDEFINED) {
            return JSType.toString(x);
        }

        final int p = JSType.toInteger(precision);
        if (Double.isNaN(x)) {
            return "NaN";
        } else if (Double.isInfinite(x)) {
            return x > 0? "Infinity" : "-Infinity";
        }

        if (p < 1 || p > 21) {
            throw rangeError("invalid.precision");
        }

        // workaround for http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6469160
        if (x == 0.0 && p <= 1) {
            return "0";
        }

        return fixExponent(String.format(Locale.US, "%." + p + "g", x), false);
    }

    /**
     * ECMA 15.7.4.2 Number.prototype.toString ( [ radix ] )
     *
     * @param self  self reference
     * @param radix radix to use for string conversion
     * @return string representation of this Number in the given radix
     */
    @Function(attributes = Attribute.NOT_ENUMERABLE)
    public static Object toString(final Object self, final Object radix) {
        if (radix != UNDEFINED) {
            final int intRadix = JSType.toInteger(radix);
            if (intRadix != 10) {
                if (intRadix < 2 || intRadix > 36) {
                    throw rangeError("invalid.radix");
                }
                return JSType.toString(getNumberValue(self), intRadix);
            }
        }

        return JSType.toString(getNumberValue(self));
    }

    /**
     * ECMA 15.7.4.3 Number.prototype.toLocaleString()
     *
     * @param self self reference
     * @return localized string for this Number
     */
    @Function(attributes = Attribute.NOT_ENUMERABLE)
    public static Object toLocaleString(final Object self) {
        return JSType.toString(getNumberValue(self));
    }


    /**
     * ECMA 15.7.4.4 Number.prototype.valueOf ( )
     *
     * @param self self reference
     * @return boxed number value for this Number
     */
    @Function(attributes = Attribute.NOT_ENUMERABLE)
    public static Object valueOf(final Object self) {
        return getNumberValue(self);
    }

    /**
     * Lookup the appropriate method for an invoke dynamic call.
     * @param request  The link request
     * @param receiver receiver of call
     * @return Link to be invoked at call site.
     */
    public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) {
        return PrimitiveLookup.lookupPrimitive(request, Number.class, new NativeNumber(((Number)receiver).doubleValue()), WRAPFILTER);
    }

    @SuppressWarnings("unused")
    private static NativeNumber wrapFilter(final Object receiver) {
        return new NativeNumber(((Number)receiver).doubleValue());
    }

    private static double getNumberValue(final Object self) {
        if (self instanceof Number) {
            return ((Number)self).doubleValue();
        } else if (self instanceof NativeNumber) {
            return ((NativeNumber)self).getValue();
        } else if (self != null && self == Global.instance().getNumberPrototype()) {
            return 0.0;
        } else {
            throw typeError("not.a.number", ScriptRuntime.safeToString(self));
        }
    }

    // Exponent of Java "e" or "E" formatter is always 2 digits and zero
    // padded if needed (e+01, e+00, e+12 etc.) JS expects exponent to contain
    // exact number of digits e+1, e+0, e+12 etc. Fix the exponent here.
    //
    // Additionally, if trimZeros is true, this cuts trailing zeros in the
    // fraction part for calls to toExponential() with undefined fractionDigits
    // argument.
    private static String fixExponent(final String str, final boolean trimZeros) {
        final int index = str.indexOf('e');
        if (index < 1) {
            // no exponent, do nothing..
            return str;
        }

        // check if character after e+ or e- is 0
        final int expPadding = str.charAt(index + 2) == '0' ? 3 : 2;
        // check if there are any trailing zeroes we should remove

        int fractionOffset = index;
        if (trimZeros) {
            assert fractionOffset > 0;
            char c = str.charAt(fractionOffset - 1);
            while (fractionOffset > 1 && (c == '0' || c == '.')) {
                c = str.charAt(--fractionOffset - 1);
            }

        }
        // if anything needs to be done compose a new string
        if (fractionOffset < index || expPadding == 3) {
            return str.substring(0, fractionOffset)
                    + str.substring(index, index + 2)
                    + str.substring(index + expPadding);
        }
        return str;
    }

    private static MethodHandle findWrapFilter() {
        return MH.findStatic(MethodHandles.lookup(), NativeNumber.class, "wrapFilter", MH.type(NativeNumber.class, Object.class));
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java NativeNumber.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.