1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef builtin_intl_DecimalNumber_h 8 #define builtin_intl_DecimalNumber_h 9 10 #include "mozilla/Attributes.h" 11 #include "mozilla/Maybe.h" 12 #include "mozilla/Span.h" 13 #include "mozilla/Variant.h" 14 15 #include <stddef.h> 16 #include <stdint.h> 17 18 #include "jstypes.h" 19 20 #include "js/TypeDecls.h" 21 22 class JSLinearString; 23 24 namespace JS { 25 class JS_PUBLIC_API AutoCheckCannotGC; 26 } 27 28 namespace js::intl { 29 30 /** 31 * Representation of a decimal number in normalized form. 32 * 33 * Examples of normalized forms: 34 * - "123" is normalized to "0.123e3". 35 * - "0.01e-4" is normalized to "0.1e-5". 36 * - "12.3" is normalized to "0.123e2". 37 * 38 * Note: Internally we leave the decimal point where it lies to avoid copying 39 * the string, but otherwise ignore it once we calculate the normalized 40 * exponent. 41 */ 42 class MOZ_STACK_CLASS DecimalNumber final { 43 using Latin1String = mozilla::Span<const JS::Latin1Char>; 44 using TwoByteString = mozilla::Span<const char16_t>; 45 46 mozilla::Variant<Latin1String, TwoByteString> string_; 47 charAt(size_t i)48 char charAt(size_t i) const { 49 if (string_.is<Latin1String>()) { 50 return static_cast<char>(string_.as<Latin1String>()[i]); 51 } 52 return static_cast<char>(string_.as<TwoByteString>()[i]); 53 } 54 55 // Decimal exponent. Valid range is (INT32_MIN, INT_MAX32]. 56 int32_t exponent_ = 0; 57 58 // Start and end position of the significand. 59 size_t significandStart_ = 0; 60 size_t significandEnd_ = 0; 61 62 // Flag if the number is zero. 63 bool zero_ = false; 64 65 // Flag for negative numbers. 66 bool negative_ = false; 67 68 // Error flag when the exponent is too large. 69 bool exponentTooLarge_ = false; 70 71 template <typename CharT> DecimalNumber(mozilla::Span<const CharT> string)72 explicit DecimalNumber(mozilla::Span<const CharT> string) : string_(string) {} 73 74 public: 75 /** Return true if this decimal is zero. */ isZero()76 bool isZero() const { return zero_; } 77 78 /** Return true if this decimal is negative. */ isNegative()79 bool isNegative() const { return negative_; } 80 81 /** Return true if the exponent is too large. */ exponentTooLarge()82 bool exponentTooLarge() const { return exponentTooLarge_; } 83 84 /** Return the exponent of this decimal. */ exponent()85 int32_t exponent() const { return exponent_; } 86 87 // Exposed for testing. significandStart()88 size_t significandStart() const { return significandStart_; } significandEnd()89 size_t significandEnd() const { return significandEnd_; } 90 91 /** 92 * Compare this decimal to another decimal. Returns a negative value if this 93 * decimal is smaller; zero if this decimal is equal; or a positive value if 94 * this decimal is larger than the input. 95 */ 96 int32_t compareTo(const DecimalNumber& other) const; 97 98 /** 99 * Create a decimal number from the input. Returns |mozilla::Nothing| if the 100 * input can't be parsed. 101 */ 102 template <typename CharT> 103 static mozilla::Maybe<DecimalNumber> from(mozilla::Span<const CharT> chars); 104 105 /** 106 * Create a decimal number from the input. Returns |mozilla::Nothing| if the 107 * input can't be parsed. 108 */ 109 static mozilla::Maybe<DecimalNumber> from(JSLinearString* str, 110 JS::AutoCheckCannotGC& nogc); 111 }; 112 } // namespace js::intl 113 114 #endif /* builtin_intl_DecimalNumber_h */ 115