Vanetza
 
Loading...
Searching...
No Matches
byte_order.hpp
1#ifndef BYTE_ORDER_HPP_LPUJ094I
2#define BYTE_ORDER_HPP_LPUJ094I
3
4#include <cstdint>
5#include <functional>
6#include <iosfwd>
7#include <type_traits>
8#include <boost/endian/conversion.hpp>
9
10namespace vanetza
11{
12
13template<class T>
14T hton(T host_value)
15{
16 return boost::endian::native_to_big(host_value);
17}
18
19template<class T>
20T ntoh(T network_value)
21{
22 return boost::endian::big_to_native(network_value);
23}
24
25
26enum class ByteOrder {
27 BigEndian,
28 LittleEndian
29};
30
31
32namespace detail
33{
34
35#if BYTE_ORDER == LITTLE_ENDIAN
36 static constexpr ByteOrder host_byte_order = ByteOrder::LittleEndian;
37#elif BYTE_ORDER == BIG_ENDIAN
38 static constexpr ByteOrder host_byte_order = ByteOrder::BigEndian;
39#else
40# error "Unknown byte order"
41#endif
42
43} // namespace detail
44
45constexpr ByteOrder getHostByteOrder() { return detail::host_byte_order; }
46
47template<typename T, ByteOrder ORDER = getHostByteOrder()>
48class EndianType;
49
50/**
51 * Explicitly forge a plain type to an EndianType.
52 * It is assumed the passed value is already in the stated byte order,
53 * i.e. endian_cast does _not_ trigger any automatic conversions.
54 * \param value A plain value in byte order ORDER
55 * \return EndianType capable to carry value type
56 */
57template<ByteOrder ORDER, typename T>
58EndianType<T, ORDER> endian_cast(T value)
59{
60 return static_cast< EndianType<T, ORDER> >(value);
61}
62
63/**
64 * Cast POD type to EndianType in host byte order
65 * \param value POD in host byte order
66 * \return EndianType carrying value
67 */
68template<typename T>
69EndianType<T, getHostByteOrder()> host_cast(T value)
70{
71 return endian_cast<getHostByteOrder()>(value);
72}
73
74/**
75 * Cast POD type to EndianType in network byte order
76 * \param value POD in network byte order
77 * \return EndianType carrying value
78 */
79template<typename T>
80EndianType<T, ByteOrder::BigEndian> network_cast(T value)
81{
82 return endian_cast<ByteOrder::BigEndian>(value);
83}
84
85
86namespace detail
87{
88
89template<typename T, ByteOrder FROM, ByteOrder TO>
91{
92 T operator()(const T&) const;
93};
94
95template<typename T, ByteOrder ORDER>
96struct EndianConverter<T, ORDER, ORDER>
97{
98 T operator()(const T& t) const { return t; }
99};
100
101template<typename T>
102struct EndianConverter<T, ByteOrder::LittleEndian, ByteOrder::BigEndian>
103{
104 T operator()(const T& t) const { return boost::endian::endian_reverse(t); }
105};
106
107template<typename T>
108struct EndianConverter<T, ByteOrder::BigEndian, ByteOrder::LittleEndian>
109{
110 T operator()(const T& t) const { return boost::endian::endian_reverse(t); }
111};
112
113template<typename T, ByteOrder FROM, ByteOrder TO>
114T convert_endian(const T& t)
115{
117 return converter(t);
118}
119
120} // namespace detail
121
122
123template<typename T, ByteOrder ORDER>
125{
126public:
127 static_assert(std::is_pod<T>::value == true, "EndianType is only availabe for POD types");
128 typedef T value_type;
129 typedef EndianType<T, getHostByteOrder()> host_type;
131
132 EndianType() = default;
133 explicit EndianType(T value) { m_value = value; }
134
135 EndianType(const EndianType&) = default;
136 EndianType& operator=(const EndianType&) = default;
137
138 template<ByteOrder OTHER_ORDER>
140 m_value(detail::convert_endian<T, OTHER_ORDER, ORDER>(other.m_value))
141 {
142 }
143
144 template<ByteOrder OTHER_ORDER>
145 EndianType& operator=(const EndianType<T, OTHER_ORDER>& other)
146 {
147 m_value = detail::convert_endian<T, OTHER_ORDER, ORDER>(other.m_value);
148 return *this;
149 }
150
151 bool operator==(const EndianType& other) const
152 {
153 return m_value == other.m_value;
154 }
155
156 bool operator!=(const EndianType& other) const
157 {
158 return !(*this == other);
159 }
160
161 bool operator<(const EndianType& other) const
162 {
163 return m_value < other.m_value;
164 }
165
166 value_type net() const
167 {
168 return detail::convert_endian<T, ORDER, ByteOrder::BigEndian>(m_value);
169 }
170
171 value_type host() const
172 {
173 return detail::convert_endian<T, ORDER, getHostByteOrder()>(m_value);
174 }
175
176 value_type get() const
177 {
178 return m_value;
179 }
180
181private:
182 friend class EndianType<T, ByteOrder::BigEndian>;
183 friend class EndianType<T, ByteOrder::LittleEndian>;
184
185 T m_value;
186};
187
188
189/**
190 * Print to ostream in network byte order
191 * \param os output stream
192 * \param t endian type object
193 * \return os
194 */
195template<typename T, ByteOrder ORDER>
196std::ostream& operator<<(std::ostream& os, const EndianType<T, ORDER>& t)
197{
198 os << t.net();
199 return os;
200}
201
202typedef EndianType<uint8_t, ByteOrder::BigEndian> uint8be_t;
203typedef EndianType<uint16_t, ByteOrder::BigEndian> uint16be_t;
204typedef EndianType<uint32_t, ByteOrder::BigEndian> uint32be_t;
205typedef EndianType<uint64_t, ByteOrder::BigEndian> uint64be_t;
206
207typedef EndianType<int8_t, ByteOrder::BigEndian> int8be_t;
208typedef EndianType<int16_t, ByteOrder::BigEndian> int16be_t;
209typedef EndianType<int32_t, ByteOrder::BigEndian> int32be_t;
210typedef EndianType<int64_t, ByteOrder::BigEndian> int64be_t;
211
212} // namespace vanetza
213
214namespace std
215{
216
217template<typename T, vanetza::ByteOrder ORDER>
218struct hash<vanetza::EndianType<T, ORDER>>
219{
220 size_t operator()(const vanetza::EndianType<T, ORDER>& t) const
221 {
222 return hash<T>()(t.get());
223 }
224};
225
226} // namespace std
227
228#endif /* BYTE_ORDER_HPP_LPUJ094I */
229