From: Willy Tarreau Date: Fri, 23 Aug 2019 17:02:26 +0000 (+0200) Subject: MINOR: tools: add a function varint_bytes() to report the size of a varint X-Git-Tag: v2.1-dev2~169 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4d589e719ba0f7c2421dbb98208de51c3e1cee1d;p=thirdparty%2Fhaproxy.git MINOR: tools: add a function varint_bytes() to report the size of a varint It will sometimes be useful to encode varints to know the output size in advance. Two versions are provided, one inline using a switch/case construct which will be trivial for use with constants (and will be very fast albeit huge) and one function iterating on the number which is 5 times smaller, for use with variables. --- diff --git a/include/common/standard.h b/include/common/standard.h index f0167d31aa..0b8a327266 100644 --- a/include/common/standard.h +++ b/include/common/standard.h @@ -201,6 +201,27 @@ static inline const char *LIM2A(unsigned long n, const char *alt) return ret; } +/* returns the number of bytes needed to encode as a varint. Be careful, use + * it only with constants as it generates a large code (typ. 180 bytes). Use the + * varint_bytes() version instead in case of doubt. + */ +int varint_bytes(uint64_t v); +static inline int __varint_bytes(uint64_t v) +{ + switch (v) { + case 0x0000000000000000 ... 0x00000000000000ef: return 1; + case 0x00000000000000f0 ... 0x00000000000008ef: return 2; + case 0x00000000000008f0 ... 0x00000000000408ef: return 3; + case 0x00000000000408f0 ... 0x00000000020408ef: return 4; + case 0x00000000020408f0 ... 0x00000001020408ef: return 5; + case 0x00000001020408f0 ... 0x00000081020408ef: return 6; + case 0x00000081020408f0 ... 0x00004081020408ef: return 7; + case 0x00004081020408f0 ... 0x00204081020408ef: return 8; + case 0x00204081020408f0 ... 0x10204081020408ef: return 9; + default: return 10; + } +} + /* Encode the integer into a varint (variable-length integer). The encoded * value is copied in <*buf>. Here is the encoding format: * diff --git a/src/standard.c b/src/standard.c index 717c14a946..08a2c0d46e 100644 --- a/src/standard.c +++ b/src/standard.c @@ -4340,6 +4340,26 @@ int parse_dotted_uints(const char *str, unsigned int **nums, size_t *sz) return 1; } + +/* returns the number of bytes needed to encode as a varint. An inline + * version exists for use with constants (__varint_bytes()). + */ +int varint_bytes(uint64_t v) +{ + int len = 1; + + if (v >= 240) { + v = (v - 240) >> 4; + while (1) { + len++; + if (v < 128) + break; + v = (v - 128) >> 7; + } + } + return len; +} + /* do nothing, just a placeholder for debugging calls, the real one is in trace.c */ #ifndef USE_OBSOLETE_LINKER __attribute__((weak,format(printf, 1, 2)))