Home | History | Annotate | Download | only in core
      1 /* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
      2 
      3 Licensed under the Apache License, Version 2.0 (the "License");
      4 you may not use this file except in compliance with the License.
      5 You may obtain a copy of the License at
      6 
      7     http://www.apache.org/licenses/LICENSE-2.0
      8 
      9 Unless required by applicable law or agreed to in writing, software
     10 distributed under the License is distributed on an "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 See the License for the specific language governing permissions and
     13 limitations under the License.
     14 ==============================================================================*/
     15 
     16 // Various Google-specific casting templates.
     17 //
     18 // This code is compiled directly on many platforms, including client
     19 // platforms like Windows, Mac, and embedded systems.  Before making
     20 // any changes here, make sure that you're not breaking any platforms.
     21 //
     22 
     23 #ifndef TENSORFLOW_LIB_CORE_CASTS_H_
     24 #define TENSORFLOW_LIB_CORE_CASTS_H_
     25 
     26 #include <string.h>  // for memcpy
     27 
     28 namespace tensorflow {
     29 
     30 // bit_cast<Dest,Source> is a template function that implements the
     31 // equivalent of "*reinterpret_cast<Dest*>(&source)".  We need this in
     32 // very low-level functions like the protobuf library and fast math
     33 // support.
     34 //
     35 //   float f = 3.14159265358979;
     36 //   int i = bit_cast<int32>(f);
     37 //   // i = 0x40490fdb
     38 //
     39 // The classical address-casting method is:
     40 //
     41 //   // WRONG
     42 //   float f = 3.14159265358979;            // WRONG
     43 //   int i = * reinterpret_cast<int*>(&f);  // WRONG
     44 //
     45 // The address-casting method actually produces undefined behavior
     46 // according to ISO C++ specification section 3.10 -15 -.  Roughly, this
     47 // section says: if an object in memory has one type, and a program
     48 // accesses it with a different type, then the result is undefined
     49 // behavior for most values of "different type".
     50 //
     51 // This is true for any cast syntax, either *(int*)&f or
     52 // *reinterpret_cast<int*>(&f).  And it is particularly true for
     53 // conversions between integral lvalues and floating-point lvalues.
     54 //
     55 // The purpose of 3.10 -15- is to allow optimizing compilers to assume
     56 // that expressions with different types refer to different memory.  gcc
     57 // 4.0.1 has an optimizer that takes advantage of this.  So a
     58 // non-conforming program quietly produces wildly incorrect output.
     59 //
     60 // The problem is not the use of reinterpret_cast.  The problem is type
     61 // punning: holding an object in memory of one type and reading its bits
     62 // back using a different type.
     63 //
     64 // The C++ standard is more subtle and complex than this, but that
     65 // is the basic idea.
     66 //
     67 // Anyways ...
     68 //
     69 // bit_cast<> calls memcpy() which is blessed by the standard,
     70 // especially by the example in section 3.9 .  Also, of course,
     71 // bit_cast<> wraps up the nasty logic in one place.
     72 //
     73 // Fortunately memcpy() is very fast.  In optimized mode, with a
     74 // constant size, gcc 2.95.3, gcc 4.0.1, and msvc 7.1 produce inline
     75 // code with the minimal amount of data movement.  On a 32-bit system,
     76 // memcpy(d,s,4) compiles to one load and one store, and memcpy(d,s,8)
     77 // compiles to two loads and two stores.
     78 //
     79 // I tested this code with gcc 2.95.3, gcc 4.0.1, icc 8.1, and msvc 7.1.
     80 //
     81 // WARNING: if Dest or Source is a non-POD type, the result of the memcpy
     82 // is likely to surprise you.
     83 //
     84 // Props to Bill Gibbons for the compile time assertion technique and
     85 // Art Komninos and Igor Tandetnik for the msvc experiments.
     86 //
     87 // -- mec 2005-10-17
     88 
     89 template <class Dest, class Source>
     90 inline Dest bit_cast(const Source& source) {
     91   static_assert(sizeof(Dest) == sizeof(Source), "Sizes do not match");
     92 
     93   Dest dest;
     94   memcpy(&dest, &source, sizeof(dest));
     95   return dest;
     96 }
     97 
     98 }  // namespace tensorflow
     99 
    100 #endif  // TENSORFLOW_LIB_CORE_CASTS_H_
    101