aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/packedtypes/zigzag.h
blob: 8d54a906da2e797d907dfd0febb600e002f9ce90 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#pragma once

#include <util/generic/typetraits.h>

#include <limits.h>

//! Convert signed values to unsigned. Convenient for further varint encoding.
//! See https://developers.google.com/protocol-buffers/docs/encoding#types for details.

template <typename TSignedInt>
inline auto ZigZagEncode(TSignedInt n) -> std::make_unsigned_t<TSignedInt> {
    static_assert(std::is_signed<TSignedInt>::value && std::is_integral<TSignedInt>::value, "Expected signed integral type."); 
    auto un = static_cast<std::make_unsigned_t<TSignedInt>>(n);
    return (un << 1) ^ (n >> (CHAR_BIT * sizeof(TSignedInt) - 1));
}

template <typename TUnsignedInt>
inline auto ZigZagDecode(TUnsignedInt n) -> std::make_signed_t<TUnsignedInt> {
    static_assert(std::is_unsigned<TUnsignedInt>::value, "Expected unsigned integral type."); 
    return (n >> 1) ^ -static_cast<std::make_signed_t<TUnsignedInt>>(n & 1);
}