michael@0: // Copyright 2010 the V8 project authors. All rights reserved. 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 michael@0: // disclaimer in the documentation and/or other materials provided michael@0: // with the 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 michael@0: // from 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: #ifndef DOUBLE_CONVERSION_UTILS_H_ michael@0: #define DOUBLE_CONVERSION_UTILS_H_ michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "mozilla/Assertions.h" michael@0: #ifndef ASSERT michael@0: #define ASSERT(condition) MOZ_ASSERT(condition) michael@0: #endif michael@0: #ifndef UNIMPLEMENTED michael@0: #define UNIMPLEMENTED() MOZ_CRASH() michael@0: #endif michael@0: #ifndef UNREACHABLE michael@0: #define UNREACHABLE() MOZ_CRASH() michael@0: #endif michael@0: michael@0: // Double operations detection based on target architecture. michael@0: // Linux uses a 80bit wide floating point stack on x86. This induces double michael@0: // rounding, which in turn leads to wrong results. michael@0: // An easy way to test if the floating-point operations are correct is to michael@0: // evaluate: 89255.0/1e22. If the floating-point stack is 64 bits wide then michael@0: // the result is equal to 89255e-22. michael@0: // The best way to test this, is to create a division-function and to compare michael@0: // the output of the division with the expected result. (Inlining must be michael@0: // disabled.) michael@0: // On Linux,x86 89255e-22 != Div_double(89255.0/1e22) michael@0: #if defined(_M_X64) || defined(__x86_64__) || \ michael@0: defined(__ARMEL__) || defined(__avr32__) || \ michael@0: defined(__hppa__) || defined(__ia64__) || \ michael@0: defined(__mips__) || \ michael@0: defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \ michael@0: defined(__sparc__) || defined(__sparc) || defined(__s390__) || \ michael@0: defined(__SH4__) || defined(__alpha__) || \ michael@0: defined(_MIPS_ARCH_MIPS32R2) || \ michael@0: defined(__AARCH64EL__) michael@0: #define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1 michael@0: #elif defined(_M_IX86) || defined(__i386__) || defined(__i386) michael@0: #if defined(_WIN32) michael@0: // Windows uses a 64bit wide floating point stack. michael@0: #define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1 michael@0: #else michael@0: #undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS michael@0: #endif // _WIN32 michael@0: #else michael@0: #error Target architecture was not detected as supported by Double-Conversion. michael@0: #endif michael@0: michael@0: michael@0: #include michael@0: michael@0: // The following macro works on both 32 and 64-bit platforms. michael@0: // Usage: instead of writing 0x1234567890123456 michael@0: // write UINT64_2PART_C(0x12345678,90123456); michael@0: #define UINT64_2PART_C(a, b) (((static_cast(a) << 32) + 0x##b##u)) michael@0: michael@0: michael@0: // The expression ARRAY_SIZE(a) is a compile-time constant of type michael@0: // size_t which represents the number of elements of the given michael@0: // array. You should only use ARRAY_SIZE on statically allocated michael@0: // arrays. michael@0: #ifndef ARRAY_SIZE michael@0: #define ARRAY_SIZE(a) \ michael@0: ((sizeof(a) / sizeof(*(a))) / \ michael@0: static_cast(!(sizeof(a) % sizeof(*(a))))) michael@0: #endif michael@0: michael@0: // A macro to disallow the evil copy constructor and operator= functions michael@0: // This should be used in the private: declarations for a class michael@0: #ifndef DISALLOW_COPY_AND_ASSIGN michael@0: #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ michael@0: TypeName(const TypeName&); \ michael@0: void operator=(const TypeName&) michael@0: #endif michael@0: michael@0: // A macro to disallow all the implicit constructors, namely the michael@0: // default constructor, copy constructor and operator= functions. michael@0: // michael@0: // This should be used in the private: declarations for a class michael@0: // that wants to prevent anyone from instantiating it. This is michael@0: // especially useful for classes containing only static methods. michael@0: #ifndef DISALLOW_IMPLICIT_CONSTRUCTORS michael@0: #define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ michael@0: TypeName(); \ michael@0: DISALLOW_COPY_AND_ASSIGN(TypeName) michael@0: #endif michael@0: michael@0: namespace double_conversion { michael@0: michael@0: static const int kCharSize = sizeof(char); michael@0: michael@0: // Returns the maximum of the two parameters. michael@0: template michael@0: static T Max(T a, T b) { michael@0: return a < b ? b : a; michael@0: } michael@0: michael@0: michael@0: // Returns the minimum of the two parameters. michael@0: template michael@0: static T Min(T a, T b) { michael@0: return a < b ? a : b; michael@0: } michael@0: michael@0: michael@0: inline int StrLength(const char* string) { michael@0: size_t length = strlen(string); michael@0: ASSERT(length == static_cast(static_cast(length))); michael@0: return static_cast(length); michael@0: } michael@0: michael@0: // This is a simplified version of V8's Vector class. michael@0: template michael@0: class Vector { michael@0: public: michael@0: Vector() : start_(NULL), length_(0) {} michael@0: Vector(T* data, int length) : start_(data), length_(length) { michael@0: ASSERT(length == 0 || (length > 0 && data != NULL)); michael@0: } michael@0: michael@0: // Returns a vector using the same backing storage as this one, michael@0: // spanning from and including 'from', to but not including 'to'. michael@0: Vector SubVector(int from, int to) { michael@0: ASSERT(to <= length_); michael@0: ASSERT(from < to); michael@0: ASSERT(0 <= from); michael@0: return Vector(start() + from, to - from); michael@0: } michael@0: michael@0: // Returns the length of the vector. michael@0: int length() const { return length_; } michael@0: michael@0: // Returns whether or not the vector is empty. michael@0: bool is_empty() const { return length_ == 0; } michael@0: michael@0: // Returns the pointer to the start of the data in the vector. michael@0: T* start() const { return start_; } michael@0: michael@0: // Access individual vector elements - checks bounds in debug mode. michael@0: T& operator[](int index) const { michael@0: ASSERT(0 <= index && index < length_); michael@0: return start_[index]; michael@0: } michael@0: michael@0: T& first() { return start_[0]; } michael@0: michael@0: T& last() { return start_[length_ - 1]; } michael@0: michael@0: private: michael@0: T* start_; michael@0: int length_; michael@0: }; michael@0: michael@0: michael@0: // Helper class for building result strings in a character buffer. The michael@0: // purpose of the class is to use safe operations that checks the michael@0: // buffer bounds on all operations in debug mode. michael@0: class StringBuilder { michael@0: public: michael@0: StringBuilder(char* buffer, int size) michael@0: : buffer_(buffer, size), position_(0) { } michael@0: michael@0: ~StringBuilder() { if (!is_finalized()) Finalize(); } michael@0: michael@0: int size() const { return buffer_.length(); } michael@0: michael@0: // Get the current position in the builder. michael@0: int position() const { michael@0: ASSERT(!is_finalized()); michael@0: return position_; michael@0: } michael@0: michael@0: // Reset the position. michael@0: void Reset() { position_ = 0; } michael@0: michael@0: // Add a single character to the builder. It is not allowed to add michael@0: // 0-characters; use the Finalize() method to terminate the string michael@0: // instead. michael@0: void AddCharacter(char c) { michael@0: ASSERT(c != '\0'); michael@0: ASSERT(!is_finalized() && position_ < buffer_.length()); michael@0: buffer_[position_++] = c; michael@0: } michael@0: michael@0: // Add an entire string to the builder. Uses strlen() internally to michael@0: // compute the length of the input string. michael@0: void AddString(const char* s) { michael@0: AddSubstring(s, StrLength(s)); michael@0: } michael@0: michael@0: // Add the first 'n' characters of the given string 's' to the michael@0: // builder. The input string must have enough characters. michael@0: void AddSubstring(const char* s, int n) { michael@0: ASSERT(!is_finalized() && position_ + n < buffer_.length()); michael@0: ASSERT(static_cast(n) <= strlen(s)); michael@0: memmove(&buffer_[position_], s, n * kCharSize); michael@0: position_ += n; michael@0: } michael@0: michael@0: michael@0: // Add character padding to the builder. If count is non-positive, michael@0: // nothing is added to the builder. michael@0: void AddPadding(char c, int count) { michael@0: for (int i = 0; i < count; i++) { michael@0: AddCharacter(c); michael@0: } michael@0: } michael@0: michael@0: // Finalize the string by 0-terminating it and returning the buffer. michael@0: char* Finalize() { michael@0: ASSERT(!is_finalized() && position_ < buffer_.length()); michael@0: buffer_[position_] = '\0'; michael@0: // Make sure nobody managed to add a 0-character to the michael@0: // buffer while building the string. michael@0: ASSERT(strlen(buffer_.start()) == static_cast(position_)); michael@0: position_ = -1; michael@0: ASSERT(is_finalized()); michael@0: return buffer_.start(); michael@0: } michael@0: michael@0: private: michael@0: Vector buffer_; michael@0: int position_; michael@0: michael@0: bool is_finalized() const { return position_ < 0; } michael@0: michael@0: DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder); michael@0: }; michael@0: michael@0: // The type-based aliasing rule allows the compiler to assume that pointers of michael@0: // different types (for some definition of different) never alias each other. michael@0: // Thus the following code does not work: michael@0: // michael@0: // float f = foo(); michael@0: // int fbits = *(int*)(&f); michael@0: // michael@0: // The compiler 'knows' that the int pointer can't refer to f since the types michael@0: // don't match, so the compiler may cache f in a register, leaving random data michael@0: // in fbits. Using C++ style casts makes no difference, however a pointer to michael@0: // char data is assumed to alias any other pointer. This is the 'memcpy michael@0: // exception'. michael@0: // michael@0: // Bit_cast uses the memcpy exception to move the bits from a variable of one michael@0: // type of a variable of another type. Of course the end result is likely to michael@0: // be implementation dependent. Most compilers (gcc-4.2 and MSVC 2005) michael@0: // will completely optimize BitCast away. michael@0: // michael@0: // There is an additional use for BitCast. michael@0: // Recent gccs will warn when they see casts that may result in breakage due to michael@0: // the type-based aliasing rule. If you have checked that there is no breakage michael@0: // you can use BitCast to cast one pointer type to another. This confuses gcc michael@0: // enough that it can no longer see that you have cast one pointer type to michael@0: // another thus avoiding the warning. michael@0: template michael@0: inline Dest BitCast(const Source& source) { michael@0: static_assert(sizeof(Dest) == sizeof(Source), michael@0: "BitCast's source and destination types must be the same size"); michael@0: michael@0: Dest dest; michael@0: memmove(&dest, &source, sizeof(dest)); michael@0: return dest; michael@0: } michael@0: michael@0: template michael@0: inline Dest BitCast(Source* source) { michael@0: return BitCast(reinterpret_cast(source)); michael@0: } michael@0: michael@0: } // namespace double_conversion michael@0: michael@0: #endif // DOUBLE_CONVERSION_UTILS_H_