1 // Copyright (c) 2018, ETH Zurich and UNC Chapel Hill.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 //     * Redistributions of source code must retain the above copyright
8 //       notice, this list of conditions and the following disclaimer.
9 //
10 //     * Redistributions in binary form must reproduce the above copyright
11 //       notice, this list of conditions and the following disclaimer in the
12 //       documentation and/or other materials provided with the distribution.
13 //
14 //     * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
15 //       its contributors may be used to endorse or promote products derived
16 //       from this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 // POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
31 
32 #ifndef COLMAP_SRC_UTIL_ENDIAN_H_
33 #define COLMAP_SRC_UTIL_ENDIAN_H_
34 
35 #include <algorithm>
36 
37 namespace colmap {
38 
39 // Reverse the order of each byte.
40 template <typename T>
41 T ReverseBytes(const T& data);
42 
43 // Check the order in which bytes are stored in computer memory.
44 bool IsLittleEndian();
45 bool IsBigEndian();
46 
47 // Convert data between endianness and the native format. Note that, for float
48 // and double types, these functions are only valid if the format is IEEE-754.
49 // This is the case for pretty much most processors.
50 template <typename T>
51 T LittleEndianToNative(const T x);
52 template <typename T>
53 T BigEndianToNative(const T x);
54 template <typename T>
55 T NativeToLittleEndian(const T x);
56 template <typename T>
57 T NativeToBigEndian(const T x);
58 
59 // Read data in little endian format for cross-platform support.
60 template <typename T>
61 T ReadBinaryLittleEndian(std::istream* stream);
62 template <typename T>
63 void ReadBinaryLittleEndian(std::istream* stream, std::vector<T>* data);
64 
65 // Write data in little endian format for cross-platform support.
66 template <typename T>
67 void WriteBinaryLittleEndian(std::ostream* stream, const T& data);
68 template <typename T>
69 void WriteBinaryLittleEndian(std::ostream* stream, const std::vector<T>& data);
70 
71 ////////////////////////////////////////////////////////////////////////////////
72 // Implementation
73 ////////////////////////////////////////////////////////////////////////////////
74 
75 template <typename T>
ReverseBytes(const T & data)76 T ReverseBytes(const T& data) {
77   T data_reversed = data;
78   std::reverse(reinterpret_cast<char*>(&data_reversed),
79                reinterpret_cast<char*>(&data_reversed) + sizeof(T));
80   return data_reversed;
81 }
82 
IsLittleEndian()83 inline bool IsLittleEndian() {
84 #ifdef BOOST_BIG_ENDIAN
85   return false;
86 #else
87   return true;
88 #endif
89 }
90 
IsBigEndian()91 inline bool IsBigEndian() {
92 #ifdef BOOST_BIG_ENDIAN
93   return true;
94 #else
95   return false;
96 #endif
97 }
98 
99 template <typename T>
LittleEndianToNative(const T x)100 T LittleEndianToNative(const T x) {
101   if (IsLittleEndian()) {
102     return x;
103   } else {
104     return ReverseBytes(x);
105   }
106 }
107 
108 template <typename T>
BigEndianToNative(const T x)109 T BigEndianToNative(const T x) {
110   if (IsBigEndian()) {
111     return x;
112   } else {
113     return ReverseBytes(x);
114   }
115 }
116 
117 template <typename T>
NativeToLittleEndian(const T x)118 T NativeToLittleEndian(const T x) {
119   if (IsLittleEndian()) {
120     return x;
121   } else {
122     return ReverseBytes(x);
123   }
124 }
125 
126 template <typename T>
NativeToBigEndian(const T x)127 T NativeToBigEndian(const T x) {
128   if (IsBigEndian()) {
129     return x;
130   } else {
131     return ReverseBytes(x);
132   }
133 }
134 
135 template <typename T>
ReadBinaryLittleEndian(std::istream * stream)136 T ReadBinaryLittleEndian(std::istream* stream) {
137   T data_little_endian;
138   stream->read(reinterpret_cast<char*>(&data_little_endian), sizeof(T));
139   return LittleEndianToNative(data_little_endian);
140 }
141 
142 template <typename T>
ReadBinaryLittleEndian(std::istream * stream,std::vector<T> * data)143 void ReadBinaryLittleEndian(std::istream* stream, std::vector<T>* data) {
144   for (size_t i = 0; i < data->size(); ++i) {
145     (*data)[i] = ReadBinaryLittleEndian<T>(stream);
146   }
147 }
148 
149 template <typename T>
WriteBinaryLittleEndian(std::ostream * stream,const T & data)150 void WriteBinaryLittleEndian(std::ostream* stream, const T& data) {
151   const T data_little_endian = NativeToLittleEndian(data);
152   stream->write(reinterpret_cast<const char*>(&data_little_endian), sizeof(T));
153 }
154 
155 template <typename T>
WriteBinaryLittleEndian(std::ostream * stream,const std::vector<T> & data)156 void WriteBinaryLittleEndian(std::ostream* stream, const std::vector<T>& data) {
157   for (const auto& elem : data) {
158     WriteBinaryLittleEndian<T>(stream, elem);
159   }
160 }
161 
162 }  // namespace colmap
163 
164 #endif  // COLMAP_SRC_UTIL_ENDIAN_H_
165