#pragma once
#include <util/system/defaults.h> // _BIDSCLASS _EXPCLASS
#include <util/system/yassert.h>
#include <util/system/unaligned_mem.h>
#define PUT_8(x, buf, shift) WriteUnaligned<ui8>((buf)++, (x) >> (shift))
#define GET_8_OR(x, buf, type, shift) (x) |= (type) * (buf)++ << (shift)
#if defined(_big_endian_)
#define LO_SHIFT 1
#define HI_SHIFT 0
#elif defined(_little_endian_)
#define LO_SHIFT 0
#define HI_SHIFT 1
#endif
#if !defined(_must_align2_)
#define PUT_16(x, buf, shift) WriteUnaligned<ui16>(buf, (x) >> (shift)), (buf) += 2
#define GET_16_OR(x, buf, type, shift) (x) |= (type)ReadUnaligned<ui16>(buf) << (shift), (buf) += 2
#else
#define PUT_16(x, buf, shift) PUT_8(x, buf, shift + 8 * LO_SHIFT), PUT_8(x, buf, shift + 8 * HI_SHIFT)
#define GET_16_OR(x, buf, type, shift) GET_8_OR(x, buf, type, shift + 8 * LO_SHIFT), GET_8_OR(x, buf, type, shift + 8 * HI_SHIFT)
#endif
#if !defined(_must_align4_)
#define PUT_32(x, buf, shift) WriteUnaligned<ui32>(buf, (x) >> (shift)), (buf) += 4
#define GET_32_OR(x, buf, type, shift) (x) |= (type)ReadUnaligned<ui32>(buf) << (shift), (buf) += 4
#else
#define PUT_32(x, buf, shift) PUT_16(x, buf, shift + 16 * LO_SHIFT), PUT_16(x, buf, shift + 16 * HI_SHIFT)
#define GET_32_OR(x, buf, type, shift) GET_16_OR(x, buf, type, shift + 16 * LO_SHIFT), GET_16_OR(x, buf, type, shift + 16 * HI_SHIFT)
#endif
#if !defined(_must_align8_)
#define PUT_64(x, buf, shift) WriteUnaligned<ui64>(buf, (x) >> (shift)), (buf) += 8
#define GET_64_OR(x, buf, type, shift) (x) |= (type)ReadUnaligned<ui64>(buf) << (shift), (buf) += 8
#else
#define PUT_64(x, buf, shift) PUT_32(x, buf, shift + 32 * LO_SHIFT), PUT_32(x, buf, shift + 32 * HI_SHIFT)
#define GET_64_OR(x, buf, type, shift) GET_32_OR(x, buf, type, shift + 32 * LO_SHIFT), GET_32_OR(x, buf, type, shift + 32 * HI_SHIFT)
#endif
struct mem_traits {
static ui8 get_8(const char*& mem) {
ui8 x = 0;
GET_8_OR(x, mem, ui8, 0);
return x;
}
static ui16 get_16(const char*& mem) {
ui16 x = 0;
GET_16_OR(x, mem, ui16, 0);
return x;
}
static ui32 get_32(const char*& mem) {
ui32 x = 0;
GET_32_OR(x, mem, ui32, 0);
return x;
}
static void put_8(ui8 x, char*& mem) {
PUT_8(x, mem, 0);
}
static void put_16(ui16 x, char*& mem) {
PUT_16(x, mem, 0);
}
static void put_32(ui32 x, char*& mem) {
PUT_32(x, mem, 0);
}
static int is_good(char*&) {
return 1;
}
};
/*
|____|____|____|____|____|____|____|____|____|____|____|____|____|____|8***|****
|____|____|____|____|____|____|____|____|____|____|____|____|i4**|****|****|****
|____|____|____|____|____|____|____|____|____|____|ii2*|****|****|****|****|****
|____|____|____|____|____|____|____|____|iii1|****|****|****|****|****|****|****
|____|____|____|____|____|____|iiii|8***|****|****|****|****|****|****|****|****
|____|____|____|____|iiii|i4**|****|****|****|****|****|****|****|****|****|****
|____|____|iiii|ii2*|****|****|****|****|****|****|****|****|****|****|****|****
|iiii|iii1|****|****|****|****|****|****|****|****|****|****|****|****|****|****
*/
#define PACK1LIM 0x80u
#define PACK2LIM 0x4000u
#define PACK3LIM 0x200000u
#define PACK4LIM 0x10000000u
#define PACK5LIM 0x800000000ull
#define PACK6LIM 0x40000000000ull
#define PACK7LIM 0x2000000000000ull
#define PACK8LIM 0x100000000000000ull
#define MY_14(x) ((ui16)(x) < PACK1LIM ? 1 : 2)
#define MY_28(x) ((ui32)(x) < PACK2LIM ? MY_14(x) : ((ui32)(x) < PACK3LIM ? 3 : 4))
#define MY_32(x) ((ui32)(x) < PACK4LIM ? MY_28(x) : 5)
#define MY_64(x) ((ui64)(x) < PACK4LIM ? MY_28(x) : ((ui64)(x) < PACK6LIM ? ((ui64)(x) < PACK5LIM ? 5 : 6) : ((ui64)(x) < PACK7LIM ? 7 : ((ui64)(x) < PACK8LIM ? 8 : 9))))
#if !defined(MACRO_BEGIN)
#define MACRO_BEGIN do {
#define MACRO_END \
} \
while (0)
#endif
#define PACK_14(x, buf, how, ret) \
MACRO_BEGIN \
if ((ui16)(x) < PACK1LIM) { \
how::put_8((ui8)(x), (buf)); \
(ret) = 1; \
} else { \
how::put_8((ui8)(0x80 | (x) >> 8), (buf)); \
how::put_8((ui8)(x), (buf)); \
(ret) = 2; \
} \
MACRO_END
#define PACK_28(x, buf, how, ret) \
MACRO_BEGIN \
if ((ui32)(x) < PACK2LIM) { \
PACK_14(x, buf, how, ret); \
} else { \
if ((ui32)(x) < PACK3LIM) { \
how::put_8((ui8)(0xC0 | (x) >> 16), buf); \
(ret) = 3; \
} else { \
how::put_8((ui8)(0xE0 | (x) >> 24), buf); \
how::put_8((ui8)((x) >> 16), buf); \
(ret) = 4; \
} \
how::put_16((ui16)(x), (buf)); \
} \
MACRO_END
#define PACK_32(x, buf, how, ret) \
MACRO_BEGIN \
if ((ui32)(x) < PACK4LIM) { \
PACK_28(x, buf, how, ret); \
} else { \
how::put_8((ui8)(0xF0), buf); \
how::put_32((ui32)(x), buf); \
(ret) = 5; \
} \
MACRO_END
#define PACK_64(x, buf, how, ret) \
MACRO_BEGIN \
if ((ui64)(x) < PACK4LIM) { \
PACK_28((ui32)(x), buf, how, ret); \
} else { \
if ((ui64)(x) < PACK6LIM) { \
if ((ui64)(x) < PACK5LIM) { \
how::put_8((ui8)(0xF0 | (x) >> 32), buf); \
(ret) = 5; \
} else { \
how::put_8((ui8)(0xF8 | (x) >> 40), buf); \
how::put_8((ui8)((x) >> 32), buf); \
(ret) = 6; \
} \
} else { \
if ((ui64)(x) < PACK7LIM) { \
how::put_8((ui8)(0xFC | (x) >> 48), buf); \
(ret) = 7; \
} else { \
if ((ui64)(x) < PACK8LIM) { \
how::put_8((ui8)(0xFE | (x) >> 56), buf); \
how::put_8((ui8)((x) >> 48), buf); \
(ret) = 8; \
} else { \
how::put_8((ui8)(0xFF), buf); \
how::put_16((ui16)((x) >> 48), buf); \
(ret) = 9; \
} \
} \
how::put_16((ui16)((x) >> 32), buf); \
} \
how::put_32((ui32)(x), buf); \
} \
MACRO_END
#define DO_UNPACK_14(firstByte, x, buf, how, ret) \
MACRO_BEGIN \
if (firstByte < 0x80) { \
(x) = (firstByte); \
(ret) = 1; \
} else { \
(x) = (firstByte & 0x7F) << 8; \
(x) |= how::get_8(buf); \
(ret) = 2; \
} \
MACRO_END
#define UNPACK_14(x, buf, how, ret) \
MACRO_BEGIN \
ui8 firstByte = how::get_8(buf); \
DO_UNPACK_14(firstByte, x, buf, how, ret); \
MACRO_END
#define DO_UNPACK_28(firstByte, x, buf, how, ret) \
MACRO_BEGIN \
if (firstByte < 0xC0) { \
DO_UNPACK_14(firstByte, x, buf, how, ret); \
} else { \
if (firstByte < 0xE0) { \
(x) = (firstByte & 0x3F) << 16; \
(ret) = 3; \
} else { \
(x) = (firstByte & 0x1F) << 24; \
(x) |= how::get_8(buf) << 16; \
(ret) = 4; \
} \
(x) |= how::get_16(buf); \
} \
MACRO_END
#define UNPACK_28(x, buf, how, ret) \
MACRO_BEGIN \
ui8 firstByte = how::get_8(buf); \
DO_UNPACK_28(firstByte, x, buf, how, ret); \
MACRO_END
#define DO_UNPACK_32(firstByte, x, buf, how, ret) \
MACRO_BEGIN \
if (firstByte < 0xF0) { \
DO_UNPACK_28(firstByte, x, buf, how, ret); \
} else { \
(x) = how::get_32(buf); \
(ret) = 5; \
} \
MACRO_END
#define UNPACK_32(x, buf, how, ret) \
MACRO_BEGIN \
ui8 firstByte = how::get_8(buf); \
DO_UNPACK_32(firstByte, x, buf, how, ret); \
MACRO_END
#define DO_UNPACK_64(firstByte, x, buf, how, ret) \
MACRO_BEGIN \
if (firstByte < 0xF0) { \
DO_UNPACK_28(firstByte, x, buf, how, ret); \
} else { \
if (firstByte < 0xFC) { \
if (firstByte < 0xF8) { \
(x) = (ui64)(firstByte & 0x0F) << 32; \
(ret) = 5; \
} else { \
(x) = (ui64)(firstByte & 0x07) << 40; \
(x) |= (ui64)how::get_8(buf) << 32; \
(ret) = 6; \
} \
} else { \
if (firstByte < 0xFE) { \
(x) = (ui64)(firstByte & 0x03) << 48; \
(ret) = 7; \
} else { \
if (firstByte < 0xFF) { \
(x) = (ui64)(firstByte & 0x01) << 56; \
(x) |= (ui64)how::get_8(buf) << 48; \
(ret) = 8; \
} else { \
(x) = (ui64)how::get_16(buf) << 48; \
(ret) = 9; \
} \
} \
(x) |= (ui64)how::get_16(buf) << 32; \
} \
(x) |= how::get_32(buf); \
} \
MACRO_END
#define UNPACK_64(x, buf, how, ret) \
MACRO_BEGIN \
ui8 firstByte = how::get_8(buf); \
DO_UNPACK_64(firstByte, x, buf, how, ret); \
MACRO_END
inline int in_long(i64& longVal, const char* ptrBuf) {
int ret = 0;
UNPACK_64(longVal, ptrBuf, mem_traits, ret);
return ret;
}
inline int out_long(const i64& longVal, char* ptrBuf) {
int ret = 0;
PACK_64(longVal, ptrBuf, mem_traits, ret); /*7*/
return ret;
}
inline int len_long(const i64& longVal) {
return MY_64(longVal);
}
inline int in_long(i32& longVal, const char* ptrBuf) {
int ret = 0;
UNPACK_32(longVal, ptrBuf, mem_traits, ret);
return ret;
}
inline int out_long(const i32& longVal, char* ptrBuf) {
int ret = 0;
PACK_32(longVal, ptrBuf, mem_traits, ret);
return ret;
}
inline int len_long(const i32& longVal) {
return MY_32(longVal);
}
template <typename T, typename C>
inline const C* Unpack32(T& x, const C* src) {
int pkLen = 0;
const char* c = reinterpret_cast<const char*>(src);
Y_UNUSED(pkLen);
UNPACK_32(x, c, mem_traits, pkLen);
Y_ASSERT(pkLen);
return reinterpret_cast<const C*>(c);
}
template <typename T, typename C>
inline const C* Unpack64(T& x, const C* src) {
int pkLen = 0;
const char* c = reinterpret_cast<const char*>(src);
Y_UNUSED(pkLen);
UNPACK_64(x, c, mem_traits, pkLen);
Y_ASSERT(pkLen);
return reinterpret_cast<const C*>(c);
}
template <typename T, typename C>
inline C* Pack32(const T& x, C* dest) {
int pkLen = 0;
Y_UNUSED(pkLen);
char* c = reinterpret_cast<char*>(dest);
PACK_32(x, c, mem_traits, pkLen);
Y_ASSERT(pkLen);
return reinterpret_cast<C*>(c);
}
template <typename T, typename C>
inline C* Pack64(const T& x, C* dest) {
int pkLen = 0;
Y_UNUSED(pkLen);
char* c = reinterpret_cast<char*>(dest);
PACK_64(x, c, mem_traits, pkLen);
Y_ASSERT(pkLen);
return reinterpret_cast<C*>(c);
}