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