summaryrefslogtreecommitdiffstats
path: root/source/core/slang-byte-encode-util.h
blob: 81fc0ef9839a3ee2cc5a3900b20b0b16ed38452d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#ifndef SLANG_CORE_BYTE_ENCODE_UTIL_H
#define SLANG_CORE_BYTE_ENCODE_UTIL_H

#include "slang-list.h"

namespace Slang
{

struct ByteEncodeUtil
{
    enum
    {
        kMaxLiteEncodeUInt16 = 3, /// One byte for prefix, the remaining 2 bytes hold the value
        kMaxLiteEncodeUInt32 = 5, /// One byte for prefix, the remaining 4 bytes hold the value
        // Cut values for 'Lite' encoding style
        kLiteCut1 = 185,
        kLiteCut2 = 249,
    };

    /** Find the most significant bit for 8 bits
    @param v The value to find most significant bit on
    @return The most significant bit, or -1 if no bits are set
    */
    SLANG_FORCE_INLINE static int calcMsb8(uint32_t v);

    /** Find the most significant bit for 32 bits
    @param v The value to find most significant bit on
    @return The most significant bit, or -1 if no bits are set
    */
    SLANG_FORCE_INLINE static int calcMsb32(uint32_t v);

    /** Calculates the 'most significant' byte ie the highest bytes that is non zero.
     Note return value is *undefined* if in is 0.
     @param in Value - cannot be 0.
     @return The byte index of the highest byte that is non zero.
     */
    SLANG_FORCE_INLINE static int calcNonZeroMsByte32(uint32_t in);

    /** Calculates the 'most significant' byte ie the highest bytes that is non zero.
    @param in Value - cannot be 0.
    @return The byte index of the highest byte that is non zero.
    */
    SLANG_FORCE_INLINE static int calcMsByte32(uint32_t in);

    /// Calculate the size of encoding bytes
    static size_t calcEncodeLiteSizeUInt32(const uint32_t* in, size_t num);

    /// Calculate the size of a single value
    static size_t calcEncodeLiteSizeUInt32(uint32_t in);

    /** Encodes a uint32_t as an integer
     @return the number of bytes needed to encode */
    static int encodeLiteUInt32(uint32_t in, uint8_t out[kMaxLiteEncodeUInt32]);

    /** Decode a lite encoding.
     @param in The lite encoded bytes
     @param out Value constructed
    @return number of bytes on in consumed */
    static int decodeLiteUInt32(const uint8_t* in, uint32_t* out);

    /** Encode an array of uint32_t
    @param in The values to encode
    @param num The amount of values to encode
    @param encodeOut The buffer to hold the encoded value. MUST be large enough to hold the encoding
    @return The size of the encoding in bytes
    */
    static size_t encodeLiteUInt32(const uint32_t* in, size_t num, uint8_t* encodeOut);

    /** Encode an array of uint32_t
    @param in The values to encode
    @param num The amount of values to encode
    @param encodeOut The buffer to hold the encoded value.
    */
    static void encodeLiteUInt32(const uint32_t* in, size_t num, List<uint8_t>& encodeOut);

    /** Encode an array of uint32_t
    @param encodeIn The encoded values
    @param numValues The amount of values to be decoded (NOTE! This is the number of valuesOut, not
    encodeIn)
    @param valuesOut The buffer to hold the encoded value. MUST be large enough to hold the encoding
    @return The amount of bytes decoded
    */
    static size_t decodeLiteUInt32(const uint8_t* encodeIn, size_t numValues, uint32_t* valuesOut);

    /// Table that maps 8 bits to it's most significant bit. If 0 returns -1.
    static const int8_t s_msb8[256];
};

#if SLANG_VC
// Works on ARM and x86/64 on visual studio compiler

// ---------------------------------------------------------------------------
SLANG_FORCE_INLINE int ByteEncodeUtil::calcNonZeroMsByte32(uint32_t in)
{
    SLANG_ASSERT(in != 0);
    // Can use intrinsic
    // https://msdn.microsoft.com/en-us/library/fbxyd7zd.aspx
    unsigned long index;
    _BitScanReverse(&index, in);
    return index >> 3;
}

// ---------------------------------------------------------------------------
SLANG_FORCE_INLINE int ByteEncodeUtil::calcMsByte32(uint32_t in)
{
    if (in == 0)
    {
        return -1;
    }
    // Can use intrinsic
    // https://msdn.microsoft.com/en-us/library/fbxyd7zd.aspx
    unsigned long index;
    _BitScanReverse(&index, in);
    return index >> 3;
}

// ---------------------------------------------------------------------------
SLANG_FORCE_INLINE /* static */ int ByteEncodeUtil::calcMsb8(uint32_t v)
{
    SLANG_ASSERT((v & 0xffffff00) == 0);
    if (v == 0)
    {
        return -1;
    }
    unsigned long index;
    _BitScanReverse(&index, v);
    return index;
}

// ---------------------------------------------------------------------------
SLANG_FORCE_INLINE /* static */ int ByteEncodeUtil::calcMsb32(uint32_t v)
{
    if (v == 0)
    {
        return -1;
    }
    unsigned long index;
    _BitScanReverse(&index, v);
    return index;
}

#else

// ---------------------------------------------------------------------------
SLANG_FORCE_INLINE /* static */ int ByteEncodeUtil::calcNonZeroMsByte32(uint32_t in)
{
    return (in & 0xffff0000) ? ((in & 0xff000000) ? 3 : 2) : ((in & 0x0000ff00) ? 1 : 0);
}

// ---------------------------------------------------------------------------
SLANG_FORCE_INLINE /* static */ int ByteEncodeUtil::calcMsByte32(uint32_t in)
{
    return (in & 0xffff0000) ? ((in & 0xff000000) ? 3 : 2)
                             : ((in & 0x0000ff00) ? 1 : ((in == 0) ? -1 : 0));
}

// ---------------------------------------------------------------------------
SLANG_FORCE_INLINE /* static */ int ByteEncodeUtil::calcMsb8(uint32_t v)
{
    SLANG_ASSERT((v & 0xffffff00) == 0);
    return s_msb8[v];
}

// ---------------------------------------------------------------------------
SLANG_FORCE_INLINE /* static */ int ByteEncodeUtil::calcMsb32(uint32_t v)
{
    return (v & 0xffff0000) ? ((v & 0xff000000) ? s_msb8[v >> 24] + 24 : s_msb8[v >> 16] + 16)
                            : ((v & 0x0000ff00) ? s_msb8[v >> 8] + 8 : s_msb8[v]);
}

#endif

// ---------------------------------------------------------------------------
inline /* static */ size_t ByteEncodeUtil::calcEncodeLiteSizeUInt32(uint32_t v)
{
    if (v < kLiteCut1)
    {
        return 1;
    }
    else if (v <= kLiteCut1 + 255 * (kLiteCut2 - 1 - kLiteCut1))
    {
        return 2;
    }
    else
    {
        return calcNonZeroMsByte32(v) + 2;
    }
}

} // namespace Slang

#endif // SLANG_BYTE_ENCODE_UTIL_H