mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-06 20:43:44 +02:00
More cross-platform build fixes and add tests for hton/ntoh/other byte order stuff because breakage there would be annoying.
This commit is contained in:
parent
77e59818a3
commit
6b49148d4e
2 changed files with 196 additions and 180 deletions
104
node/Tests.cpp
104
node/Tests.cpp
|
@ -313,21 +313,85 @@ extern "C" const char *ZTT_general()
|
|||
}
|
||||
|
||||
{
|
||||
ZT_T_PRINTF("[general] Testing hton/ntoh byte order converters... ");
|
||||
uint64_t a = Utils::hton((uint64_t)1);
|
||||
uint32_t b = Utils::hton((uint32_t)1);
|
||||
uint16_t c = Utils::hton((uint16_t)1);
|
||||
ZT_T_PRINTF("[general] Testing byte order loading, storing, and conversion... ");
|
||||
uint64_t a = Utils::hton((uint64_t)0x0807060504030201ULL);
|
||||
uint32_t b = Utils::hton((uint32_t)0x04030201);
|
||||
uint16_t c = Utils::hton((uint16_t)0x0201);
|
||||
uint8_t t[8];
|
||||
if (
|
||||
(reinterpret_cast<uint8_t *>(&a)[7] != 1)||
|
||||
(reinterpret_cast<uint8_t *>(&b)[3] != 1)||
|
||||
(reinterpret_cast<uint8_t *>(&c)[1] != 1)||
|
||||
(Utils::ntoh(a) != 1)||
|
||||
(Utils::ntoh(b) != 1)||
|
||||
(Utils::ntoh(c) != 1)
|
||||
(Utils::ntoh(a) != 0x0807060504030201ULL)||
|
||||
(Utils::ntoh(b) != 0x04030201)||
|
||||
(Utils::ntoh(c) != 0x0201)
|
||||
) {
|
||||
ZT_T_PRINTF("FAILED" ZT_EOL_S);
|
||||
return "Utils::hton/ntoh not working properly";
|
||||
ZT_T_PRINTF("FAILED (hton/ntoh)" ZT_EOL_S);
|
||||
return "Utils::hton() or ntoh() broken";
|
||||
}
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
if (Utils::loadAsIsEndian<uint64_t>(&a) != 0x0102030405060708ULL) {
|
||||
ZT_T_PRINTF("FAILED (loadAsIsEndian)" ZT_EOL_S);
|
||||
return "Utils::loadAsIsEndian() broken";
|
||||
}
|
||||
if (Utils::loadAsIsEndian<uint32_t>(&b) != 0x01020304) {
|
||||
ZT_T_PRINTF("FAILED (loadAsIsEndian)" ZT_EOL_S);
|
||||
return "Utils::loadAsIsEndian() broken";
|
||||
}
|
||||
if (Utils::loadAsIsEndian<uint16_t>(&c) != 0x0102) {
|
||||
ZT_T_PRINTF("FAILED (loadAsIsEndian)" ZT_EOL_S);
|
||||
return "Utils::loadAsIsEndian() broken";
|
||||
}
|
||||
memset(t,0,sizeof(t));
|
||||
Utils::storeAsIsEndian<uint64_t>(t,0x0807060504030201ULL);
|
||||
if (t[0] != 1) {
|
||||
ZT_T_PRINTF("FAILED (storeAsIsEndian)" ZT_EOL_S);
|
||||
return "Utils::storeAsIsEndian() broken";
|
||||
}
|
||||
memset(t,0,sizeof(t));
|
||||
Utils::storeAsIsEndian<uint32_t>(t,0x04030201);
|
||||
if (t[0] != 1) {
|
||||
ZT_T_PRINTF("FAILED (storeAsIsEndian)" ZT_EOL_S);
|
||||
return "Utils::storeAsIsEndian() broken";
|
||||
}
|
||||
memset(t,0,sizeof(t));
|
||||
Utils::storeAsIsEndian<uint16_t>(t,0x0201);
|
||||
if (t[0] != 1) {
|
||||
ZT_T_PRINTF("FAILED (storeAsIsEndian)" ZT_EOL_S);
|
||||
return "Utils::storeAsIsEndian() broken";
|
||||
}
|
||||
#else
|
||||
if (Utils::loadAsIsEndian<uint64_t>(&a) != 0x0807060504030201ULL) {
|
||||
ZT_T_PRINTF("FAILED (loadAsIsEndian)" ZT_EOL_S);
|
||||
return "Utils::loadAsIsEndian() broken";
|
||||
}
|
||||
if (Utils::loadAsIsEndian<uint32_t>(&b) != 0x04030201) {
|
||||
ZT_T_PRINTF("FAILED (loadAsIsEndian)" ZT_EOL_S);
|
||||
return "Utils::loadAsIsEndian() broken";
|
||||
}
|
||||
if (Utils::loadAsIsEndian<uint16_t>(&c) != 0x0201) {
|
||||
ZT_T_PRINTF("FAILED (loadAsIsEndian)" ZT_EOL_S);
|
||||
return "Utils::loadAsIsEndian() broken";
|
||||
}
|
||||
memset(t,0,sizeof(t));
|
||||
Utils::storeAsIsEndian<uint64_t>(t,0x0807060504030201ULL);
|
||||
if (t[0] != 8) {
|
||||
ZT_T_PRINTF("FAILED (storeAsIsEndian)" ZT_EOL_S);
|
||||
return "Utils::storeAsIsEndian() broken";
|
||||
}
|
||||
memset(t,0,sizeof(t));
|
||||
Utils::storeAsIsEndian<uint32_t>(t,0x04030201);
|
||||
if (t[0] != 4) {
|
||||
ZT_T_PRINTF("FAILED (storeAsIsEndian)" ZT_EOL_S);
|
||||
return "Utils::storeAsIsEndian() broken";
|
||||
}
|
||||
memset(t,0,sizeof(t));
|
||||
Utils::storeAsIsEndian<uint16_t>(t,0x0201);
|
||||
if (t[0] != 2) {
|
||||
ZT_T_PRINTF("FAILED (storeAsIsEndian)" ZT_EOL_S);
|
||||
return "Utils::storeAsIsEndian() broken";
|
||||
}
|
||||
#endif
|
||||
ZT_T_PRINTF("OK" ZT_EOL_S);
|
||||
}
|
||||
ZT_T_PRINTF("[general] Utils::hash64() samples for 1, 2, int64_max, uint64_max: %.16llx %.16llx %.16llx %.16llx" ZT_EOL_S,Utils::hash64(1),Utils::hash64(2),Utils::hash64(0xffffffffffffffffULL),Utils::hash64(0x7fffffffffffffffULL));
|
||||
|
@ -597,7 +661,6 @@ extern "C" const char *ZTT_general()
|
|||
ZT_T_PRINTF("FAILED (v0 marshal)" ZT_EOL_S);
|
||||
return "Identity test failed: v0 marshal";
|
||||
}
|
||||
ZT_T_PRINTF("(marshal: %d bytes) ",ms);
|
||||
Identity id2;
|
||||
if (id2.unmarshal(idm,ms) <= 0) {
|
||||
ZT_T_PRINTF("FAILED (v0 unmarshal)" ZT_EOL_S);
|
||||
|
@ -607,6 +670,16 @@ extern "C" const char *ZTT_general()
|
|||
ZT_T_PRINTF("FAILED (v0 unmarshal !=)" ZT_EOL_S);
|
||||
return "Identity test failed: v0 unmarshal !=";
|
||||
}
|
||||
ms = id.marshal(idm,false);
|
||||
if (ms <= 0) {
|
||||
ZT_T_PRINTF("FAILED (v0 marshal)" ZT_EOL_S);
|
||||
return "Identity test failed: v0 marshal";
|
||||
}
|
||||
if (id2.unmarshal(idm,ms) <= 0) {
|
||||
ZT_T_PRINTF("FAILED (v0 unmarshal)" ZT_EOL_S);
|
||||
return "Identity test failed: v0 unmarshal";
|
||||
}
|
||||
ZT_T_PRINTF("(marshalled size: %d bytes) ",ms);
|
||||
|
||||
if (!id.fromString(IDENTITY_V0_KNOWN_BAD_0)) {
|
||||
ZT_T_PRINTF("FAILED (error parsing test identity #2)" ZT_EOL_S);
|
||||
|
@ -638,7 +711,6 @@ extern "C" const char *ZTT_general()
|
|||
ZT_T_PRINTF("FAILED (v1 marshal)" ZT_EOL_S);
|
||||
return "Identity test failed: v1 marshal";
|
||||
}
|
||||
ZT_T_PRINTF("(marshal: %d bytes) ",ms);
|
||||
if (id2.unmarshal(idm,ms) <= 0) {
|
||||
ZT_T_PRINTF("FAILED (v1 unmarshal)" ZT_EOL_S);
|
||||
return "Identity test failed: v1 unmarshal";
|
||||
|
@ -647,6 +719,16 @@ extern "C" const char *ZTT_general()
|
|||
ZT_T_PRINTF("FAILED (v1 unmarshal !=)" ZT_EOL_S);
|
||||
return "Identity test failed: v1 unmarshal !=";
|
||||
}
|
||||
ms = id.marshal(idm,false);
|
||||
if (ms <= 0) {
|
||||
ZT_T_PRINTF("FAILED (v1 marshal)" ZT_EOL_S);
|
||||
return "Identity test failed: v1 marshal";
|
||||
}
|
||||
if (id2.unmarshal(idm,ms) <= 0) {
|
||||
ZT_T_PRINTF("FAILED (v1 unmarshal)" ZT_EOL_S);
|
||||
return "Identity test failed: v1 unmarshal";
|
||||
}
|
||||
ZT_T_PRINTF("(marshalled size: %d bytes) ",ms);
|
||||
|
||||
if (!id.fromString(IDENTITY_V1_KNOWN_BAD_0)) {
|
||||
ZT_T_PRINTF("FAILED (error parsing test identity #2)" ZT_EOL_S);
|
||||
|
|
272
node/Utils.hpp
272
node/Utils.hpp
|
@ -361,17 +361,38 @@ static ZT_ALWAYS_INLINE uint16_t swapBytes(const uint16_t n) noexcept
|
|||
#endif
|
||||
}
|
||||
|
||||
// ZZvvvzvzvvzzz... moooooo... http://www.catb.org/~esr/jargon/html/Y/yak-shaving.html
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
// These are helper adapters to load and swap integer types special cased by size
|
||||
// to work with all typedef'd variants, signed/unsigned, etc.
|
||||
template<typename I,unsigned int S>
|
||||
class _hton_impl { public: static ZT_ALWAYS_INLINE I hton(const I n) { return n; } };
|
||||
class _swap_bytes_bysize;
|
||||
template<typename I>
|
||||
class _hton_impl<I,2> { public: static ZT_ALWAYS_INLINE I hton(const I n) { return (I)swapBytes((uint16_t)n); } };
|
||||
class _swap_bytes_bysize<I,1> { public: static ZT_ALWAYS_INLINE I s(const I n) noexcept { return n; } };
|
||||
template<typename I>
|
||||
class _hton_impl<I,4> { public: static ZT_ALWAYS_INLINE I hton(const I n) { return (I)swapBytes((uint32_t)n); } };
|
||||
class _swap_bytes_bysize<I,2> { public: static ZT_ALWAYS_INLINE I s(const I n) noexcept { return (I)swapBytes((uint16_t)n); } };
|
||||
template<typename I>
|
||||
class _hton_impl<I,8> { public: static ZT_ALWAYS_INLINE I hton(const I n) { return (I)swapBytes((uint64_t)n); } };
|
||||
#endif
|
||||
class _swap_bytes_bysize<I,4> { public: static ZT_ALWAYS_INLINE I s(const I n) noexcept { return (I)swapBytes((uint32_t)n); } };
|
||||
template<typename I>
|
||||
class _swap_bytes_bysize<I,8> { public: static ZT_ALWAYS_INLINE I s(const I n) noexcept { return (I)swapBytes((uint64_t)n); } };
|
||||
template<typename I,unsigned int S>
|
||||
class _load_be_bysize;
|
||||
template<typename I>
|
||||
class _load_be_bysize<I,1> { public: static ZT_ALWAYS_INLINE I l(const uint8_t *const p) noexcept { return p[0]; }};
|
||||
template<typename I>
|
||||
class _load_be_bysize<I,2> { public: static ZT_ALWAYS_INLINE I l(const uint8_t *const p) noexcept { return (I)(((unsigned int)p[0] << 8U) | (unsigned int)p[1]); }};
|
||||
template<typename I>
|
||||
class _load_be_bysize<I,4> { public: static ZT_ALWAYS_INLINE I l(const uint8_t *const p) noexcept { return (I)(((uint32_t)p[0] << 24U) | ((uint32_t)p[1] << 16U) | ((uint32_t)p[2] << 8U) | (uint32_t)p[3]); }};
|
||||
template<typename I>
|
||||
class _load_be_bysize<I,8> { public: static ZT_ALWAYS_INLINE I l(const uint8_t *const p) noexcept { return (I)(((uint64_t)p[0] << 56U) | ((uint64_t)p[1] << 48U) | ((uint64_t)p[2] << 40U) | ((uint64_t)p[3] << 32U) | ((uint64_t)p[4] << 24U) | ((uint64_t)p[5] << 16U) | ((uint64_t)p[6] << 8U) | (uint64_t)p[7]); }};
|
||||
template<typename I,unsigned int S>
|
||||
class _load_le_bysize;
|
||||
template<typename I>
|
||||
class _load_le_bysize<I,1> { public: static ZT_ALWAYS_INLINE I l(const uint8_t *const p) noexcept { return p[0]; }};
|
||||
template<typename I>
|
||||
class _load_le_bysize<I,2> { public: static ZT_ALWAYS_INLINE I l(const uint8_t *const p) noexcept { return (I)((unsigned int)p[0] | ((unsigned int)p[1] << 8U)); }};
|
||||
template<typename I>
|
||||
class _load_le_bysize<I,4> { public: static ZT_ALWAYS_INLINE I l(const uint8_t *const p) noexcept { return (I)((uint32_t)p[0] | ((uint32_t)p[1] << 8U) | ((uint32_t)p[2] << 16U) | ((uint32_t)p[3] << 24U)); }};
|
||||
template<typename I>
|
||||
class _load_le_bysize<I,8> { public: static ZT_ALWAYS_INLINE I l(const uint8_t *const p) noexcept { return (I)((uint64_t)p[0] | ((uint64_t)p[1] << 8U) | ((uint64_t)p[2] << 16U) | ((uint64_t)p[3] << 24U) | ((uint64_t)p[4] << 32U) | ((uint64_t)p[5] << 40U) | ((uint64_t)p[6] << 48U) | ((uint64_t)p[7]) << 56U); }};
|
||||
|
||||
/**
|
||||
* Convert any signed or unsigned integer type to big-endian ("network") byte order
|
||||
|
@ -384,7 +405,7 @@ template<typename I>
|
|||
static ZT_ALWAYS_INLINE I hton(const I n) noexcept
|
||||
{
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
return _hton_impl<I,sizeof(I)>::hton(n);
|
||||
return _swap_bytes_bysize<I,sizeof(I)>::s(n);
|
||||
#else
|
||||
return n;
|
||||
#endif
|
||||
|
@ -401,168 +422,12 @@ template<typename I>
|
|||
static ZT_ALWAYS_INLINE I ntoh(const I n) noexcept
|
||||
{
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
return _hton_impl<I,sizeof(I)>::hton(n);
|
||||
return _swap_bytes_bysize<I,sizeof(I)>::s(n);
|
||||
#else
|
||||
return n;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a big-endian value from a byte stream
|
||||
*
|
||||
* @tparam I Type to decode (should be unsigned e.g. uint32_t or uint64_t)
|
||||
* @param p Byte stream, must be at least sizeof(I) in size
|
||||
* @return Decoded integer
|
||||
*/
|
||||
template<typename I>
|
||||
static ZT_ALWAYS_INLINE I loadBigEndian(const void *const p) noexcept
|
||||
{
|
||||
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||
if (sizeof(I) == 8) {
|
||||
return (I)(
|
||||
((uint64_t)reinterpret_cast<const uint8_t *>(p)[0] << 56U) |
|
||||
((uint64_t)reinterpret_cast<const uint8_t *>(p)[1] << 48U) |
|
||||
((uint64_t)reinterpret_cast<const uint8_t *>(p)[2] << 40U) |
|
||||
((uint64_t)reinterpret_cast<const uint8_t *>(p)[3] << 32U) |
|
||||
((uint64_t)reinterpret_cast<const uint8_t *>(p)[4] << 24U) |
|
||||
((uint64_t)reinterpret_cast<const uint8_t *>(p)[5] << 16U) |
|
||||
((uint64_t)reinterpret_cast<const uint8_t *>(p)[6] << 8U) |
|
||||
(uint64_t)reinterpret_cast<const uint8_t *>(p)[7]
|
||||
);
|
||||
} else if (sizeof(I) == 4) {
|
||||
return (I)(
|
||||
((uint32_t)reinterpret_cast<const uint8_t *>(p)[0] << 24U) |
|
||||
((uint32_t)reinterpret_cast<const uint8_t *>(p)[1] << 16U) |
|
||||
((uint32_t)reinterpret_cast<const uint8_t *>(p)[2] << 8U) |
|
||||
(uint32_t)reinterpret_cast<const uint8_t *>(p)[3]
|
||||
);
|
||||
} else if (sizeof(I) == 2) {
|
||||
return (I)(
|
||||
((unsigned int)reinterpret_cast<const uint8_t *>(p)[0] << 8U) |
|
||||
(unsigned int)reinterpret_cast<const uint8_t *>(p)[1]
|
||||
);
|
||||
} else {
|
||||
return (I)reinterpret_cast<const uint8_t *>(p)[0];
|
||||
}
|
||||
#else
|
||||
return ntoh(*reinterpret_cast<const I *>(p));
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Save an integer in big-endian format
|
||||
*
|
||||
* @tparam I Integer type to store (usually inferred)
|
||||
* @param p Byte stream to write (must be at least sizeof(I))
|
||||
* #param i Integer to write
|
||||
*/
|
||||
template<typename I>
|
||||
static ZT_ALWAYS_INLINE void storeBigEndian(void *const p,I i) noexcept
|
||||
{
|
||||
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||
if (sizeof(I) == 8) {
|
||||
reinterpret_cast<uint8_t *>(p)[0] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 56U);
|
||||
reinterpret_cast<uint8_t *>(p)[1] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 48U);
|
||||
reinterpret_cast<uint8_t *>(p)[2] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 40U);
|
||||
reinterpret_cast<uint8_t *>(p)[3] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 32U);
|
||||
reinterpret_cast<uint8_t *>(p)[4] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 24U);
|
||||
reinterpret_cast<uint8_t *>(p)[5] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 16U);
|
||||
reinterpret_cast<uint8_t *>(p)[6] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 8U);
|
||||
reinterpret_cast<uint8_t *>(p)[7] = (uint8_t)reinterpret_cast<uint64_t>(i);
|
||||
} else if (sizeof(I) == 4) {
|
||||
reinterpret_cast<uint8_t *>(p)[0] = (uint8_t)(reinterpret_cast<uint32_t>(i) >> 24U);
|
||||
reinterpret_cast<uint8_t *>(p)[1] = (uint8_t)(reinterpret_cast<uint32_t>(i) >> 16U);
|
||||
reinterpret_cast<uint8_t *>(p)[2] = (uint8_t)(reinterpret_cast<uint32_t>(i) >> 8U);
|
||||
reinterpret_cast<uint8_t *>(p)[3] = (uint8_t)reinterpret_cast<uint32_t>(i);
|
||||
} else if (sizeof(I) == 2) {
|
||||
reinterpret_cast<uint8_t *>(p)[0] = (uint8_t)(reinterpret_cast<uint16_t>(i) >> 8U);
|
||||
reinterpret_cast<uint8_t *>(p)[1] = (uint8_t)reinterpret_cast<uint16_t>(i);
|
||||
} else {
|
||||
reinterpret_cast<uint8_t *>(p)[0] = (uint8_t)i;
|
||||
}
|
||||
#else
|
||||
*reinterpret_cast<I *>(p) = hton(i);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a little-endian value from a byte stream
|
||||
*
|
||||
* @tparam I Type to decode
|
||||
* @param p Byte stream, must be at least sizeof(I) in size
|
||||
* @return Decoded integer
|
||||
*/
|
||||
template<typename I>
|
||||
static ZT_ALWAYS_INLINE I loadLittleEndian(const void *const p) noexcept
|
||||
{
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN || defined(ZT_NO_UNALIGNED_ACCESS)
|
||||
if (sizeof(I) == 8) {
|
||||
return (I)(
|
||||
(uint64_t)reinterpret_cast<const uint8_t *>(p)[0] |
|
||||
((uint64_t)reinterpret_cast<const uint8_t *>(p)[1] << 8U) |
|
||||
((uint64_t)reinterpret_cast<const uint8_t *>(p)[2] << 16U) |
|
||||
((uint64_t)reinterpret_cast<const uint8_t *>(p)[3] << 24U) |
|
||||
((uint64_t)reinterpret_cast<const uint8_t *>(p)[4] << 32U) |
|
||||
((uint64_t)reinterpret_cast<const uint8_t *>(p)[5] << 40U) |
|
||||
((uint64_t)reinterpret_cast<const uint8_t *>(p)[6] << 48U) |
|
||||
((uint64_t)reinterpret_cast<const uint8_t *>(p)[7] << 56U)
|
||||
);
|
||||
} else if (sizeof(I) == 4) {
|
||||
return (I)(
|
||||
(uint32_t)reinterpret_cast<const uint8_t *>(p)[0] |
|
||||
((uint32_t)reinterpret_cast<const uint8_t *>(p)[1] << 8U) |
|
||||
((uint32_t)reinterpret_cast<const uint8_t *>(p)[2] << 16U) |
|
||||
((uint32_t)reinterpret_cast<const uint8_t *>(p)[3] << 24U)
|
||||
);
|
||||
} else if (sizeof(I) == 2) {
|
||||
return (I)(
|
||||
(unsigned int)reinterpret_cast<const uint8_t *>(p)[0] |
|
||||
((unsigned int)reinterpret_cast<const uint8_t *>(p)[1] << 8U)
|
||||
);
|
||||
} else {
|
||||
return (I)reinterpret_cast<const uint8_t *>(p)[0];
|
||||
}
|
||||
#else
|
||||
return *reinterpret_cast<const I *>(p);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Save an integer in little-endian format
|
||||
*
|
||||
* @tparam I Integer type to store (usually inferred)
|
||||
* @param p Byte stream to write (must be at least sizeof(I))
|
||||
* #param i Integer to write
|
||||
*/
|
||||
template<typename I>
|
||||
static ZT_ALWAYS_INLINE void storeLittleEndian(void *const p,const I i) noexcept
|
||||
{
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN || defined(ZT_NO_UNALIGNED_ACCESS)
|
||||
if (sizeof(I) == 8) {
|
||||
reinterpret_cast<uint8_t *>(p)[0] = (uint8_t)reinterpret_cast<uint64_t>(i);
|
||||
reinterpret_cast<uint8_t *>(p)[1] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 8U);
|
||||
reinterpret_cast<uint8_t *>(p)[2] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 16U);
|
||||
reinterpret_cast<uint8_t *>(p)[3] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 24U);
|
||||
reinterpret_cast<uint8_t *>(p)[4] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 32U);
|
||||
reinterpret_cast<uint8_t *>(p)[5] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 40U);
|
||||
reinterpret_cast<uint8_t *>(p)[6] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 48U);
|
||||
reinterpret_cast<uint8_t *>(p)[7] = (uint8_t)(reinterpret_cast<uint64_t>(i) >> 56U);
|
||||
} else if (sizeof(I) == 4) {
|
||||
reinterpret_cast<uint8_t *>(p)[0] = (uint8_t)reinterpret_cast<uint32_t>(i);
|
||||
reinterpret_cast<uint8_t *>(p)[1] = (uint8_t)(reinterpret_cast<uint32_t>(i) >> 8U);
|
||||
reinterpret_cast<uint8_t *>(p)[2] = (uint8_t)(reinterpret_cast<uint32_t>(i) >> 16U);
|
||||
reinterpret_cast<uint8_t *>(p)[3] = (uint8_t)(reinterpret_cast<uint32_t>(i) >> 24U);
|
||||
} else if (sizeof(I) == 2) {
|
||||
reinterpret_cast<uint8_t *>(p)[0] = (uint8_t)reinterpret_cast<uint16_t>(i);
|
||||
reinterpret_cast<uint8_t *>(p)[1] = (uint8_t)(reinterpret_cast<uint16_t>(i) >> 8U);
|
||||
} else {
|
||||
reinterpret_cast<uint8_t *>(p)[0] = (uint8_t)i;
|
||||
}
|
||||
#else
|
||||
*reinterpret_cast<I *>(p) = i;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy bits from memory into an integer type without modifying their order
|
||||
*
|
||||
|
@ -574,10 +439,11 @@ template<typename I>
|
|||
static ZT_ALWAYS_INLINE I loadAsIsEndian(const void *const p) noexcept
|
||||
{
|
||||
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||
I x = (I)0;
|
||||
for(unsigned int k=0;k<sizeof(I);++k)
|
||||
reinterpret_cast<uint8_t *>(&x)[k] = reinterpret_cast<const uint8_t *>(p)[k];
|
||||
return x;
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
return _load_le_bysize<I,sizeof(I)>::l(reinterpret_cast<const uint8_t *>(p));
|
||||
#else
|
||||
return _load_be_bysize<I,sizeof(I)>::l(reinterpret_cast<const uint8_t *>(p));
|
||||
#endif
|
||||
#else
|
||||
return *reinterpret_cast<const I *>(p);
|
||||
#endif
|
||||
|
@ -601,6 +467,74 @@ static ZT_ALWAYS_INLINE void storeAsIsEndian(void *const p,const I i) noexcept
|
|||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a big-endian value from a byte stream
|
||||
*
|
||||
* @tparam I Type to decode (should be unsigned e.g. uint32_t or uint64_t)
|
||||
* @param p Byte stream, must be at least sizeof(I) in size
|
||||
* @return Decoded integer
|
||||
*/
|
||||
template<typename I>
|
||||
static ZT_ALWAYS_INLINE I loadBigEndian(const void *const p) noexcept
|
||||
{
|
||||
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||
return _load_be_bysize<I,sizeof(I)>::l(reinterpret_cast<const uint8_t *>(p));
|
||||
#else
|
||||
return ntoh(*reinterpret_cast<const I *>(p));
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Save an integer in big-endian format
|
||||
*
|
||||
* @tparam I Integer type to store (usually inferred)
|
||||
* @param p Byte stream to write (must be at least sizeof(I))
|
||||
* #param i Integer to write
|
||||
*/
|
||||
template<typename I>
|
||||
static ZT_ALWAYS_INLINE void storeBigEndian(void *const p,I i) noexcept
|
||||
{
|
||||
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||
storeAsIsEndian(p,hton(i));
|
||||
#else
|
||||
*reinterpret_cast<I *>(p) = hton(i);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a little-endian value from a byte stream
|
||||
*
|
||||
* @tparam I Type to decode
|
||||
* @param p Byte stream, must be at least sizeof(I) in size
|
||||
* @return Decoded integer
|
||||
*/
|
||||
template<typename I>
|
||||
static ZT_ALWAYS_INLINE I loadLittleEndian(const void *const p) noexcept
|
||||
{
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN || defined(ZT_NO_UNALIGNED_ACCESS)
|
||||
return _load_le_bysize<I,sizeof(I)>::l(reinterpret_cast<const uint8_t *>(p));
|
||||
#else
|
||||
return *reinterpret_cast<const I *>(p);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Save an integer in little-endian format
|
||||
*
|
||||
* @tparam I Integer type to store (usually inferred)
|
||||
* @param p Byte stream to write (must be at least sizeof(I))
|
||||
* #param i Integer to write
|
||||
*/
|
||||
template<typename I>
|
||||
static ZT_ALWAYS_INLINE void storeLittleEndian(void *const p,const I i) noexcept
|
||||
{
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN || defined(ZT_NO_UNALIGNED_ACCESS)
|
||||
storeAsIsEndian(p,_swap_bytes_bysize<I,sizeof(I)>::s(i));
|
||||
#else
|
||||
*reinterpret_cast<I *>(p) = i;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Utils
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
|
Loading…
Add table
Reference in a new issue