11 #include <hilti/rt/extension-points.h> 12 #include <hilti/rt/result.h> 13 #include <hilti/rt/safe-int.h> 14 #include <hilti/rt/types/bytes.h> 15 #include <hilti/rt/unpack.h> 16 #include <hilti/rt/util.h> 20 namespace detail::adl {
21 inline std::string
to_string(hilti::rt::integer::safe<uint64_t> x, adl::tag ) {
22 return fmt(
"%" PRIu64, *x.Ptr());
25 inline std::string
to_string(hilti::rt::integer::safe<int64_t> x, adl::tag ) {
26 return fmt(
"%" PRId64, *x.Ptr());
29 inline std::string
to_string(hilti::rt::integer::safe<uint32_t> x, adl::tag ) {
30 return fmt(
"%" PRIu32, *x.Ptr());
33 inline std::string
to_string(hilti::rt::integer::safe<int32_t> x, adl::tag ) {
34 return fmt(
"%" PRId32, *x.Ptr());
37 inline std::string
to_string(hilti::rt::integer::safe<uint16_t> x, adl::tag ) {
38 return fmt(
"%" PRIu16, *x.Ptr());
41 inline std::string
to_string(hilti::rt::integer::safe<int16_t> x, adl::tag ) {
42 return fmt(
"%" PRId16, *x.Ptr());
45 inline std::string
to_string(hilti::rt::integer::safe<uint8_t> x, adl::tag ) {
46 return fmt(
"%" PRIu8, *x.Ptr());
49 inline std::string
to_string(hilti::rt::integer::safe<int8_t> x, adl::tag ) {
50 return fmt(
"%" PRId8, *x.Ptr());
53 inline std::string
to_string(hilti::rt::integer::safe<char> x, adl::tag ) {
return fmt(
"%" PRId8, *x.Ptr()); }
55 inline std::string
to_string(uint64_t x, adl::tag ) {
return fmt(
"%" PRIu64, x); }
57 inline std::string
to_string(int64_t x, adl::tag ) {
return fmt(
"%" PRId64, x); }
59 inline std::string
to_string(uint32_t x, adl::tag ) {
return fmt(
"%" PRIu32, x); }
61 inline std::string
to_string(int32_t x, adl::tag ) {
return fmt(
"%" PRId32, x); }
63 inline std::string
to_string(uint16_t x, adl::tag ) {
return fmt(
"%" PRIu16, x); }
65 inline std::string
to_string(int16_t x, adl::tag ) {
return fmt(
"%" PRId16, x); }
67 inline std::string
to_string(uint8_t x, adl::tag ) {
return fmt(
"%" PRIu8, x); }
69 inline std::string
to_string(int8_t x, adl::tag ) {
return fmt(
"%" PRId8, x); }
76 template<
typename T,
typename D>
77 inline void pack(D x, uint8_t* dst, std::initializer_list<int> bytes) {
78 for (
auto i : bytes ) {
79 dst[
sizeof(x) - i - 1] = (x & 0xff);
84 template<
typename T,
typename D>
85 inline Result<std::tuple<integer::safe<T>, D>> unpack(D b,
const uint8_t* dst, std::initializer_list<int> bytes) {
87 for (
auto i : bytes ) {
89 x |= (
static_cast<T
>(dst[i]));
92 return std::make_tuple(
static_cast<integer::safe<T>
>(x), std::move(b));
98 inline Bytes pack(integer::safe<T> i, ByteOrder
fmt) {
99 if ( fmt == ByteOrder::Host )
102 uint8_t raw[
sizeof(T)];
104 switch ( fmt.value() ) {
106 case ByteOrder::Network:
107 if constexpr ( std::is_same_v<T, uint8_t> )
109 else if constexpr ( std::is_same_v<T, int8_t> )
110 raw[0] =
static_cast<uint8_t
>(i);
111 else if constexpr ( std::is_same_v<T, uint16_t> || std::is_same_v<T, int16_t> )
112 detail::pack<T>(i, raw, {0, 1});
113 else if constexpr ( std::is_same_v<T, uint32_t> || std::is_same_v<T, int32_t> )
114 detail::pack<T>(i, raw, {0, 1, 2, 3});
115 else if constexpr ( std::is_same_v<T, uint64_t> || std::is_same_v<T, int64_t> )
116 detail::pack<T>(i, raw, {0, 1, 2, 3, 4, 5, 6, 7});
122 case ByteOrder::Little:
123 if constexpr ( std::is_same_v<T, uint8_t> )
126 else if constexpr ( std::is_same_v<T, int8_t> )
127 raw[0] =
static_cast<uint8_t
>(i);
129 else if constexpr ( std::is_same_v<T, uint16_t> || std::is_same_v<T, int16_t> )
130 detail::pack<T>(i, raw, {1, 0});
132 else if constexpr ( std::is_same_v<T, uint32_t> || std::is_same_v<T, int32_t> )
133 detail::pack<T>(i, raw, {3, 2, 1, 0});
135 else if constexpr ( std::is_same_v<T, uint64_t> || std::is_same_v<T, int64_t> )
136 detail::pack<T>(i, raw, {7, 6, 5, 4, 3, 2, 1, 0});
142 case ByteOrder::Host:
146 case ByteOrder::Undef:
throw RuntimeError(
"attempt to pack value with undefined byte order");
149 return Bytes(reinterpret_cast<Bytes::Base::value_type*>(raw),
sizeof(raw));
152 template<
typename T,
typename D>
153 inline Result<std::tuple<integer::safe<T>, D>> unpack(D b, ByteOrder fmt) {
154 if ( fmt == ByteOrder::Host )
157 if ( b.size() <
static_cast<int64_t
>(
sizeof(T)) )
158 return result::Error(
"insufficient data to unpack integer");
160 uint8_t raw[
sizeof(T)];
161 b = b.extract(raw,
sizeof(raw));
163 switch ( fmt.value() ) {
165 case ByteOrder::Network:
166 if constexpr ( std::is_same<T, uint8_t>::value )
167 return std::make_tuple(
static_cast<integer::safe<uint8_t>
>(raw[0]), std::move(b));
169 if constexpr ( std::is_same<T, int8_t>::value ) {
170 auto x =
static_cast<int8_t
>(raw[0]);
171 return std::make_tuple(
static_cast<integer::safe<int8_t>
>(x), std::move(b));
174 if constexpr ( std::is_same<T, uint16_t>::value || std::is_same<T, int16_t>::value )
175 return detail::unpack<T>(std::move(b), raw, {0, 1});
177 if constexpr ( std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value )
178 return detail::unpack<T>(std::move(b), raw, {0, 1, 2, 3});
180 if constexpr ( std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value )
181 return detail::unpack<T>(std::move(b), raw, {0, 1, 2, 3, 4, 5, 6, 7});
185 case ByteOrder::Little:
186 if constexpr ( std::is_same<T, uint8_t>::value )
187 return std::make_tuple(
static_cast<integer::safe<uint8_t>
>(raw[0]), std::move(b));
189 if constexpr ( std::is_same<T, int8_t>::value ) {
190 auto x =
static_cast<int8_t
>(raw[0]);
191 return std::make_tuple(
static_cast<integer::safe<int8_t>
>(x), std::move(b));
194 if constexpr ( std::is_same<T, uint16_t>::value || std::is_same<T, int16_t>::value )
195 return detail::unpack<T>(std::move(b), raw, {1, 0});
197 if constexpr ( std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value )
198 return detail::unpack<T>(std::move(b), raw, {3, 2, 1, 0});
200 if constexpr ( std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value )
201 return detail::unpack<T>(std::move(b), raw, {7, 6, 5, 4, 3, 2, 1, 0});
205 case ByteOrder::Host:
209 case ByteOrder::Undef:
return result::Error(
"undefined byte order");
220 extern uint64_t hton64(uint64_t v);
227 extern uint32_t hton32(uint32_t v);
234 extern uint16_t hton16(uint16_t v);
241 extern uint64_t ntoh64(uint64_t v);
248 extern uint32_t ntoh32(uint32_t v);
255 extern uint16_t ntoh16(uint16_t v);
262 extern uint16_t flip16(uint16_t v);
269 extern uint32_t flip32(uint32_t v);
276 extern uint64_t flip64(uint64_t v);
285 inline int64_t flip(int64_t v, uint64_t n) {
288 auto i =
static_cast<uint64_t
>(v);
289 i = flip64(i) >> (64 - n * 8);
290 return static_cast<int64_t
>(i);
300 inline uint64_t flip(uint64_t v, uint64_t n) {
303 return (flip64(v) >> (64 - n * 8));
307 HILTI_RT_ENUM(BitOrder, LSB0, MSB0, Undef);
310 template<
typename UINT>
311 inline hilti::rt::integer::safe<UINT> bits(hilti::rt::integer::safe<UINT> v, uint64_t lower, uint64_t upper,
313 constexpr
auto width = std::numeric_limits<UINT>::digits;
316 throw InvalidArgument(
"lower limit needs to be less or equal the upper limit");
318 if ( upper >= width )
319 throw InvalidArgument(
"upper limit needs to be less or equal the input width");
321 switch ( bo.value() ) {
322 case BitOrder::LSB0:
break;
325 lower = (width - lower - 1);
326 upper = (width - upper - 1);
327 std::swap(lower, upper);
330 case BitOrder::Undef:
throw RuntimeError(
"undefined bit order");
333 assert(lower <= upper);
334 const auto range = upper - lower + 1;
339 if (
range == width )
342 const auto mask = ((uint64_t(1) <<
range) - uint64_t(1U)) << lower;
343 return (v & mask) >> lower;
348 namespace detail::adl {
349 std::string
to_string(
const integer::BitOrder& x, tag );
std::string to_string(T &&x)
Definition: extension-points.h:26
auto range(const T &t)
Definition: iterator.h:37
void cannot_be_reached() __attribute__((noreturn))
Definition: util.cc:42
ByteOrder systemByteOrder()
Definition: util.cc:392
void abort_with_backtrace() __attribute__((noreturn))
Definition: util.cc:34
std::string fmt(const char *fmt, const Args &... args)
Definition: fmt.h:13