%other-pointer-widetag derive-type: derive for simple-array.
[sbcl.git] / src / runtime / var-io.c
blob958573229a918e044d5dbb08eab29835eaf05390
1 /*
2 * This software is part of the SBCL system. See the README file for
3 * more information.
5 * This software is derived from the CMU CL system, which was
6 * written at Carnegie Mellon University and released into the
7 * public domain. The software is in the public domain and is
8 * provided with absolutely no warranty. See the COPYING and CREDITS
9 * files for more information.
12 #include "gc-assert.h"
13 #include "var-io.h"
14 #include "genesis/number-types.h"
16 // Read a variable-length encoded 32-bit integer from SOURCE and
17 // return its value.
19 // If OFFSET is not NULL, start decoding at OFFSET bytes from SOURCE
20 // and increment the value pointed to by OFFSET by the length of the
21 // encoded representation.
23 // Keep in sync with {READ,WRITE}-VAR-INTEGER in
24 // src/code/debug-var-io.lisp
25 int read_var_integer(unsigned char *source, int *offset) {
26 unsigned char *ptr = source + (offset ? *offset : 0);
27 int result = 0;
28 unsigned char octet;
29 int k = 0;
30 for (;; k += 7) {
31 octet = *(ptr++);
32 result |= (octet & 0x7f) << k;
33 if (!(octet & 0x80)) {
34 break;
37 if (offset) {
38 *offset += (ptr - source);
40 return result;
43 void varint_unpacker_init(struct varint_unpacker* unpacker, lispobj integer)
45 if (fixnump(integer)) {
46 unpacker->word = fixnum_value(integer);
47 unpacker->limit = N_WORD_BYTES;
48 unpacker->data = (char*)&unpacker->word;
49 } else {
50 gc_assert(lowtag_of(integer) == OTHER_POINTER_LOWTAG
51 && widetag_of(native_pointer(integer)) == BIGNUM_WIDETAG);
52 struct bignum* bignum = (struct bignum*)(integer - OTHER_POINTER_LOWTAG);
53 unpacker->word = 0;
54 unpacker->limit = HeaderValue(bignum->header) * N_WORD_BYTES;
55 unpacker->data = (char*)bignum->digits;
57 unpacker->index = 0;
60 // Fetch the next varint from 'unpacker' into 'result'.
61 // Because there is no length prefix on the number of varints encoded,
62 // spurious trailing zeros might be observed. The data consumer can
63 // circumvent that by storing a count as the first value in the series.
64 // Return 1 for success, 0 for EOF.
65 int varint_unpack(struct varint_unpacker* unpacker, int* result)
67 if (unpacker->index >= unpacker->limit) return 0;
68 int accumulator = 0;
69 int shift = 0;
70 while (1) {
71 #ifdef LISP_FEATURE_LITTLE_ENDIAN
72 int byte = unpacker->data[unpacker->index];
73 #else
74 // bignums are little-endian in word order,
75 // but machine-native within each word.
76 // We could pack bytes MSB-to-LSB in the bigdigits,
77 // but that seems less intuitive on the Lisp side.
78 int word_index = unpacker->index / N_WORD_BYTES;
79 int byte_index = unpacker->index % N_WORD_BYTES;
80 int byte = (((uword_t*)unpacker->data)[word_index] >> (byte_index * 8)) & 0xFF;
81 #endif
82 ++unpacker->index;
83 accumulator |= (byte & 0x7F) << shift;
84 if (!(byte & 0x80)) break;
85 gc_assert(unpacker->index < unpacker->limit);
86 shift += 7;
88 *result = accumulator;
89 return 1;
92 void skip_data_stream(struct varint_unpacker* unpacker)
94 // Read elements until seeing a 0
95 int val;
96 while (varint_unpack(unpacker, &val) && val != 0) { }