Protocol Buffers - Google's data interchange format (grpc依赖)
https://developers.google.com/protocol-buffers/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
143 lines
4.8 KiB
143 lines
4.8 KiB
14 years ago
|
/*
|
||
|
* upb - a minimalist implementation of protocol buffers.
|
||
|
*
|
||
14 years ago
|
* Copyright (c) 2011 Google Inc. See LICENSE for details.
|
||
|
* Author: Josh Haberman <jhaberman@gmail.com>
|
||
|
*
|
||
14 years ago
|
* A number of routines for varint manipulation (we keep them all around to
|
||
|
* have multiple approaches available for benchmarking).
|
||
14 years ago
|
*/
|
||
|
|
||
|
#ifndef UPB_VARINT_DECODER_H_
|
||
|
#define UPB_VARINT_DECODER_H_
|
||
|
|
||
|
#include <stdint.h>
|
||
|
#include <string.h>
|
||
14 years ago
|
#include "upb/upb.h"
|
||
14 years ago
|
|
||
|
#ifdef __cplusplus
|
||
|
extern "C" {
|
||
|
#endif
|
||
|
|
||
14 years ago
|
/* Decoding *******************************************************************/
|
||
|
|
||
14 years ago
|
// All decoding functions return this struct by value.
|
||
|
typedef struct {
|
||
|
const char *p; // NULL if the varint was unterminated.
|
||
|
uint64_t val;
|
||
|
} upb_decoderet;
|
||
|
|
||
|
// A basic branch-based decoder, uses 32-bit values to get good performance
|
||
|
// on 32-bit architectures (but performs well on 64-bits also).
|
||
14 years ago
|
INLINE upb_decoderet upb_vdecode_branch32(const char *p) {
|
||
14 years ago
|
upb_decoderet r = {NULL, 0};
|
||
|
uint32_t low, high = 0;
|
||
|
uint32_t b;
|
||
|
b = *(p++); low = (b & 0x7f) ; if(!(b & 0x80)) goto done;
|
||
|
b = *(p++); low |= (b & 0x7f) << 7; if(!(b & 0x80)) goto done;
|
||
|
b = *(p++); low |= (b & 0x7f) << 14; if(!(b & 0x80)) goto done;
|
||
|
b = *(p++); low |= (b & 0x7f) << 21; if(!(b & 0x80)) goto done;
|
||
|
b = *(p++); low |= (b & 0x7f) << 28;
|
||
|
high = (b & 0x7f) >> 4; if(!(b & 0x80)) goto done;
|
||
|
b = *(p++); high |= (b & 0x7f) << 3; if(!(b & 0x80)) goto done;
|
||
|
b = *(p++); high |= (b & 0x7f) << 10; if(!(b & 0x80)) goto done;
|
||
|
b = *(p++); high |= (b & 0x7f) << 17; if(!(b & 0x80)) goto done;
|
||
|
b = *(p++); high |= (b & 0x7f) << 24; if(!(b & 0x80)) goto done;
|
||
|
b = *(p++); high |= (b & 0x7f) << 31; if(!(b & 0x80)) goto done;
|
||
|
return r;
|
||
|
|
||
|
done:
|
||
|
r.val = ((uint64_t)high << 32) | low;
|
||
|
r.p = p;
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
// Like the previous, but uses 64-bit values.
|
||
14 years ago
|
INLINE upb_decoderet upb_vdecode_branch64(const char *p) {
|
||
14 years ago
|
uint64_t val;
|
||
|
uint64_t b;
|
||
|
upb_decoderet r = {(void*)0, 0};
|
||
|
b = *(p++); val = (b & 0x7f) ; if(!(b & 0x80)) goto done;
|
||
|
b = *(p++); val |= (b & 0x7f) << 7; if(!(b & 0x80)) goto done;
|
||
|
b = *(p++); val |= (b & 0x7f) << 14; if(!(b & 0x80)) goto done;
|
||
|
b = *(p++); val |= (b & 0x7f) << 21; if(!(b & 0x80)) goto done;
|
||
|
b = *(p++); val |= (b & 0x7f) << 28; if(!(b & 0x80)) goto done;
|
||
|
b = *(p++); val |= (b & 0x7f) << 35; if(!(b & 0x80)) goto done;
|
||
|
b = *(p++); val |= (b & 0x7f) << 42; if(!(b & 0x80)) goto done;
|
||
|
b = *(p++); val |= (b & 0x7f) << 49; if(!(b & 0x80)) goto done;
|
||
|
b = *(p++); val |= (b & 0x7f) << 56; if(!(b & 0x80)) goto done;
|
||
|
b = *(p++); val |= (b & 0x7f) << 63; if(!(b & 0x80)) goto done;
|
||
|
return r;
|
||
|
|
||
|
done:
|
||
|
r.val = val;
|
||
|
r.p = p;
|
||
|
return r;
|
||
|
}
|
||
|
|
||
14 years ago
|
// Decodes a varint of at most 8 bytes without branching (except for error).
|
||
14 years ago
|
upb_decoderet upb_vdecode_max8_wright(upb_decoderet r);
|
||
14 years ago
|
|
||
14 years ago
|
// Another implementation of the previous.
|
||
14 years ago
|
upb_decoderet upb_vdecode_max8_massimino(upb_decoderet r);
|
||
14 years ago
|
|
||
14 years ago
|
// Template for a function that checks the first two bytes with branching
|
||
|
// and dispatches 2-10 bytes with a separate function.
|
||
14 years ago
|
#define UPB_VARINT_DECODER_CHECK2(name, decode_max8_function) \
|
||
|
INLINE upb_decoderet upb_vdecode_check2_ ## name(const char *_p) { \
|
||
|
uint8_t *p = (uint8_t*)_p; \
|
||
|
if ((*p & 0x80) == 0) { upb_decoderet r = {_p + 1, *p & 0x7f}; return r; } \
|
||
|
upb_decoderet r = {_p + 2, (*p & 0x7f) | ((*(p + 1) & 0x7f) << 7)}; \
|
||
|
if ((*(p + 1) & 0x80) == 0) return r; \
|
||
|
return decode_max8_function(r); \
|
||
14 years ago
|
}
|
||
|
|
||
|
UPB_VARINT_DECODER_CHECK2(wright, upb_vdecode_max8_wright);
|
||
|
UPB_VARINT_DECODER_CHECK2(massimino, upb_vdecode_max8_massimino);
|
||
|
#undef UPB_VARINT_DECODER_CHECK2
|
||
|
|
||
|
// Our canonical functions for decoding varints, based on the currently
|
||
|
// favored best-performing implementations.
|
||
|
INLINE upb_decoderet upb_vdecode_fast(const char *p) {
|
||
14 years ago
|
// Use nobranch2 on 64-bit, branch32 on 32-bit.
|
||
|
if (sizeof(long) == 8)
|
||
14 years ago
|
return upb_vdecode_check2_massimino(p);
|
||
14 years ago
|
else
|
||
14 years ago
|
return upb_vdecode_branch32(p);
|
||
|
}
|
||
|
|
||
|
INLINE upb_decoderet upb_vdecode_max8_fast(upb_decoderet r) {
|
||
|
return upb_vdecode_max8_massimino(r);
|
||
14 years ago
|
}
|
||
14 years ago
|
|
||
14 years ago
|
|
||
|
/* Encoding *******************************************************************/
|
||
|
|
||
|
INLINE size_t upb_value_size(uint64_t val) {
|
||
|
#ifdef __GNUC__
|
||
|
int high_bit = 63 - __builtin_clzll(val); // 0-based, undef if val == 0.
|
||
|
#else
|
||
|
int high_bit = 0;
|
||
|
uint64_t tmp = val;
|
||
|
while(tmp >>= 1) high_bit++;
|
||
|
#endif
|
||
|
return val == 0 ? 1 : high_bit / 8 + 1;
|
||
|
}
|
||
|
|
||
14 years ago
|
// Encodes a 32-bit varint, *not* sign-extended.
|
||
|
INLINE uint64_t upb_vencode32(uint32_t val) {
|
||
14 years ago
|
uint64_t ret = 0;
|
||
|
for (int bitpos = 0; val; bitpos+=8, val >>=7) {
|
||
|
if (bitpos > 0) ret |= (1 << (bitpos-1));
|
||
|
ret |= (val & 0x7f) << bitpos;
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
|
||
14 years ago
|
#ifdef __cplusplus
|
||
|
} /* extern "C" */
|
||
|
#endif
|
||
|
|
||
|
#endif /* UPB_VARINT_DECODER_H_ */
|