/src/capnproto/c++/src/capnp/endian.h
Line | Count | Source |
1 | | // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors |
2 | | // Licensed under the MIT License: |
3 | | // |
4 | | // Permission is hereby granted, free of charge, to any person obtaining a copy |
5 | | // of this software and associated documentation files (the "Software"), to deal |
6 | | // in the Software without restriction, including without limitation the rights |
7 | | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
8 | | // copies of the Software, and to permit persons to whom the Software is |
9 | | // furnished to do so, subject to the following conditions: |
10 | | // |
11 | | // The above copyright notice and this permission notice shall be included in |
12 | | // all copies or substantial portions of the Software. |
13 | | // |
14 | | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
17 | | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
18 | | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
19 | | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
20 | | // THE SOFTWARE. |
21 | | |
22 | | #pragma once |
23 | | |
24 | | #include "common.h" |
25 | | #include <inttypes.h> |
26 | | #include <string.h> // memcpy |
27 | | |
28 | | CAPNP_BEGIN_HEADER |
29 | | |
30 | | namespace capnp { |
31 | | namespace _ { // private |
32 | | |
33 | | // WireValue |
34 | | // |
35 | | // Wraps a primitive value as it appears on the wire. Namely, values are little-endian on the |
36 | | // wire, because little-endian is the most common endianness in modern CPUs. |
37 | | // |
38 | | // Note: In general, code that depends cares about byte ordering is bad. See: |
39 | | // http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html |
40 | | // Cap'n Proto is special because it is essentially doing compiler-like things, fussing over |
41 | | // allocation and layout of memory, in order to squeeze out every last drop of performance. |
42 | | |
43 | | #if _MSC_VER |
44 | | // Assume Windows is little-endian. |
45 | | // |
46 | | // TODO(msvc): This is ugly. Maybe refactor later checks to be based on CAPNP_BYTE_ORDER or |
47 | | // CAPNP_SWAP_BYTES or something, and define that in turn based on _MSC_VER or the GCC |
48 | | // intrinsics. |
49 | | |
50 | | #ifndef __ORDER_BIG_ENDIAN__ |
51 | | #define __ORDER_BIG_ENDIAN__ 4321 |
52 | | #endif |
53 | | #ifndef __ORDER_LITTLE_ENDIAN__ |
54 | | #define __ORDER_LITTLE_ENDIAN__ 1234 |
55 | | #endif |
56 | | #ifndef __BYTE_ORDER__ |
57 | | #define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ |
58 | | #endif |
59 | | #endif |
60 | | |
61 | | #if CAPNP_REVERSE_ENDIAN |
62 | | #define CAPNP_WIRE_BYTE_ORDER __ORDER_BIG_ENDIAN__ |
63 | | #define CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER __ORDER_LITTLE_ENDIAN__ |
64 | | #else |
65 | | #define CAPNP_WIRE_BYTE_ORDER __ORDER_LITTLE_ENDIAN__ |
66 | | #define CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER __ORDER_BIG_ENDIAN__ |
67 | | #endif |
68 | | |
69 | | #if defined(__BYTE_ORDER__) && \ |
70 | | __BYTE_ORDER__ == CAPNP_WIRE_BYTE_ORDER && \ |
71 | | !CAPNP_DISABLE_ENDIAN_DETECTION |
72 | | // CPU is little-endian. We can just read/write the memory directly. |
73 | | |
74 | | template <typename T> |
75 | | class DirectWireValue { |
76 | | public: |
77 | 594k | KJ_ALWAYS_INLINE(T get() const) { return value; }capnp::_::DirectWireValue<signed char>::get() const Line | Count | Source | 77 | 5.32k | KJ_ALWAYS_INLINE(T get() const) { return value; } |
capnp::_::DirectWireValue<short>::get() const Line | Count | Source | 77 | 5.13k | KJ_ALWAYS_INLINE(T get() const) { return value; } |
capnp::_::DirectWireValue<int>::get() const Line | Count | Source | 77 | 4.96k | KJ_ALWAYS_INLINE(T get() const) { return value; } |
capnp::_::DirectWireValue<long>::get() const Line | Count | Source | 77 | 4.44k | KJ_ALWAYS_INLINE(T get() const) { return value; } |
capnp::_::DirectWireValue<unsigned char>::get() const Line | Count | Source | 77 | 3.81k | KJ_ALWAYS_INLINE(T get() const) { return value; } |
capnp::_::DirectWireValue<unsigned short>::get() const Line | Count | Source | 77 | 143k | KJ_ALWAYS_INLINE(T get() const) { return value; } |
capnp::_::DirectWireValue<unsigned int>::get() const Line | Count | Source | 77 | 396k | KJ_ALWAYS_INLINE(T get() const) { return value; } |
capnp::_::DirectWireValue<unsigned long>::get() const Line | Count | Source | 77 | 3.28k | KJ_ALWAYS_INLINE(T get() const) { return value; } |
capnp::_::DirectWireValue<float>::get() const Line | Count | Source | 77 | 4.08k | KJ_ALWAYS_INLINE(T get() const) { return value; } |
capnp::_::DirectWireValue<double>::get() const Line | Count | Source | 77 | 3.17k | KJ_ALWAYS_INLINE(T get() const) { return value; } |
capnp::_::DirectWireValue<capnp::schemas::TestEnum_9c8e9318b29d9cd3>::get() const Line | Count | Source | 77 | 1.04k | KJ_ALWAYS_INLINE(T get() const) { return value; } |
Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestUnion::Union0::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestUnion::Union1::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestUnion::Union2::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestUnion::Union3::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestUnnamedUnion::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestUnionInUnion::Outer::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestUnionInUnion::Outer::Inner::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestGroups::Groups::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestInterleavedGroups::Group1::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestInterleavedGroups::Group2::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestLateUnion::TheUnion::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestLateUnion::AnotherUnion::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestOldUnionVersion::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestNewUnionVersion::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestNewUnionVersion::A::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestStructUnion::Un::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::RenamedStruct::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnp::schemas::RenamedEnum_f610d1deb4c9e84a>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::RenamedStruct::RenamedUnion::Which>::get() const capnp::_::DirectWireValue<capnp::schema::Node::Which>::get() const Line | Count | Source | 77 | 6.77k | KJ_ALWAYS_INLINE(T get() const) { return value; } |
Unexecuted instantiation: capnp::_::DirectWireValue<capnp::schemas::ElementSize_d1958f7dba521926>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnp::schema::Field::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnp::schema::Field::Ordinal::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnp::schema::Type::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnp::schema::Type::AnyPointer::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnp::schema::Type::AnyPointer::Unconstrained::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnp::schema::Brand::Scope::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnp::schema::Brand::Binding::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnp::schema::Value::Which>::get() const Unexecuted instantiation: capnp::_::DirectWireValue<capnp::schema::CodeGeneratorRequest::RequestedFile::FileSourceInfo::Identifier::Which>::get() const capnp::_::DirectWireValue<kj::Id<unsigned int, capnp::_::Segment> >::get() const Line | Count | Source | 77 | 12.5k | KJ_ALWAYS_INLINE(T get() const) { return value; } |
|
78 | 0 | KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; }Unexecuted instantiation: capnp::_::DirectWireValue<signed char>::set(signed char) Unexecuted instantiation: capnp::_::DirectWireValue<short>::set(short) Unexecuted instantiation: capnp::_::DirectWireValue<int>::set(int) Unexecuted instantiation: capnp::_::DirectWireValue<long>::set(long) Unexecuted instantiation: capnp::_::DirectWireValue<unsigned char>::set(unsigned char) Unexecuted instantiation: capnp::_::DirectWireValue<unsigned short>::set(unsigned short) Unexecuted instantiation: capnp::_::DirectWireValue<unsigned int>::set(unsigned int) Unexecuted instantiation: capnp::_::DirectWireValue<unsigned long>::set(unsigned long) Unexecuted instantiation: capnp::_::DirectWireValue<float>::set(float) Unexecuted instantiation: capnp::_::DirectWireValue<double>::set(double) Unexecuted instantiation: capnp::_::DirectWireValue<capnp::schemas::TestEnum_9c8e9318b29d9cd3>::set(capnp::schemas::TestEnum_9c8e9318b29d9cd3) Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestUnion::Union0::Which>::set(capnproto_test::capnp::test::TestUnion::Union0::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestUnion::Union1::Which>::set(capnproto_test::capnp::test::TestUnion::Union1::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestUnion::Union2::Which>::set(capnproto_test::capnp::test::TestUnion::Union2::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestUnion::Union3::Which>::set(capnproto_test::capnp::test::TestUnion::Union3::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestUnnamedUnion::Which>::set(capnproto_test::capnp::test::TestUnnamedUnion::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestUnionInUnion::Outer::Which>::set(capnproto_test::capnp::test::TestUnionInUnion::Outer::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestUnionInUnion::Outer::Inner::Which>::set(capnproto_test::capnp::test::TestUnionInUnion::Outer::Inner::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestGroups::Groups::Which>::set(capnproto_test::capnp::test::TestGroups::Groups::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestInterleavedGroups::Group1::Which>::set(capnproto_test::capnp::test::TestInterleavedGroups::Group1::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestInterleavedGroups::Group2::Which>::set(capnproto_test::capnp::test::TestInterleavedGroups::Group2::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestLateUnion::TheUnion::Which>::set(capnproto_test::capnp::test::TestLateUnion::TheUnion::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestLateUnion::AnotherUnion::Which>::set(capnproto_test::capnp::test::TestLateUnion::AnotherUnion::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestOldUnionVersion::Which>::set(capnproto_test::capnp::test::TestOldUnionVersion::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestNewUnionVersion::Which>::set(capnproto_test::capnp::test::TestNewUnionVersion::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestNewUnionVersion::A::Which>::set(capnproto_test::capnp::test::TestNewUnionVersion::A::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::TestStructUnion::Un::Which>::set(capnproto_test::capnp::test::TestStructUnion::Un::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::RenamedStruct::Which>::set(capnproto_test::capnp::test::RenamedStruct::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnp::schemas::RenamedEnum_f610d1deb4c9e84a>::set(capnp::schemas::RenamedEnum_f610d1deb4c9e84a) Unexecuted instantiation: capnp::_::DirectWireValue<capnproto_test::capnp::test::RenamedStruct::RenamedUnion::Which>::set(capnproto_test::capnp::test::RenamedStruct::RenamedUnion::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnp::schema::Node::Which>::set(capnp::schema::Node::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnp::schemas::ElementSize_d1958f7dba521926>::set(capnp::schemas::ElementSize_d1958f7dba521926) Unexecuted instantiation: capnp::_::DirectWireValue<capnp::schema::Field::Which>::set(capnp::schema::Field::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnp::schema::Field::Ordinal::Which>::set(capnp::schema::Field::Ordinal::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnp::schema::Type::Which>::set(capnp::schema::Type::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnp::schema::Type::AnyPointer::Which>::set(capnp::schema::Type::AnyPointer::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnp::schema::Type::AnyPointer::Unconstrained::Which>::set(capnp::schema::Type::AnyPointer::Unconstrained::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnp::schema::Brand::Scope::Which>::set(capnp::schema::Brand::Scope::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnp::schema::Brand::Binding::Which>::set(capnp::schema::Brand::Binding::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnp::schema::Value::Which>::set(capnp::schema::Value::Which) Unexecuted instantiation: capnp::_::DirectWireValue<capnp::schema::CodeGeneratorRequest::RequestedFile::FileSourceInfo::Identifier::Which>::set(capnp::schema::CodeGeneratorRequest::RequestedFile::FileSourceInfo::Identifier::Which) Unexecuted instantiation: capnp::_::DirectWireValue<kj::Id<unsigned int, capnp::_::Segment> >::set(kj::Id<unsigned int, capnp::_::Segment>) |
79 | | |
80 | | private: |
81 | | T value; |
82 | | }; |
83 | | |
84 | | template <typename T> |
85 | | using WireValue = DirectWireValue<T>; |
86 | | // To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are |
87 | | // linked together, we define each implementation with a different name and define an alias to the |
88 | | // one we want to use. |
89 | | |
90 | | #elif defined(__BYTE_ORDER__) && \ |
91 | | __BYTE_ORDER__ == CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER && \ |
92 | | defined(__GNUC__) && !CAPNP_DISABLE_ENDIAN_DETECTION |
93 | | // Big-endian, but GCC's __builtin_bswap() is available. |
94 | | |
95 | | // TODO(perf): Use dedicated instructions to read little-endian data on big-endian CPUs that have |
96 | | // them. |
97 | | |
98 | | // TODO(perf): Verify that this code optimizes reasonably. In particular, ensure that the |
99 | | // compiler optimizes away the byte copies and keeps everything in registers. |
100 | | |
101 | | template <typename T, size_t size = sizeof(T)> |
102 | | class SwappingWireValue; |
103 | | |
104 | | template <typename T> |
105 | | class SwappingWireValue<T, 1> { |
106 | | public: |
107 | | KJ_ALWAYS_INLINE(T get() const) { return value; } |
108 | | KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; } |
109 | | |
110 | | private: |
111 | | T value; |
112 | | }; |
113 | | |
114 | | template <typename T> |
115 | | class SwappingWireValue<T, 2> { |
116 | | public: |
117 | | KJ_ALWAYS_INLINE(T get() const) { |
118 | | // Not all platforms have __builtin_bswap16() for some reason. In particular, it is missing |
119 | | // on gcc-4.7.3-cygwin32 (but present on gcc-4.8.1-cygwin64). |
120 | | uint16_t swapped = (value << 8) | (value >> 8); |
121 | | T result; |
122 | | kj::asBytes(result).copyFrom(kj::asBytes(swapped)); |
123 | | return result; |
124 | | } |
125 | | KJ_ALWAYS_INLINE(void set(T newValue)) { |
126 | | uint16_t raw; |
127 | | kj::asBytes(raw).copyFrom(kj::asBytes(newValue)); |
128 | | // Not all platforms have __builtin_bswap16() for some reason. In particular, it is missing |
129 | | // on gcc-4.7.3-cygwin32 (but present on gcc-4.8.1-cygwin64). |
130 | | value = (raw << 8) | (raw >> 8); |
131 | | } |
132 | | |
133 | | private: |
134 | | uint16_t value; |
135 | | }; |
136 | | |
137 | | template <typename T> |
138 | | class SwappingWireValue<T, 4> { |
139 | | public: |
140 | | KJ_ALWAYS_INLINE(T get() const) { |
141 | | uint32_t swapped = __builtin_bswap32(value); |
142 | | T result; |
143 | | kj::asBytes(result).copyFrom(kj::asBytes(swapped)); |
144 | | return result; |
145 | | } |
146 | | KJ_ALWAYS_INLINE(void set(T newValue)) { |
147 | | uint32_t raw; |
148 | | kj::asBytes(raw).copyFrom(kj::asBytes(newValue)); |
149 | | value = __builtin_bswap32(raw); |
150 | | } |
151 | | |
152 | | private: |
153 | | uint32_t value; |
154 | | }; |
155 | | |
156 | | template <typename T> |
157 | | class SwappingWireValue<T, 8> { |
158 | | public: |
159 | | KJ_ALWAYS_INLINE(T get() const) { |
160 | | uint64_t swapped = __builtin_bswap64(value); |
161 | | T result; |
162 | | kj::asBytes(result).copyFrom(kj::asBytes(swapped)); |
163 | | return result; |
164 | | } |
165 | | KJ_ALWAYS_INLINE(void set(T newValue)) { |
166 | | uint64_t raw; |
167 | | kj::asBytes(raw).copyFrom(kj::asBytes(newValue)); |
168 | | value = __builtin_bswap64(raw); |
169 | | } |
170 | | |
171 | | private: |
172 | | uint64_t value; |
173 | | }; |
174 | | |
175 | | template <typename T> |
176 | | using WireValue = SwappingWireValue<T>; |
177 | | // To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are |
178 | | // linked together, we define each implementation with a different name and define an alias to the |
179 | | // one we want to use. |
180 | | |
181 | | #else |
182 | | // Unknown endianness. Fall back to bit shifts. |
183 | | |
184 | | #if !CAPNP_DISABLE_ENDIAN_DETECTION |
185 | | #if _MSC_VER |
186 | | #pragma message("Couldn't detect endianness of your platform. Using unoptimized fallback implementation.") |
187 | | #pragma message("Consider changing this code to detect your platform and send us a patch!") |
188 | | #else |
189 | | #warning "Couldn't detect endianness of your platform. Using unoptimized fallback implementation." |
190 | | #warning "Consider changing this code to detect your platform and send us a patch!" |
191 | | #endif |
192 | | #endif // !CAPNP_DISABLE_ENDIAN_DETECTION |
193 | | |
194 | | template <typename T, size_t size = sizeof(T)> |
195 | | class ShiftingWireValue; |
196 | | |
197 | | template <typename T> |
198 | | class ShiftingWireValue<T, 1> { |
199 | | public: |
200 | | KJ_ALWAYS_INLINE(T get() const) { return value; } |
201 | | KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; } |
202 | | |
203 | | private: |
204 | | T value; |
205 | | }; |
206 | | |
207 | | template <typename T> |
208 | | class ShiftingWireValue<T, 2> { |
209 | | public: |
210 | | KJ_ALWAYS_INLINE(T get() const) { |
211 | | uint16_t raw = (static_cast<uint16_t>(bytes[0]) ) | |
212 | | (static_cast<uint16_t>(bytes[1]) << 8); |
213 | | T result; |
214 | | kj::asBytes(result).copyFrom(kj::asBytes(raw)); |
215 | | return result; |
216 | | } |
217 | | KJ_ALWAYS_INLINE(void set(T newValue)) { |
218 | | uint16_t raw; |
219 | | kj::asBytes(raw).copyFrom(kj::asBytes(newValue)); |
220 | | bytes[0] = raw; |
221 | | bytes[1] = raw >> 8; |
222 | | } |
223 | | |
224 | | private: |
225 | | union { |
226 | | byte bytes[2]; |
227 | | uint16_t align; |
228 | | }; |
229 | | }; |
230 | | |
231 | | template <typename T> |
232 | | class ShiftingWireValue<T, 4> { |
233 | | public: |
234 | | KJ_ALWAYS_INLINE(T get() const) { |
235 | | uint32_t raw = (static_cast<uint32_t>(bytes[0]) ) | |
236 | | (static_cast<uint32_t>(bytes[1]) << 8) | |
237 | | (static_cast<uint32_t>(bytes[2]) << 16) | |
238 | | (static_cast<uint32_t>(bytes[3]) << 24); |
239 | | T result; |
240 | | kj::asBytes(result).copyFrom(kj::asBytes(raw)); |
241 | | return result; |
242 | | } |
243 | | KJ_ALWAYS_INLINE(void set(T newValue)) { |
244 | | uint32_t raw; |
245 | | kj::asBytes(raw).copyFrom(kj::asBytes(newValue)); |
246 | | bytes[0] = raw; |
247 | | bytes[1] = raw >> 8; |
248 | | bytes[2] = raw >> 16; |
249 | | bytes[3] = raw >> 24; |
250 | | } |
251 | | |
252 | | private: |
253 | | union { |
254 | | byte bytes[4]; |
255 | | uint32_t align; |
256 | | }; |
257 | | }; |
258 | | |
259 | | template <typename T> |
260 | | class ShiftingWireValue<T, 8> { |
261 | | public: |
262 | | KJ_ALWAYS_INLINE(T get() const) { |
263 | | uint64_t raw = (static_cast<uint64_t>(bytes[0]) ) | |
264 | | (static_cast<uint64_t>(bytes[1]) << 8) | |
265 | | (static_cast<uint64_t>(bytes[2]) << 16) | |
266 | | (static_cast<uint64_t>(bytes[3]) << 24) | |
267 | | (static_cast<uint64_t>(bytes[4]) << 32) | |
268 | | (static_cast<uint64_t>(bytes[5]) << 40) | |
269 | | (static_cast<uint64_t>(bytes[6]) << 48) | |
270 | | (static_cast<uint64_t>(bytes[7]) << 56); |
271 | | T result; |
272 | | kj::asBytes(result).copyFrom(kj::asBytes(raw)); |
273 | | return result; |
274 | | } |
275 | | KJ_ALWAYS_INLINE(void set(T newValue)) { |
276 | | uint64_t raw; |
277 | | kj::asBytes(raw).copyFrom(kj::asBytes(newValue)); |
278 | | bytes[0] = raw; |
279 | | bytes[1] = raw >> 8; |
280 | | bytes[2] = raw >> 16; |
281 | | bytes[3] = raw >> 24; |
282 | | bytes[4] = raw >> 32; |
283 | | bytes[5] = raw >> 40; |
284 | | bytes[6] = raw >> 48; |
285 | | bytes[7] = raw >> 56; |
286 | | } |
287 | | |
288 | | private: |
289 | | union { |
290 | | byte bytes[8]; |
291 | | uint64_t align; |
292 | | }; |
293 | | }; |
294 | | |
295 | | template <typename T> |
296 | | using WireValue = ShiftingWireValue<T>; |
297 | | // To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are |
298 | | // linked together, we define each implementation with a different name and define an alias to the |
299 | | // one we want to use. |
300 | | |
301 | | #endif |
302 | | |
303 | | } // namespace _ (private) |
304 | | } // namespace capnp |
305 | | |
306 | | CAPNP_END_HEADER |