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