Skip to content

Commit 3cb158b

Browse files
committed
FEAT: Bincode - added command VINT (for variable-length integers)
1 parent e1ee49e commit 3cb158b

File tree

2 files changed

+62
-0
lines changed

2 files changed

+62
-0
lines changed

src/core/u-bincode.c

+47
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,13 @@ static REBCNT EncodedU32_Size(u32 value) {
218218
return count;
219219
}
220220

221+
static REBCNT EncodedVINT_Size(REBU64 value) {
222+
REBCNT count = 1;
223+
REBU64 temp = value;
224+
while (temp >= (1ULL << (7 * count))) count++;
225+
return count;
226+
}
227+
221228
/***********************************************************************
222229
**
223230
*/ REBNATIVE(binary)
@@ -565,6 +572,13 @@ static REBCNT EncodedU32_Size(u32 value) {
565572
}
566573
goto error;
567574

575+
case SYM_VINT:
576+
if (IS_INTEGER(next)) {
577+
count += EncodedVINT_Size(VAL_UNT64(next));
578+
continue;
579+
}
580+
goto error;
581+
568582
case SYM_FLOAT:
569583
case SYM_F32:
570584
case SYM_F32LE:
@@ -936,6 +950,16 @@ static REBCNT EncodedU32_Size(u32 value) {
936950
}
937951
break;
938952

953+
case SYM_VINT:
954+
u = VAL_UNT64(next);
955+
n = EncodedVINT_Size(u);
956+
for (i = n-1; i > 0; i--) {
957+
cp[i] = (char)(u & 0xFF);
958+
u >>= 8;
959+
}
960+
cp[0] = (char)(u | (0x80 >> (n-1)));
961+
break;
962+
939963
case SYM_UNIXTIME_NOW:
940964
value--; // no args
941965
n = 4;
@@ -1651,6 +1675,29 @@ static REBCNT EncodedU32_Size(u32 value) {
16511675
VAL_INDEX(buffer_write) = MAX(0, (REBI64)VAL_INDEX(buffer_write) - VAL_INDEX(buffer_read));
16521676
VAL_INDEX(buffer_read) = 0;
16531677
continue;
1678+
1679+
case SYM_VINT: {
1680+
// A variable-length format for positive integers
1681+
ASSERT_READ_SIZE(value, cp, ep, 1);
1682+
int mask = 0x80;
1683+
n = 1;
1684+
// Determine the length of the VINT
1685+
while (mask) {
1686+
if (cp[0] & mask) break;
1687+
mask >>= 1;
1688+
n++;
1689+
}
1690+
// Extract the VINT value
1691+
ASSERT_READ_SIZE(value, cp, ep, n);
1692+
u = (u64)(cp[0] & (0xFF >> n));
1693+
for (int i = 1; i < n; i++) {
1694+
u = (u << 8) | cp[i];
1695+
}
1696+
VAL_SET(temp, REB_INTEGER);
1697+
VAL_UNT64(temp) = u;
1698+
break;
1699+
}
1700+
16541701
default:
16551702
Trap1(RE_INVALID_SPEC, value);
16561703
}

src/tests/units/bincode-test.r3

+15
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,21 @@ is-protected-error?: func[code][
335335
--assert [0 1 128 129 130 2214768806] = binary/read b [
336336
EncodedU32 EncodedU32 EncodedU32 EncodedU32 EncodedU32 EncodedU32]
337337

338+
--test-- "BinCode - VINT"
339+
;; Another variable-length integer encoding (used in EBML/Matroska files)
340+
b: binary/init none 16
341+
binary/write b [
342+
VINT 0
343+
VINT 1
344+
VINT 128
345+
VINT 129
346+
VINT 130
347+
VINT 2214768806
348+
]
349+
--assert b/buffer = #{8081408040814082088402B0A6}
350+
--assert [0 1 128 129 130 2214768806] = binary/read b [
351+
VINT VINT VINT VINT VINT VINT]
352+
338353
--test-- "BinCode - BITSET8, BITSET16, BITSET32 (read)"
339354
binary/read #{81800180000001} [
340355
f8: BITSET8

0 commit comments

Comments
 (0)