001/*
002 * The MIT License (MIT)
003 *
004 * Copyright (c) 2015-2023 decimal4j (tools4j), Marco Terzer
005 *
006 * Permission is hereby granted, free of charge, to any person obtaining a copy
007 * of this software and associated documentation files (the "Software"), to deal
008 * in the Software without restriction, including without limitation the rights
009 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
010 * copies of the Software, and to permit persons to whom the Software is
011 * furnished to do so, subject to the following conditions:
012 *
013 * The above copyright notice and this permission notice shall be included in all
014 * copies or substantial portions of the Software.
015 *
016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
017 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
018 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
019 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
020 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
021 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
022 * SOFTWARE.
023 */
024package org.decimal4j.generic;
025
026import java.util.Objects;
027
028import org.decimal4j.api.Decimal;
029import org.decimal4j.api.ImmutableDecimal;
030import org.decimal4j.base.AbstractImmutableDecimal;
031import org.decimal4j.factory.Factories;
032import org.decimal4j.scale.ScaleMetrics;
033import org.decimal4j.scale.Scales;
034
035/**
036 * <code>GenericImmutableDecimal</code> is an {@link ImmutableDecimal} implemented
037 * in a generic way, that is, different instances can have different scales. In
038 * contrast the classes defined in the {@code immutable} package have have no
039 * generic parameter as they have a fixed scale per class.
040 * 
041 * @param <S>
042 *            the scale metrics type associated with this decimal
043 */
044public final class GenericImmutableDecimal<S extends ScaleMetrics> extends AbstractImmutableDecimal<S, GenericImmutableDecimal<S>> {
045
046        private static final long serialVersionUID = 1L;
047
048        private final S scaleMetrics;
049
050        /**
051         * Creates a new {@code GenericImmutableDecimal} with the scale specified by
052         * the given {@code scaleMetrics} argument. The numeric value of new the
053         * Decimal is <code>unscaledValue &times; 10<sup>-scale</sup></code>
054         * 
055         * @param scaleMetrics
056         *            the metrics object defining the scale for the new value
057         * @param unscaledValue
058         *            the unscaled long value representing the new Decimal's
059         *            numerical value before applying the scale factor
060         */
061        public GenericImmutableDecimal(S scaleMetrics, long unscaledValue) {
062                super(unscaledValue);
063                this.scaleMetrics = Objects.requireNonNull(scaleMetrics, "scaleMetrics cannot be null");
064        }
065
066        /**
067         * Creates a new {@code GenericImmutableDecimal} with the same value and scale
068         * as the given {@code decimal} argument.
069         * 
070         * @param decimal
071         *            the numeric value to assign to the created immutable Decimal
072         */
073        public GenericImmutableDecimal(Decimal<S> decimal) {
074                this(decimal.getScaleMetrics(), decimal.unscaledValue());
075        }
076        
077        /**
078         * Creates and returns a new {@code GenericImmutableDecimal} with the same
079         * value and scale as the given {@code decimal} argument.
080         * 
081         * @param decimal
082         *            the numeric value to assign to the created immutable Decimal
083         * @param <S> the scale metrics type
084         * @return a new generic immutable Decimal value with scale and value copied
085         *         from the {@code decimal} argument
086         */
087        public static <S extends ScaleMetrics> GenericImmutableDecimal<S> valueOf(Decimal<S> decimal) {
088                return new GenericImmutableDecimal<S>(decimal);
089        }
090
091        /**
092         * Creates and returns a new {@code GenericImmutableDecimal} with the scale
093         * specified by the given {@code scaleMetrics} argument. The numeric value
094         * of new the Decimal is
095         * <code>unscaledValue &times; 10<sup>-scale</sup></code>
096         * 
097         * @param scaleMetrics
098         *            the metrics object defining the scale for the new value
099         * @param unscaled
100         *            the unscaled long value representing the new Decimal's
101         *            numerical value before applying the scale factor
102         * @param <S> the scale metrics type
103         * @return a new Decimal value representing
104         *         <code>unscaledValue &times; 10<sup>-scale</sup></code>
105         */
106        public static <S extends ScaleMetrics> GenericImmutableDecimal<S> valueOfUnscaled(S scaleMetrics, long unscaled) {
107                return new GenericImmutableDecimal<S>(scaleMetrics, unscaled);
108        }
109
110        /**
111         * Creates and returns a new {@code GenericImmutableDecimal} with the
112         * specified {@code scale} and value. The numeric value of new the Decimal
113         * is <code>unscaledValue &times; 10<sup>-scale</sup></code>
114         * 
115         * @param scale
116         *            the scale for the new value
117         * @param unscaled
118         *            the unscaled long value representing the new Decimal's
119         *            numerical value before applying the scale factor
120         * @return a new Decimal value representing
121         *         <code>unscaledValue &times; 10<sup>-scale</sup></code>
122         */
123        public static GenericImmutableDecimal<?> valueOfUnscaled(int scale, long unscaled) {
124                return valueOfUnscaled(Scales.getScaleMetrics(scale), unscaled);
125        }
126        
127        @Override
128        public S getScaleMetrics() {
129                return scaleMetrics;
130        }
131
132        @Override
133        public int getScale() {
134                return scaleMetrics.getScale();
135        }
136
137        @Override
138        public GenericDecimalFactory<S> getFactory() {
139                return Factories.getGenericDecimalFactory(scaleMetrics);
140        }
141
142        @Override
143        protected GenericImmutableDecimal<S> self() {
144                return this;
145        }
146
147        @Override
148        protected GenericImmutableDecimal<S> createOrAssign(long unscaled) {
149                return unscaledValue() == unscaled ? this : create(unscaled);
150        }
151        
152        @Override
153        protected GenericImmutableDecimal<S> create(long unscaled) {
154                return new GenericImmutableDecimal<S>(scaleMetrics, unscaled);
155        }
156        
157        @SuppressWarnings("unchecked")
158        @Override
159        protected GenericImmutableDecimal<S>[] createArray(int length) {
160                return new GenericImmutableDecimal[length];
161        }
162
163        @Override
164        public GenericMutableDecimal<S> toMutableDecimal() {
165                return new GenericMutableDecimal<S>(this);
166        }
167
168        @Override
169        public GenericImmutableDecimal<S> toImmutableDecimal() {
170                return this;
171        }
172}