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.factory;
025
026import java.math.BigDecimal;
027import java.math.BigInteger;
028import java.math.RoundingMode;
029
030import org.decimal4j.api.Decimal;
031import org.decimal4j.api.ImmutableDecimal;
032import org.decimal4j.api.MutableDecimal;
033import org.decimal4j.scale.ScaleMetrics;
034
035/**
036 * Factory for {@link Decimal} values and Decimal arrays of the
037 * {@link #getScale() scale} defined by {@code <S>}.
038 *
039 * @param <S>
040 *            the {@link #getScaleMetrics() scale metrics} type associated with
041 *            decimals created by this factory
042 */
043public interface DecimalFactory<S extends ScaleMetrics> {
044        /**
045         * Returns the scale metrics type associated with Decimal values created by
046         * this factory.
047         * 
048         * @return the scale metrics defining the scale for Decimal values created
049         *         by this factory
050         */
051        S getScaleMetrics();
052
053        /**
054         * Returns the scale of values created by this factory.
055         * 
056         * @return the scale for Decimal values created by this factory
057         */
058        int getScale();
059
060        /**
061         * Returns the implementing class for immutable values.
062         * 
063         * @return the implementation type for immutable Decimal values
064         */
065        Class<? extends ImmutableDecimal<S>> immutableType();
066
067        /**
068         * Returns the implementing class for mutable values.
069         * 
070         * @return the implementation type for mutable Decimal values
071         */
072        Class<? extends MutableDecimal<S>> mutableType();
073
074        /**
075         * Returns a factory for the given {@code scale}.
076         * 
077         * @param scale
078         *            the scale of Decimal numbers created by the returned factory
079         * @return a decimal factory for numbers with the given scale
080         */
081        DecimalFactory<?> deriveFactory(int scale);
082
083        /**
084         * Returns a factory for the given {@code scaleMetrics}.
085         * 
086         * @param scaleMetrics
087         *            the metrics defining the scale of the Decimal numbers created
088         *            by the returned factory
089         * @param <S>
090         *            the generic type for {@code scaleMetrics}
091         * @return a decimal factory for numbers with the scale specified by
092         *         {@code scaleMetrics}
093         */
094        @SuppressWarnings("hiding")
095        <S extends ScaleMetrics> DecimalFactory<S> deriveFactory(S scaleMetrics);
096
097        /**
098         * Returns a new immutable Decimal whose value is numerically equal to that
099         * of the specified {@code long} value. An exception is thrown if the
100         * specified value is too large to be represented as a Decimal of this
101         * factory's {@link #getScale() scale}.
102         *
103         * @param value
104         *            long value to convert into an immutable Decimal value
105         * @return a Decimal value numerically equal to the specified {@code long}
106         *         value
107         * @throws IllegalArgumentException
108         *             if {@code value} is too large to be represented as a Decimal
109         *             with the scale of this factory
110         */
111        ImmutableDecimal<S> valueOf(long value);
112
113        /**
114         * Returns a new immutable Decimal whose value is calculated by rounding the
115         * specified {@code float} argument to the {@link #getScale() scale} of this
116         * factory using {@link RoundingMode#HALF_UP HALF_UP} rounding. An exception
117         * is thrown if the specified value is too large to be represented as a
118         * Decimal of this factory's scale.
119         *
120         * @param value
121         *            float value to convert into an immutable Decimal value
122         * @return a Decimal calculated as: <code>round<sub>HALF_UP</sub>(value)</code>
123         * @throws IllegalArgumentException
124         *             if {@code value} is NaN or infinite or if the magnitude is
125         *             too large for the float to be represented as a
126         *             {@code Decimal} with the scale of this factory
127         */
128        ImmutableDecimal<S> valueOf(float value);
129
130        /**
131         * Returns a new immutable Decimal whose value is calculated by rounding the
132         * specified {@code float} argument to the {@link #getScale() scale} of this
133         * factory using the specified {@code roundingMode}. An exception is thrown
134         * if the specified value is too large to be represented as a Decimal of
135         * this factory's scale.
136         *
137         * @param value
138         *            float value to convert into an immutable Decimal value
139         * @param roundingMode
140         *            the rounding mode to apply during the conversion if necessary
141         * @return a Decimal calculated as: <code>round(value)</code>
142         * @throws IllegalArgumentException
143         *             if {@code value} is NaN or infinite or if the magnitude is
144         *             too large for the float to be represented as a
145         *             {@code Decimal} with the scale of this factory
146         * @throws ArithmeticException
147         *             if {@code roundingMode==UNNECESSARY} and rounding is
148         *             necessary
149         */
150        ImmutableDecimal<S> valueOf(float value, RoundingMode roundingMode);
151
152        /**
153         * Returns a new immutable Decimal whose value is calculated by rounding the
154         * specified {@code double} argument to the {@link #getScale() scale} of
155         * this factory using {@link RoundingMode#HALF_UP HALF_UP} rounding. An
156         * exception is thrown if the specified value is too large to be represented
157         * as a Decimal of this factory's scale.
158         *
159         * @param value
160         *            double value to convert into an immutable Decimal value
161         * @return a Decimal calculated as: <code>round<sub>HALF_UP</sub>(value)</code>
162         * @throws IllegalArgumentException
163         *             if {@code value} is NaN or infinite or if the magnitude is
164         *             too large for the double to be represented as a
165         *             {@code Decimal} with the scale of this factory
166         */
167        ImmutableDecimal<S> valueOf(double value);
168
169        /**
170         * Returns a new immutable Decimal whose value is calculated by rounding the
171         * specified {@code double} argument to the {@link #getScale() scale} of
172         * this factory using the specified {@code roundingMode}. An exception is
173         * thrown if the specified value is too large to be represented as a Decimal
174         * of this factory's scale.
175         *
176         * @param value
177         *            double value to convert into an immutable Decimal value
178         * @param roundingMode
179         *            the rounding mode to apply during the conversion if necessary
180         * @return a Decimal calculated as: <code>round(value)</code>
181         * @throws IllegalArgumentException
182         *             if {@code value} is NaN or infinite or if the magnitude is
183         *             too large for the double to be represented as a
184         *             {@code Decimal} with the scale of this factory
185         * @throws ArithmeticException
186         *             if {@code roundingMode==UNNECESSARY} and rounding is
187         *             necessary
188         */
189        ImmutableDecimal<S> valueOf(double value, RoundingMode roundingMode);
190
191        /**
192         * Returns a new immutable Decimal whose value is numerically equal to that
193         * of the specified {@link BigInteger} value. An exception is thrown if the
194         * specified value is too large to be represented as a Decimal of this
195         * factory's {@link #getScale() scale}.
196         *
197         * @param value
198         *            {@code BigInteger} value to convert into an immutable Decimal
199         *            value
200         * @return a Decimal value numerically equal to the specified big integer
201         *         value
202         * @throws IllegalArgumentException
203         *             if {@code value} is too large to be represented as a Decimal
204         *             with the scale of this factory
205         */
206        ImmutableDecimal<S> valueOf(BigInteger value);
207
208        /**
209         * Returns a new immutable Decimal whose value is calculated by rounding the
210         * specified {@link BigDecimal} argument to the {@link #getScale() scale} of
211         * this factory using {@link RoundingMode#HALF_UP HALF_UP} rounding. An
212         * exception is thrown if the specified value is too large to be represented
213         * as a Decimal of this factory's scale.
214         *
215         * @param value
216         *            {@code BigDecimal} value to convert into an immutable Decimal
217         *            value
218         * @return a Decimal calculated as: <code>round<sub>HALF_UP</sub>(value)</code>
219         * @throws IllegalArgumentException
220         *             if {@code value} too large to be represented as a Decimal
221         *             with the scale of this factory
222         */
223        ImmutableDecimal<S> valueOf(BigDecimal value);
224
225        /**
226         * Returns a new immutable Decimal whose value is calculated by rounding the
227         * specified {@link BigDecimal} argument to the {@link #getScale() scale} of
228         * this factory using the specified {@code roundingMode}. An exception is
229         * thrown if the specified value is too large to be represented as a Decimal
230         * of this factory's scale.
231         *
232         * @param value
233         *            {@code BigDecimal} value to convert into an immutable Decimal
234         *            value
235         * @param roundingMode
236         *            the rounding mode to apply during the conversion if necessary
237         * @return a Decimal calculated as: <code>round(value)</code>
238         * @throws IllegalArgumentException
239         *             if {@code value} too large to be represented as a Decimal
240         *             with the scale of this factory
241         * @throws ArithmeticException
242         *             if {@code roundingMode==UNNECESSARY} and rounding is
243         *             necessary
244         */
245        ImmutableDecimal<S> valueOf(BigDecimal value, RoundingMode roundingMode);
246
247        /**
248         * Returns a new immutable Decimal whose value is calculated by rounding the
249         * specified {@link Decimal} argument to the {@link #getScale() scale} of
250         * this factory using {@link RoundingMode#HALF_UP HALF_UP} rounding. An
251         * exception is thrown if the specified value is too large to be represented
252         * as a Decimal of this factory's scale.
253         *
254         * @param value
255         *            Decimal value to convert into an immutable Decimal value of
256         *            this factory's scale
257         * @return a Decimal calculated as: <code>round<sub>HALF_UP</sub>(value)</code>
258         * @throws IllegalArgumentException
259         *             if {@code value} too large to be represented as a Decimal
260         *             with the scale of this factory
261         */
262        ImmutableDecimal<S> valueOf(Decimal<?> value);
263
264        /**
265         * Returns a new immutable Decimal whose value is calculated by rounding the
266         * specified {@link Decimal} argument to the {@link #getScale() scale} of
267         * this factory using the specified {@code roundingMode}. An exception is
268         * thrown if the specified value is too large to be represented as a Decimal
269         * of this factory's scale.
270         *
271         * @param value
272         *            Decimal value to convert into an immutable Decimal value of
273         *            this factory's scale
274         * @param roundingMode
275         *            the rounding mode to apply during the conversion if necessary
276         * @return a Decimal calculated as: <code>round(value)</code>
277         * @throws IllegalArgumentException
278         *             if {@code value} too large to be represented as a Decimal
279         *             with the scale of this factory
280         * @throws ArithmeticException
281         *             if {@code roundingMode==UNNECESSARY} and rounding is
282         *             necessary
283         */
284        ImmutableDecimal<S> valueOf(Decimal<?> value, RoundingMode roundingMode);
285
286        /**
287         * Translates the string representation of a {@code Decimal} into an
288         * immutable {@code Decimal}. The string representation consists of an
289         * optional sign, {@code '+'} or {@code '-'} , followed by a sequence of
290         * zero or more decimal digits ("the integer"), optionally followed by a
291         * fraction.
292         * <p>
293         * The fraction consists of a decimal point followed by zero or more decimal
294         * digits. The string must contain at least one digit in either the integer
295         * or the fraction. If the fraction contains more digits than this factory's
296         * {@link #getScale() scale}, the value is rounded using
297         * {@link RoundingMode#HALF_UP HALF_UP} rounding. An exception is thrown if
298         * the value is too large to be represented as a Decimal of this factory's
299         * scale.
300         *
301         * @param value
302         *            String value to convert into an immutable Decimal value of
303         *            this factory's scale
304         * @return a Decimal calculated as: <code>round<sub>HALF_UP</sub>(value)</code>
305         * @throws NumberFormatException
306         *             if {@code value} does not represent a valid {@code Decimal}
307         *             or if the value is too large to be represented as a Decimal
308         *             with the scale of this factory
309         */
310        ImmutableDecimal<S> parse(String value);
311
312        /**
313         * Translates the string representation of a {@code Decimal} into an
314         * immutable {@code Decimal}. The string representation consists of an
315         * optional sign, {@code '+'} or {@code '-'} , followed by a sequence of
316         * zero or more decimal digits ("the integer"), optionally followed by a
317         * fraction.
318         * <p>
319         * The fraction consists of a decimal point followed by zero or more decimal
320         * digits. The string must contain at least one digit in either the integer
321         * or the fraction. If the fraction contains more digits than this factory's
322         * {@link #getScale() scale}, the value is rounded using the specified
323         * {@code roundingMode}. An exception is thrown if the value is too large to
324         * be represented as a Decimal of this factory's scale.
325         *
326         * @param value
327         *            String value to convert into an immutable Decimal value of
328         *            this factory's scale
329         * @param roundingMode
330         *            the rounding mode to apply if the fraction contains more
331         *            digits than the scale of this factory
332         * @return a Decimal calculated as: <code>round(value)</code>
333         * @throws NumberFormatException
334         *             if {@code value} does not represent a valid {@code Decimal}
335         *             or if the value is too large to be represented as a Decimal
336         *             with the scale of this factory
337         * @throws ArithmeticException
338         *             if {@code roundingMode==UNNECESSARY} and rounding is
339         *             necessary
340         */
341        ImmutableDecimal<S> parse(String value, RoundingMode roundingMode);
342
343        /**
344         * Returns a new immutable Decimal whose value is numerically equal to
345         * <code>(unscaled &times; 10<sup>-scale</sup>)</code> where {@code scale}
346         * refers to this factory's {@link #getScale() scale}.
347         *
348         * @param unscaled
349         *            unscaled value to convert into an immutable Decimal value
350         * @return a Decimal calculated as:
351         *         <code>unscaled &times; 10<sup>-scale</sup></code>
352         */
353        ImmutableDecimal<S> valueOfUnscaled(long unscaled);
354
355        /**
356         * Returns a new immutable Decimal whose value is numerically equal to
357         * <code>(unscaled &times; 10<sup>-scale</sup>)</code>. The result is rounded to
358         * the {@link #getScale() scale} of this factory using
359         * {@link RoundingMode#HALF_UP HALF_UP} rounding. An exception is thrown if
360         * the specified value is too large to be represented as a Decimal of this
361         * factory's scale.
362         *
363         * @param unscaled
364         *            unscaled value to convert into an immutable Decimal value
365         * @param scale
366         *            the scale to apply to the {@code unscaled} value
367         * @return a Decimal calculated as:
368         *         <code>round<sub>HALF_UP</sub>(unscaled &times; 10<sup>-scale</sup>)</code>
369         * @throws IllegalArgumentException
370         *             if {@code value} too large to be represented as a Decimal of
371         *             this factory's scale
372         */
373        ImmutableDecimal<S> valueOfUnscaled(long unscaled, int scale);
374
375        /**
376         * Returns a new immutable Decimal whose value is numerically equal to
377         * <code>(unscaled &times; 10<sup>-scale</sup>)</code>. The result is rounded to
378         * the {@link #getScale() scale} of this factory using the specified
379         * {@code roundingMode}. An exception is thrown if the specified value is
380         * too large to be represented as a Decimal of this factory's scale.
381         *
382         * @param unscaled
383         *            unscaled value to convert into an immutable Decimal value
384         * @param scale
385         *            the scale to apply to the {@code unscaled} value
386         * @param roundingMode
387         *            the rounding mode to apply during the conversion if necessary
388         * @return a Decimal calculated as:
389         *         <code>round(unscaled &times; 10<sup>-scale</sup>)</code>
390         * @throws IllegalArgumentException
391         *             if {@code value} too large to be represented as a Decimal of
392         *             this factory's scale
393         * @throws ArithmeticException
394         *             if {@code roundingMode==UNNECESSARY} and rounding is
395         *             necessary
396         */
397        ImmutableDecimal<S> valueOfUnscaled(long unscaled, int scale, RoundingMode roundingMode);
398
399        /**
400         * Creates a one dimensional array of the specified {@code length} for
401         * immutable Decimal values.
402         * 
403         * @param length
404         *            the length of the returned array
405         * @return a new array of the specified length
406         */
407        ImmutableDecimal<S>[] newArray(int length);
408
409        /**
410         * Creates a new mutable value initialized with zero.
411         * 
412         * @return a new mutable Decimal value representing zero.
413         */
414        MutableDecimal<S> newMutable();
415
416        /**
417         * Creates a one dimensional array of the specified {@code length} for
418         * mutable Decimal values.
419         * 
420         * @param length
421         *            the length of the returned array
422         * @return a new array of the specified length
423         */
424        MutableDecimal<S>[] newMutableArray(int length);
425}