mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Bug 888573 - Remove bit_cast; r=Waldo
This commit is contained in:
parent
343818a218
commit
dd8f07a495
@ -236,72 +236,6 @@ enum Ownership {
|
||||
TAKE_OWNERSHIP
|
||||
};
|
||||
|
||||
// bit_cast<Dest,Source> is a template function that implements the
|
||||
// equivalent of "*reinterpret_cast<Dest*>(&source)". We need this in
|
||||
// very low-level functions like the protobuf library and fast math
|
||||
// support.
|
||||
//
|
||||
// float f = 3.14159265358979;
|
||||
// int i = bit_cast<int32_t>(f);
|
||||
// // i = 0x40490fdb
|
||||
//
|
||||
// The classical address-casting method is:
|
||||
//
|
||||
// // WRONG
|
||||
// float f = 3.14159265358979; // WRONG
|
||||
// int i = * reinterpret_cast<int*>(&f); // WRONG
|
||||
//
|
||||
// The address-casting method actually produces undefined behavior
|
||||
// according to ISO C++ specification section 3.10 -15 -. Roughly, this
|
||||
// section says: if an object in memory has one type, and a program
|
||||
// accesses it with a different type, then the result is undefined
|
||||
// behavior for most values of "different type".
|
||||
//
|
||||
// This is true for any cast syntax, either *(int*)&f or
|
||||
// *reinterpret_cast<int*>(&f). And it is particularly true for
|
||||
// conversions betweeen integral lvalues and floating-point lvalues.
|
||||
//
|
||||
// The purpose of 3.10 -15- is to allow optimizing compilers to assume
|
||||
// that expressions with different types refer to different memory. gcc
|
||||
// 4.0.1 has an optimizer that takes advantage of this. So a
|
||||
// non-conforming program quietly produces wildly incorrect output.
|
||||
//
|
||||
// The problem is not the use of reinterpret_cast. The problem is type
|
||||
// punning: holding an object in memory of one type and reading its bits
|
||||
// back using a different type.
|
||||
//
|
||||
// The C++ standard is more subtle and complex than this, but that
|
||||
// is the basic idea.
|
||||
//
|
||||
// Anyways ...
|
||||
//
|
||||
// bit_cast<> calls memcpy() which is blessed by the standard,
|
||||
// especially by the example in section 3.9 . Also, of course,
|
||||
// bit_cast<> wraps up the nasty logic in one place.
|
||||
//
|
||||
// Fortunately memcpy() is very fast. In optimized mode, with a
|
||||
// constant size, gcc 2.95.3, gcc 4.0.1, and msvc 7.1 produce inline
|
||||
// code with the minimal amount of data movement. On a 32-bit system,
|
||||
// memcpy(d,s,4) compiles to one load and one store, and memcpy(d,s,8)
|
||||
// compiles to two loads and two stores.
|
||||
//
|
||||
// I tested this code with gcc 2.95.3, gcc 4.0.1, icc 8.1, and msvc 7.1.
|
||||
//
|
||||
// WARNING: if Dest or Source is a non-POD type, the result of the memcpy
|
||||
// is likely to surprise you.
|
||||
|
||||
template <class Dest, class Source>
|
||||
inline Dest bit_cast(const Source& source) {
|
||||
// Compile time assertion: sizeof(Dest) == sizeof(Source)
|
||||
// A compile error here means your Dest and Source have different sizes.
|
||||
MOZ_STATIC_ASSERT(sizeof(Dest) == sizeof(Source),
|
||||
"Only bit-cast between identically-sized types!");
|
||||
|
||||
Dest dest;
|
||||
memcpy(&dest, &source, sizeof(dest));
|
||||
return dest;
|
||||
}
|
||||
|
||||
// The following enum should be used only as a constructor argument to indicate
|
||||
// that the variable has static storage class, and that the constructor should
|
||||
// do nothing to its state. It indicates to the reader that it is legal to
|
||||
|
@ -46,29 +46,31 @@
|
||||
#include "base/cpu.h"
|
||||
#include "base/singleton.h"
|
||||
#include "base/system_monitor.h"
|
||||
#include "mozilla/Casting.h"
|
||||
|
||||
using base::Time;
|
||||
using base::TimeDelta;
|
||||
using base::TimeTicks;
|
||||
using mozilla::BitwiseCast;
|
||||
|
||||
namespace {
|
||||
|
||||
// From MSDN, FILETIME "Contains a 64-bit value representing the number of
|
||||
// 100-nanosecond intervals since January 1, 1601 (UTC)."
|
||||
int64_t FileTimeToMicroseconds(const FILETIME& ft) {
|
||||
// Need to bit_cast to fix alignment, then divide by 10 to convert
|
||||
// Need to BitwiseCast to fix alignment, then divide by 10 to convert
|
||||
// 100-nanoseconds to milliseconds. This only works on little-endian
|
||||
// machines.
|
||||
return bit_cast<int64_t, FILETIME>(ft) / 10;
|
||||
return BitwiseCast<int64_t>(ft) / 10;
|
||||
}
|
||||
|
||||
void MicrosecondsToFileTime(int64_t us, FILETIME* ft) {
|
||||
DCHECK(us >= 0) << "Time is less than 0, negative values are not "
|
||||
"representable in FILETIME";
|
||||
|
||||
// Multiply by 10 to convert milliseconds to 100-nanoseconds. Bit_cast will
|
||||
// Multiply by 10 to convert milliseconds to 100-nanoseconds. BitwiseCast will
|
||||
// handle alignment problems. This only works on little-endian machines.
|
||||
*ft = bit_cast<FILETIME, int64_t>(us * 10);
|
||||
*ft = BitwiseCast<FILETIME>(us * 10);
|
||||
}
|
||||
|
||||
int64_t CurrentWallclockMicroseconds() {
|
||||
|
Loading…
Reference in New Issue
Block a user