Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
VarInt.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreTypes.h"
6#include "HAL/PlatformMath.h"
7
8// Variable-Length Integer Encoding
9//
10// ZigZag encoding is used to convert signed integers into unsigned integers in a way that allows
11// integers with a small magnitude to have a smaller encoded representation.
12//
13// An unsigned integer is encoded into 1-9 bytes based on its magnitude. The first byte indicates
14// how many additional bytes are used by the number of leading 1-bits that it has. The additional
15// bytes are stored in big endian order, and the most significant bits of the value are stored in
16// the remaining bits in the first byte. The encoding of the first byte allows the reader to skip
17// over the encoded integer without consuming its bytes individually.
18//
19// Encoded unsigned integers sort the same in a byte-wise comparison as when their decoded values
20// are compared. The same property does not hold for signed integers due to ZigZag encoding.
21//
22// 32-bit inputs encode to 1-5 bytes.
23// 64-bit inputs encode to 1-9 bytes.
24//
25// 0x0000'0000'0000'0000 - 0x0000'0000'0000'007f : 0b0_______ 1 byte
26// 0x0000'0000'0000'0080 - 0x0000'0000'0000'3fff : 0b10______ 2 bytes
27// 0x0000'0000'0000'4000 - 0x0000'0000'001f'ffff : 0b110_____ 3 bytes
28// 0x0000'0000'0020'0000 - 0x0000'0000'0fff'ffff : 0b1110____ 4 bytes
29// 0x0000'0000'1000'0000 - 0x0000'0007'ffff'ffff : 0b11110___ 5 bytes
30// 0x0000'0008'0000'0000 - 0x0000'03ff'ffff'ffff : 0b111110__ 6 bytes
31// 0x0000'0400'0000'0000 - 0x0001'ffff'ffff'ffff : 0b1111110_ 7 bytes
32// 0x0002'0000'0000'0000 - 0x00ff'ffff'ffff'ffff : 0b11111110 8 bytes
33// 0x0100'0000'0000'0000 - 0xffff'ffff'ffff'ffff : 0b11111111 9 bytes
34//
35// Encoding Examples
36// -42 => ZigZag => 0x53 => 0x53
37// 42 => ZigZag => 0x54 => 0x54
38// 0x1 => 0x01
39// 0x12 => 0x12
40// 0x123 => 0x81 0x23
41// 0x1234 => 0x92 0x34
42// 0x12345 => 0xc1 0x23 0x45
43// 0x123456 => 0xd2 0x34 0x56
44// 0x1234567 => 0xe1 0x23 0x45 0x67
45// 0x12345678 => 0xf0 0x12 0x34 0x56 0x78
46// 0x123456789 => 0xf1 0x23 0x45 0x67 0x89
47// 0x123456789a => 0xf8 0x12 0x34 0x56 0x78 0x9a
48// 0x123456789ab => 0xfb 0x23 0x45 0x67 0x89 0xab
49// 0x123456789abc => 0xfc 0x12 0x34 0x56 0x78 0x9a 0xbc
50// 0x123456789abcd => 0xfd 0x23 0x45 0x67 0x89 0xab 0xcd
51// 0x123456789abcde => 0xfe 0x12 0x34 0x56 0x78 0x9a 0xbc 0xde
52// 0x123456789abcdef => 0xff 0x01 0x23 0x45 0x67 0x89 0xab 0xcd 0xef
53// 0x123456789abcdef0 => 0xff 0x12 0x34 0x56 0x78 0x9a 0xbc 0xde 0xf0
54
55/**
56 * Measure the length in bytes (1-9) of an encoded variable-length integer.
57 *
58 * @param InData A variable-length encoding of an (signed or unsigned) integer.
59 * @return The number of bytes used to encode the integer, in the range 1-9.
60 */
61FORCEINLINE uint32 MeasureVarUInt(const void* InData)
62{
63 return FPlatformMath::CountLeadingZeros(uint8(~*static_cast<const uint8*>(InData))) - 23;
64}
65
66/** Measure the length in bytes (1-9) of an encoded variable-length integer. \see \ref MeasureVarUInt */
67FORCEINLINE uint32 MeasureVarInt(const void* InData)
68{
69 return MeasureVarUInt(InData);
70}
71
72/** Measure the number of bytes (1-5) required to encode the 32-bit input. */
73FORCEINLINE uint32 MeasureVarUInt(uint32 InValue)
74{
75 return uint32(int32(FPlatformMath::FloorLog2(InValue)) / 7 + 1);
76}
77
78/** Measure the number of bytes (1-9) required to encode the 64-bit input. */
79FORCEINLINE uint32 MeasureVarUInt(uint64 InValue)
80{
81 return uint32(FPlatformMath::Min(int32(FPlatformMath::FloorLog2_64(InValue)) / 7 + 1, 9));
82}
83
84/** Measure the number of bytes (1-5) required to encode the 32-bit input. \see \ref MeasureVarUInt */
85FORCEINLINE uint32 MeasureVarInt(int32 InValue)
86{
87 return MeasureVarUInt(uint32((InValue >> 31) ^ (InValue << 1)));
88}
89
90/** Measure the number of bytes (1-9) required to encode the 64-bit input. \see \ref MeasureVarUInt */
91FORCEINLINE uint32 MeasureVarInt(int64 InValue)
92{
93 return MeasureVarUInt(uint64((InValue >> 63) ^ (InValue << 1)));
94}
95
96/**
97 * Read a variable-length unsigned integer.
98 *
99 * @param InData A variable-length encoding of an unsigned integer.
100 * @param OutByteCount The number of bytes consumed from the input.
101 * @return An unsigned integer.
102 */
103FORCEINLINE uint64 ReadVarUInt(const void* InData, uint32& OutByteCount)
104{
105 const uint32 ByteCount = MeasureVarUInt(InData);
106 OutByteCount = ByteCount;
107
108 const uint8* InBytes = static_cast<const uint8*>(InData);
109 uint64 Value = *InBytes++ & uint8(0xff >> ByteCount);
110 switch (ByteCount - 1)
111 {
112 case 8: Value <<= 8; Value |= *InBytes++;
113 case 7: Value <<= 8; Value |= *InBytes++;
114 case 6: Value <<= 8; Value |= *InBytes++;
115 case 5: Value <<= 8; Value |= *InBytes++;
116 case 4: Value <<= 8; Value |= *InBytes++;
117 case 3: Value <<= 8; Value |= *InBytes++;
118 case 2: Value <<= 8; Value |= *InBytes++;
119 case 1: Value <<= 8; Value |= *InBytes++;
120 default:
121 return Value;
122 }
123}
124
125/**
126 * Read a variable-length signed integer.
127 *
128 * @param InData A variable-length encoding of a signed integer.
129 * @param OutByteCount The number of bytes consumed from the input.
130 * @return A signed integer.
131 */
132FORCEINLINE int64 ReadVarInt(const void* InData, uint32& OutByteCount)
133{
134 const uint64 Value = ReadVarUInt(InData, OutByteCount);
135 return -int64(Value & 1) ^ int64(Value >> 1);
136}
137
138/**
139 * Write a variable-length unsigned integer.
140 *
141 * @param InValue An unsigned integer to encode.
142 * @param OutData A buffer of at least 5 bytes to write the output to.
143 * @return The number of bytes used in the output.
144 */
145FORCEINLINE uint32 WriteVarUInt(uint32 InValue, void* OutData)
146{
147 const uint32 ByteCount = MeasureVarUInt(InValue);
148 uint8* OutBytes = static_cast<uint8*>(OutData) + ByteCount - 1;
149 switch (ByteCount - 1)
150 {
151 case 4: *OutBytes-- = uint8(InValue); InValue >>= 8;
152 case 3: *OutBytes-- = uint8(InValue); InValue >>= 8;
153 case 2: *OutBytes-- = uint8(InValue); InValue >>= 8;
154 case 1: *OutBytes-- = uint8(InValue); InValue >>= 8;
155 default: break;
156 }
157 *OutBytes = uint8(0xff << (9 - ByteCount)) | uint8(InValue);
158 return ByteCount;
159}
160
161/**
162 * Write a variable-length unsigned integer.
163 *
164 * @param InValue An unsigned integer to encode.
165 * @param OutData A buffer of at least 9 bytes to write the output to.
166 * @return The number of bytes used in the output.
167 */
168FORCEINLINE uint32 WriteVarUInt(uint64 InValue, void* OutData)
169{
170 const uint32 ByteCount = MeasureVarUInt(InValue);
171 uint8* OutBytes = static_cast<uint8*>(OutData) + ByteCount - 1;
172 switch (ByteCount - 1)
173 {
174 case 8: *OutBytes-- = uint8(InValue); InValue >>= 8;
175 case 7: *OutBytes-- = uint8(InValue); InValue >>= 8;
176 case 6: *OutBytes-- = uint8(InValue); InValue >>= 8;
177 case 5: *OutBytes-- = uint8(InValue); InValue >>= 8;
178 case 4: *OutBytes-- = uint8(InValue); InValue >>= 8;
179 case 3: *OutBytes-- = uint8(InValue); InValue >>= 8;
180 case 2: *OutBytes-- = uint8(InValue); InValue >>= 8;
181 case 1: *OutBytes-- = uint8(InValue); InValue >>= 8;
182 default: break;
183 }
184 *OutBytes = uint8(0xff << (9 - ByteCount)) | uint8(InValue);
185 return ByteCount;
186}
187
188/** Write a variable-length signed integer. \see \ref WriteVarUInt */
189FORCEINLINE uint32 WriteVarInt(int32 InValue, void* OutData)
190{
191 const uint32 Value = uint32((InValue >> 31) ^ (InValue << 1));
192 return WriteVarUInt(Value, OutData);
193}
194
195/** Write a variable-length signed integer. \see \ref WriteVarUInt */
196FORCEINLINE uint32 WriteVarInt(int64 InValue, void* OutData)
197{
198 const uint64 Value = uint64((InValue >> 63) ^ (InValue << 1));
199 return WriteVarUInt(Value, OutData);
200}
201
202class FArchive;
203
205void WriteVarIntToArchive(FArchive& Ar, int64 Value);
206void SerializeVarInt(FArchive& Ar, int64& Value);
207
209void WriteVarUIntToArchive(FArchive& Ar, uint64 Value);
210void SerializeVarUInt(FArchive& Ar, uint64& Value);
#define FORCEINLINE
Definition Platform.h:644
FORCEINLINE uint32 WriteVarInt(int64 InValue, void *OutData)
Definition VarInt.h:196
void SerializeVarInt(FArchive &Ar, int64 &Value)
FORCEINLINE uint32 MeasureVarUInt(const void *InData)
Definition VarInt.h:61
uint64 ReadVarUIntFromArchive(FArchive &Ar)
FORCEINLINE uint32 WriteVarUInt(uint32 InValue, void *OutData)
Definition VarInt.h:145
FORCEINLINE uint32 WriteVarUInt(uint64 InValue, void *OutData)
Definition VarInt.h:168
FORCEINLINE uint64 ReadVarUInt(const void *InData, uint32 &OutByteCount)
Definition VarInt.h:103
void SerializeVarUInt(FArchive &Ar, uint64 &Value)
void WriteVarIntToArchive(FArchive &Ar, int64 Value)
FORCEINLINE uint32 MeasureVarUInt(uint32 InValue)
Definition VarInt.h:73
int64 ReadVarIntFromArchive(FArchive &Ar)
FORCEINLINE uint32 MeasureVarInt(int32 InValue)
Definition VarInt.h:85
FORCEINLINE uint32 MeasureVarInt(const void *InData)
Definition VarInt.h:67
FORCEINLINE int64 ReadVarInt(const void *InData, uint32 &OutByteCount)
Definition VarInt.h:132
FORCEINLINE uint32 MeasureVarInt(int64 InValue)
Definition VarInt.h:91
FORCEINLINE uint32 WriteVarInt(int32 InValue, void *OutData)
Definition VarInt.h:189
FORCEINLINE uint32 MeasureVarUInt(uint64 InValue)
Definition VarInt.h:79
void WriteVarUIntToArchive(FArchive &Ar, uint64 Value)
FWindowsPlatformMath FPlatformMath