michael@0: /* michael@0: * Copyright (C) 2012 Google Inc. All rights reserved. michael@0: * michael@0: * Redistribution and use in source and binary forms, with or without michael@0: * modification, are permitted provided that the following conditions are michael@0: * met: michael@0: * michael@0: * * Redistributions of source code must retain the above copyright michael@0: * notice, this list of conditions and the following disclaimer. michael@0: * * Redistributions in binary form must reproduce the above michael@0: * copyright notice, this list of conditions and the following disclaimer michael@0: * in the documentation and/or other materials provided with the michael@0: * distribution. michael@0: * * Neither the name of Google Inc. nor the names of its michael@0: * contributors may be used to endorse or promote products derived from michael@0: * this software without specific prior written permission. michael@0: * michael@0: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: */ michael@0: michael@0: /** michael@0: * Imported from: michael@0: * http://src.chromium.org/viewvc/blink/trunk/Source/core/platform/Decimal.h michael@0: * Check hg log for the svn rev of the last update from Blink core. michael@0: */ michael@0: michael@0: #ifndef Decimal_h michael@0: #define Decimal_h michael@0: michael@0: #include "mozilla/Assertions.h" michael@0: #include michael@0: #include "mozilla/Types.h" michael@0: michael@0: #include michael@0: michael@0: #ifndef ASSERT michael@0: #define DEFINED_ASSERT_FOR_DECIMAL_H 1 michael@0: #define ASSERT MOZ_ASSERT michael@0: #endif michael@0: michael@0: // To use WTF_MAKE_FAST_ALLOCATED we'd need: michael@0: // http://src.chromium.org/viewvc/blink/trunk/Source/wtf/FastMalloc.h michael@0: // Since we don't allocate Decimal objects, no need. michael@0: #define WTF_MAKE_FAST_ALLOCATED \ michael@0: void ignore_this_dummy_method() MOZ_DELETE michael@0: michael@0: namespace WebCore { michael@0: michael@0: namespace DecimalPrivate { michael@0: class SpecialValueHandler; michael@0: } michael@0: michael@0: // This class represents decimal base floating point number. michael@0: // michael@0: // FIXME: Once all C++ compiler support decimal type, we should replace this michael@0: // class to compiler supported one. See below URI for current status of decimal michael@0: // type for C++: // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1977.html michael@0: class Decimal { michael@0: WTF_MAKE_FAST_ALLOCATED; michael@0: public: michael@0: enum Sign { michael@0: Positive, michael@0: Negative, michael@0: }; michael@0: michael@0: // You should not use EncodedData other than unit testing. michael@0: class EncodedData { michael@0: // For accessing FormatClass. michael@0: friend class Decimal; michael@0: friend class DecimalPrivate::SpecialValueHandler; michael@0: public: michael@0: EncodedData(Sign, int exponent, uint64_t coefficient); michael@0: michael@0: bool operator==(const EncodedData&) const; michael@0: bool operator!=(const EncodedData& another) const { return !operator==(another); } michael@0: michael@0: uint64_t coefficient() const { return m_coefficient; } michael@0: int countDigits() const; michael@0: int exponent() const { return m_exponent; } michael@0: bool isFinite() const { return !isSpecial(); } michael@0: bool isInfinity() const { return m_formatClass == ClassInfinity; } michael@0: bool isNaN() const { return m_formatClass == ClassNaN; } michael@0: bool isSpecial() const { return m_formatClass == ClassInfinity || m_formatClass == ClassNaN; } michael@0: bool isZero() const { return m_formatClass == ClassZero; } michael@0: Sign sign() const { return m_sign; } michael@0: void setSign(Sign sign) { m_sign = sign; } michael@0: michael@0: private: michael@0: enum FormatClass { michael@0: ClassInfinity, michael@0: ClassNormal, michael@0: ClassNaN, michael@0: ClassZero, michael@0: }; michael@0: michael@0: EncodedData(Sign, FormatClass); michael@0: FormatClass formatClass() const { return m_formatClass; } michael@0: michael@0: uint64_t m_coefficient; michael@0: int16_t m_exponent; michael@0: FormatClass m_formatClass; michael@0: Sign m_sign; michael@0: }; michael@0: michael@0: MFBT_API Decimal(int32_t = 0); michael@0: MFBT_API Decimal(Sign, int exponent, uint64_t coefficient); michael@0: MFBT_API Decimal(const Decimal&); michael@0: michael@0: MFBT_API Decimal& operator=(const Decimal&); michael@0: MFBT_API Decimal& operator+=(const Decimal&); michael@0: MFBT_API Decimal& operator-=(const Decimal&); michael@0: MFBT_API Decimal& operator*=(const Decimal&); michael@0: MFBT_API Decimal& operator/=(const Decimal&); michael@0: michael@0: MFBT_API Decimal operator-() const; michael@0: michael@0: MFBT_API bool operator==(const Decimal&) const; michael@0: MFBT_API bool operator!=(const Decimal&) const; michael@0: MFBT_API bool operator<(const Decimal&) const; michael@0: MFBT_API bool operator<=(const Decimal&) const; michael@0: MFBT_API bool operator>(const Decimal&) const; michael@0: MFBT_API bool operator>=(const Decimal&) const; michael@0: michael@0: MFBT_API Decimal operator+(const Decimal&) const; michael@0: MFBT_API Decimal operator-(const Decimal&) const; michael@0: MFBT_API Decimal operator*(const Decimal&) const; michael@0: MFBT_API Decimal operator/(const Decimal&) const; michael@0: michael@0: int exponent() const michael@0: { michael@0: ASSERT(isFinite()); michael@0: return m_data.exponent(); michael@0: } michael@0: michael@0: bool isFinite() const { return m_data.isFinite(); } michael@0: bool isInfinity() const { return m_data.isInfinity(); } michael@0: bool isNaN() const { return m_data.isNaN(); } michael@0: bool isNegative() const { return sign() == Negative; } michael@0: bool isPositive() const { return sign() == Positive; } michael@0: bool isSpecial() const { return m_data.isSpecial(); } michael@0: bool isZero() const { return m_data.isZero(); } michael@0: michael@0: MFBT_API Decimal abs() const; michael@0: MFBT_API Decimal ceiling() const; michael@0: MFBT_API Decimal floor() const; michael@0: MFBT_API Decimal remainder(const Decimal&) const; michael@0: MFBT_API Decimal round() const; michael@0: michael@0: MFBT_API double toDouble() const; michael@0: // Note: toString method supports infinity and nan but fromString not. michael@0: MFBT_API std::string toString() const; michael@0: MFBT_API bool toString(char* strBuf, size_t bufLength) const; michael@0: michael@0: static MFBT_API Decimal fromDouble(double); michael@0: // fromString supports following syntax EBNF: michael@0: // number ::= sign? digit+ ('.' digit*) (exponent-marker sign? digit+)? michael@0: // | sign? '.' digit+ (exponent-marker sign? digit+)? michael@0: // sign ::= '+' | '-' michael@0: // exponent-marker ::= 'e' | 'E' michael@0: // digit ::= '0' | '1' | ... | '9' michael@0: // Note: fromString doesn't support "infinity" and "nan". michael@0: static MFBT_API Decimal fromString(const std::string& aValue); michael@0: static MFBT_API Decimal infinity(Sign); michael@0: static MFBT_API Decimal nan(); michael@0: static MFBT_API Decimal zero(Sign); michael@0: michael@0: // You should not use below methods. We expose them for unit testing. michael@0: MFBT_API explicit Decimal(const EncodedData&); michael@0: const EncodedData& value() const { return m_data; } michael@0: michael@0: private: michael@0: struct AlignedOperands { michael@0: uint64_t lhsCoefficient; michael@0: uint64_t rhsCoefficient; michael@0: int exponent; michael@0: }; michael@0: michael@0: MFBT_API Decimal(double); michael@0: MFBT_API Decimal compareTo(const Decimal&) const; michael@0: michael@0: static MFBT_API AlignedOperands alignOperands(const Decimal& lhs, const Decimal& rhs); michael@0: static inline Sign invertSign(Sign sign) { return sign == Negative ? Positive : Negative; } michael@0: michael@0: Sign sign() const { return m_data.sign(); } michael@0: michael@0: EncodedData m_data; michael@0: }; michael@0: michael@0: } // namespace WebCore michael@0: michael@0: namespace mozilla { michael@0: typedef WebCore::Decimal Decimal; michael@0: } michael@0: michael@0: #undef WTF_MAKE_FAST_ALLOCATED michael@0: michael@0: #ifdef DEFINED_ASSERT_FOR_DECIMAL_H michael@0: #undef DEFINED_ASSERT_FOR_DECIMAL_H michael@0: #undef ASSERT michael@0: #endif michael@0: michael@0: #endif // Decimal_h michael@0: