mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-29 17:51:22 +02:00
REORG: include: move integer manipulation functions from standard.h to intops.h
There are quite a number of integer manipulation functions defined in standard.h, which is one of the reasons why standard.h is included from many places and participates to the dependencies loop. Let's just have a new file, intops.h to place all these operations. These are a few bitops, 32/64 bit mul/div/rotate, integer parsing and encoding (including varints), the full avalanche hash function, and the my_htonll/my_ntohll functions. For now no new C file was created for these yet.
This commit is contained in:
parent
92b4f1372e
commit
aea4635c38
@ -38,6 +38,7 @@
|
|||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <haproxy/api.h>
|
#include <haproxy/api.h>
|
||||||
|
#include <haproxy/intops.h>
|
||||||
#include <common/chunk.h>
|
#include <common/chunk.h>
|
||||||
#include <common/namespace.h>
|
#include <common/namespace.h>
|
||||||
#include <import/eb32tree.h>
|
#include <import/eb32tree.h>
|
||||||
@ -75,26 +76,6 @@
|
|||||||
/* return the largest possible integer of type <ret>, with all bits set */
|
/* return the largest possible integer of type <ret>, with all bits set */
|
||||||
#define MAX_RANGE(ret) (~(typeof(ret))0)
|
#define MAX_RANGE(ret) (~(typeof(ret))0)
|
||||||
|
|
||||||
/* rotate left a 64-bit integer by <bits:[0-5]> bits */
|
|
||||||
static inline uint64_t rotl64(uint64_t v, uint8_t bits)
|
|
||||||
{
|
|
||||||
#if !defined(__ARM_ARCH_8A) && !defined(__x86_64__)
|
|
||||||
bits &= 63;
|
|
||||||
#endif
|
|
||||||
v = (v << bits) | (v >> (-bits & 63));
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* rotate right a 64-bit integer by <bits:[0-5]> bits */
|
|
||||||
static inline uint64_t rotr64(uint64_t v, uint8_t bits)
|
|
||||||
{
|
|
||||||
#if !defined(__ARM_ARCH_8A) && !defined(__x86_64__)
|
|
||||||
bits &= 63;
|
|
||||||
#endif
|
|
||||||
v = (v >> bits) | (v << (-bits & 63));
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* DEFNULL() returns either the argument as-is, or NULL if absent. This is for
|
/* DEFNULL() returns either the argument as-is, or NULL if absent. This is for
|
||||||
* use in macros arguments.
|
* use in macros arguments.
|
||||||
*/
|
*/
|
||||||
@ -241,104 +222,6 @@ static inline const char *LIM2A(unsigned long n, const char *alt)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns the number of bytes needed to encode <v> 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 <i> into a varint (variable-length integer). The encoded
|
|
||||||
* value is copied in <*buf>. Here is the encoding format:
|
|
||||||
*
|
|
||||||
* 0 <= X < 240 : 1 byte (7.875 bits) [ XXXX XXXX ]
|
|
||||||
* 240 <= X < 2288 : 2 bytes (11 bits) [ 1111 XXXX ] [ 0XXX XXXX ]
|
|
||||||
* 2288 <= X < 264432 : 3 bytes (18 bits) [ 1111 XXXX ] [ 1XXX XXXX ] [ 0XXX XXXX ]
|
|
||||||
* 264432 <= X < 33818864 : 4 bytes (25 bits) [ 1111 XXXX ] [ 1XXX XXXX ]*2 [ 0XXX XXXX ]
|
|
||||||
* 33818864 <= X < 4328786160 : 5 bytes (32 bits) [ 1111 XXXX ] [ 1XXX XXXX ]*3 [ 0XXX XXXX ]
|
|
||||||
* ...
|
|
||||||
*
|
|
||||||
* On success, it returns the number of written bytes and <*buf> is moved after
|
|
||||||
* the encoded value. Otherwise, it returns -1. */
|
|
||||||
static inline int
|
|
||||||
encode_varint(uint64_t i, char **buf, char *end)
|
|
||||||
{
|
|
||||||
unsigned char *p = (unsigned char *)*buf;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (p >= (unsigned char *)end)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (i < 240) {
|
|
||||||
*p++ = i;
|
|
||||||
*buf = (char *)p;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
*p++ = (unsigned char)i | 240;
|
|
||||||
i = (i - 240) >> 4;
|
|
||||||
while (i >= 128) {
|
|
||||||
if (p >= (unsigned char *)end)
|
|
||||||
return -1;
|
|
||||||
*p++ = (unsigned char)i | 128;
|
|
||||||
i = (i - 128) >> 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p >= (unsigned char *)end)
|
|
||||||
return -1;
|
|
||||||
*p++ = (unsigned char)i;
|
|
||||||
|
|
||||||
r = ((char *)p - *buf);
|
|
||||||
*buf = (char *)p;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Decode a varint from <*buf> and save the decoded value in <*i>. See
|
|
||||||
* 'spoe_encode_varint' for details about varint.
|
|
||||||
* On success, it returns the number of read bytes and <*buf> is moved after the
|
|
||||||
* varint. Otherwise, it returns -1. */
|
|
||||||
static inline int
|
|
||||||
decode_varint(char **buf, char *end, uint64_t *i)
|
|
||||||
{
|
|
||||||
unsigned char *p = (unsigned char *)*buf;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (p >= (unsigned char *)end)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
*i = *p++;
|
|
||||||
if (*i < 240) {
|
|
||||||
*buf = (char *)p;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = 4;
|
|
||||||
do {
|
|
||||||
if (p >= (unsigned char *)end)
|
|
||||||
return -1;
|
|
||||||
*i += (uint64_t)*p << r;
|
|
||||||
r += 7;
|
|
||||||
} while (*p++ >= 128);
|
|
||||||
|
|
||||||
r = ((char *)p - *buf);
|
|
||||||
*buf = (char *)p;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* returns a locally allocated string containing the quoted encoding of the
|
/* returns a locally allocated string containing the quoted encoding of the
|
||||||
* input string. The output may be truncated to QSTR_SIZE chars, but it is
|
* input string. The output may be truncated to QSTR_SIZE chars, but it is
|
||||||
* guaranteed that the string will always be properly terminated. Quotes are
|
* guaranteed that the string will always be properly terminated. Quotes are
|
||||||
@ -367,24 +250,6 @@ static inline const char *cstr(const char *str)
|
|||||||
*/
|
*/
|
||||||
extern int ishex(char s);
|
extern int ishex(char s);
|
||||||
|
|
||||||
/*
|
|
||||||
* Return integer equivalent of character <c> for a hex digit (0-9, a-f, A-F),
|
|
||||||
* otherwise -1. This compact form helps gcc produce efficient code.
|
|
||||||
*/
|
|
||||||
static inline int hex2i(int c)
|
|
||||||
{
|
|
||||||
if ((unsigned char)(c -= '0') > 9) {
|
|
||||||
if ((unsigned char)(c -= 'A' - '0') > 5 &&
|
|
||||||
(unsigned char)(c -= 'a' - 'A') > 5)
|
|
||||||
c = -11;
|
|
||||||
c += 10;
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* rounds <i> down to the closest value having max 2 digits */
|
|
||||||
unsigned int round_2dig(unsigned int i);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Checks <name> for invalid characters. Valid chars are [A-Za-z0-9_:.-]. If an
|
* Checks <name> for invalid characters. Valid chars are [A-Za-z0-9_:.-]. If an
|
||||||
* invalid character is found, a pointer to it is returned. If everything is
|
* invalid character is found, a pointer to it is returned. If everything is
|
||||||
@ -625,101 +490,6 @@ static inline const char *csv_enc(const char *str, int quote,
|
|||||||
*/
|
*/
|
||||||
int url_decode(char *string, int in_form);
|
int url_decode(char *string, int in_form);
|
||||||
|
|
||||||
/* This one is 6 times faster than strtoul() on athlon, but does
|
|
||||||
* no check at all.
|
|
||||||
*/
|
|
||||||
static inline unsigned int __str2ui(const char *s)
|
|
||||||
{
|
|
||||||
unsigned int i = 0;
|
|
||||||
while (*s) {
|
|
||||||
i = i * 10 - '0';
|
|
||||||
i += (unsigned char)*s++;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This one is 5 times faster than strtoul() on athlon with checks.
|
|
||||||
* It returns the value of the number composed of all valid digits read.
|
|
||||||
*/
|
|
||||||
static inline unsigned int __str2uic(const char *s)
|
|
||||||
{
|
|
||||||
unsigned int i = 0;
|
|
||||||
unsigned int j;
|
|
||||||
while (1) {
|
|
||||||
j = (*s++) - '0';
|
|
||||||
if (j > 9)
|
|
||||||
break;
|
|
||||||
i *= 10;
|
|
||||||
i += j;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This one is 28 times faster than strtoul() on athlon, but does
|
|
||||||
* no check at all!
|
|
||||||
*/
|
|
||||||
static inline unsigned int __strl2ui(const char *s, int len)
|
|
||||||
{
|
|
||||||
unsigned int i = 0;
|
|
||||||
while (len-- > 0) {
|
|
||||||
i = i * 10 - '0';
|
|
||||||
i += (unsigned char)*s++;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This one is 7 times faster than strtoul() on athlon with checks.
|
|
||||||
* It returns the value of the number composed of all valid digits read.
|
|
||||||
*/
|
|
||||||
static inline unsigned int __strl2uic(const char *s, int len)
|
|
||||||
{
|
|
||||||
unsigned int i = 0;
|
|
||||||
unsigned int j, k;
|
|
||||||
|
|
||||||
while (len-- > 0) {
|
|
||||||
j = (*s++) - '0';
|
|
||||||
k = i * 10;
|
|
||||||
if (j > 9)
|
|
||||||
break;
|
|
||||||
i = k + j;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This function reads an unsigned integer from the string pointed to by <s>
|
|
||||||
* and returns it. The <s> pointer is adjusted to point to the first unread
|
|
||||||
* char. The function automatically stops at <end>.
|
|
||||||
*/
|
|
||||||
static inline unsigned int __read_uint(const char **s, const char *end)
|
|
||||||
{
|
|
||||||
const char *ptr = *s;
|
|
||||||
unsigned int i = 0;
|
|
||||||
unsigned int j, k;
|
|
||||||
|
|
||||||
while (ptr < end) {
|
|
||||||
j = *ptr - '0';
|
|
||||||
k = i * 10;
|
|
||||||
if (j > 9)
|
|
||||||
break;
|
|
||||||
i = k + j;
|
|
||||||
ptr++;
|
|
||||||
}
|
|
||||||
*s = ptr;
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long long int read_uint64(const char **s, const char *end);
|
|
||||||
long long int read_int64(const char **s, const char *end);
|
|
||||||
|
|
||||||
extern unsigned int str2ui(const char *s);
|
|
||||||
extern unsigned int str2uic(const char *s);
|
|
||||||
extern unsigned int strl2ui(const char *s, int len);
|
|
||||||
extern unsigned int strl2uic(const char *s, int len);
|
|
||||||
extern int strl2ic(const char *s, int len);
|
|
||||||
extern int strl2irc(const char *s, int len, int *ret);
|
|
||||||
extern int strl2llrc(const char *s, int len, long long *ret);
|
|
||||||
extern int strl2llrc_dotted(const char *text, int len, long long *ret);
|
|
||||||
extern unsigned int read_uint(const char **s, const char *end);
|
|
||||||
unsigned int inetaddr_host(const char *text);
|
unsigned int inetaddr_host(const char *text);
|
||||||
unsigned int inetaddr_host_lim(const char *text, const char *stop);
|
unsigned int inetaddr_host_lim(const char *text, const char *stop);
|
||||||
unsigned int inetaddr_host_lim_ret(char *text, char *stop, char **ret);
|
unsigned int inetaddr_host_lim_ret(char *text, char *stop, char **ret);
|
||||||
@ -836,168 +606,6 @@ extern const char *parse_size_err(const char *text, unsigned *ret);
|
|||||||
#define HOUR (60 * MINUTE)
|
#define HOUR (60 * MINUTE)
|
||||||
#define DAY (24 * HOUR)
|
#define DAY (24 * HOUR)
|
||||||
|
|
||||||
/* Multiply the two 32-bit operands and shift the 64-bit result right 32 bits.
|
|
||||||
* This is used to compute fixed ratios by setting one of the operands to
|
|
||||||
* (2^32*ratio).
|
|
||||||
*/
|
|
||||||
static inline unsigned int mul32hi(unsigned int a, unsigned int b)
|
|
||||||
{
|
|
||||||
return ((unsigned long long)a * b) >> 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* gcc does not know when it can safely divide 64 bits by 32 bits. Use this
|
|
||||||
* function when you know for sure that the result fits in 32 bits, because
|
|
||||||
* it is optimal on x86 and on 64bit processors.
|
|
||||||
*/
|
|
||||||
static inline unsigned int div64_32(unsigned long long o1, unsigned int o2)
|
|
||||||
{
|
|
||||||
unsigned long long result;
|
|
||||||
#ifdef __i386__
|
|
||||||
asm("divl %2"
|
|
||||||
: "=A" (result)
|
|
||||||
: "A"(o1), "rm"(o2));
|
|
||||||
#else
|
|
||||||
result = o1 / o2;
|
|
||||||
#endif
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Simple popcountl implementation. It returns the number of ones in a word.
|
|
||||||
* Described here : https://graphics.stanford.edu/~seander/bithacks.html
|
|
||||||
*/
|
|
||||||
static inline unsigned int my_popcountl(unsigned long a)
|
|
||||||
{
|
|
||||||
a = a - ((a >> 1) & ~0UL/3);
|
|
||||||
a = (a & ~0UL/15*3) + ((a >> 2) & ~0UL/15*3);
|
|
||||||
a = (a + (a >> 4)) & ~0UL/255*15;
|
|
||||||
return (unsigned long)(a * (~0UL/255)) >> (sizeof(unsigned long) - 1) * 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* returns non-zero if <a> has at least 2 bits set */
|
|
||||||
static inline unsigned long atleast2(unsigned long a)
|
|
||||||
{
|
|
||||||
return a & (a - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Simple ffs implementation. It returns the position of the lowest bit set to
|
|
||||||
* one, starting at 1. It is illegal to call it with a==0 (undefined result).
|
|
||||||
*/
|
|
||||||
static inline unsigned int my_ffsl(unsigned long a)
|
|
||||||
{
|
|
||||||
unsigned long cnt;
|
|
||||||
|
|
||||||
#if defined(__x86_64__)
|
|
||||||
__asm__("bsf %1,%0\n" : "=r" (cnt) : "rm" (a));
|
|
||||||
cnt++;
|
|
||||||
#else
|
|
||||||
|
|
||||||
cnt = 1;
|
|
||||||
#if LONG_MAX > 0x7FFFFFFFL /* 64bits */
|
|
||||||
if (!(a & 0xFFFFFFFFUL)) {
|
|
||||||
a >>= 32;
|
|
||||||
cnt += 32;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (!(a & 0XFFFFU)) {
|
|
||||||
a >>= 16;
|
|
||||||
cnt += 16;
|
|
||||||
}
|
|
||||||
if (!(a & 0XFF)) {
|
|
||||||
a >>= 8;
|
|
||||||
cnt += 8;
|
|
||||||
}
|
|
||||||
if (!(a & 0xf)) {
|
|
||||||
a >>= 4;
|
|
||||||
cnt += 4;
|
|
||||||
}
|
|
||||||
if (!(a & 0x3)) {
|
|
||||||
a >>= 2;
|
|
||||||
cnt += 2;
|
|
||||||
}
|
|
||||||
if (!(a & 0x1)) {
|
|
||||||
cnt += 1;
|
|
||||||
}
|
|
||||||
#endif /* x86_64 */
|
|
||||||
|
|
||||||
return cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Simple fls implementation. It returns the position of the highest bit set to
|
|
||||||
* one, starting at 1. It is illegal to call it with a==0 (undefined result).
|
|
||||||
*/
|
|
||||||
static inline unsigned int my_flsl(unsigned long a)
|
|
||||||
{
|
|
||||||
unsigned long cnt;
|
|
||||||
|
|
||||||
#if defined(__x86_64__)
|
|
||||||
__asm__("bsr %1,%0\n" : "=r" (cnt) : "rm" (a));
|
|
||||||
cnt++;
|
|
||||||
#else
|
|
||||||
|
|
||||||
cnt = 1;
|
|
||||||
#if LONG_MAX > 0x7FFFFFFFUL /* 64bits */
|
|
||||||
if (a & 0xFFFFFFFF00000000UL) {
|
|
||||||
a >>= 32;
|
|
||||||
cnt += 32;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (a & 0XFFFF0000U) {
|
|
||||||
a >>= 16;
|
|
||||||
cnt += 16;
|
|
||||||
}
|
|
||||||
if (a & 0XFF00) {
|
|
||||||
a >>= 8;
|
|
||||||
cnt += 8;
|
|
||||||
}
|
|
||||||
if (a & 0xf0) {
|
|
||||||
a >>= 4;
|
|
||||||
cnt += 4;
|
|
||||||
}
|
|
||||||
if (a & 0xc) {
|
|
||||||
a >>= 2;
|
|
||||||
cnt += 2;
|
|
||||||
}
|
|
||||||
if (a & 0x2) {
|
|
||||||
cnt += 1;
|
|
||||||
}
|
|
||||||
#endif /* x86_64 */
|
|
||||||
|
|
||||||
return cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Build a word with the <bits> lower bits set (reverse of my_popcountl) */
|
|
||||||
static inline unsigned long nbits(int bits)
|
|
||||||
{
|
|
||||||
if (--bits < 0)
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return (2UL << bits) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* sets bit <bit> into map <map>, which must be long-aligned */
|
|
||||||
static inline void ha_bit_set(unsigned long bit, long *map)
|
|
||||||
{
|
|
||||||
map[bit / (8 * sizeof(*map))] |= 1UL << (bit & (8 * sizeof(*map) - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* clears bit <bit> from map <map>, which must be long-aligned */
|
|
||||||
static inline void ha_bit_clr(unsigned long bit, long *map)
|
|
||||||
{
|
|
||||||
map[bit / (8 * sizeof(*map))] &= ~(1UL << (bit & (8 * sizeof(*map) - 1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* flips bit <bit> from map <map>, which must be long-aligned */
|
|
||||||
static inline void ha_bit_flip(unsigned long bit, long *map)
|
|
||||||
{
|
|
||||||
map[bit / (8 * sizeof(*map))] ^= 1UL << (bit & (8 * sizeof(*map) - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* returns non-zero if bit <bit> from map <map> is set, otherwise 0 */
|
|
||||||
static inline int ha_bit_test(unsigned long bit, const long *map)
|
|
||||||
{
|
|
||||||
return !!(map[bit / (8 * sizeof(*map))] & 1UL << (bit & (8 * sizeof(*map) - 1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse binary string written in hexadecimal (source) and store the decoded
|
* Parse binary string written in hexadecimal (source) and store the decoded
|
||||||
* result into binstr and set binstrlen to the length of binstr. Memory for
|
* result into binstr and set binstrlen to the length of binstr. Memory for
|
||||||
@ -1062,44 +670,6 @@ const char *quote_arg(const char *ptr);
|
|||||||
/* returns an operator among STD_OP_* for string <str> or < 0 if unknown */
|
/* returns an operator among STD_OP_* for string <str> or < 0 if unknown */
|
||||||
int get_std_op(const char *str);
|
int get_std_op(const char *str);
|
||||||
|
|
||||||
/* hash a 32-bit integer to another 32-bit integer */
|
|
||||||
extern unsigned int full_hash(unsigned int a);
|
|
||||||
static inline unsigned int __full_hash(unsigned int a)
|
|
||||||
{
|
|
||||||
/* This function is one of Bob Jenkins' full avalanche hashing
|
|
||||||
* functions, which when provides quite a good distribution for little
|
|
||||||
* input variations. The result is quite suited to fit over a 32-bit
|
|
||||||
* space with enough variations so that a randomly picked number falls
|
|
||||||
* equally before any server position.
|
|
||||||
* Check http://burtleburtle.net/bob/hash/integer.html for more info.
|
|
||||||
*/
|
|
||||||
a = (a+0x7ed55d16) + (a<<12);
|
|
||||||
a = (a^0xc761c23c) ^ (a>>19);
|
|
||||||
a = (a+0x165667b1) + (a<<5);
|
|
||||||
a = (a+0xd3a2646c) ^ (a<<9);
|
|
||||||
a = (a+0xfd7046c5) + (a<<3);
|
|
||||||
a = (a^0xb55a4f09) ^ (a>>16);
|
|
||||||
|
|
||||||
/* ensure values are better spread all around the tree by multiplying
|
|
||||||
* by a large prime close to 3/4 of the tree.
|
|
||||||
*/
|
|
||||||
return a * 3221225473U;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return the bit position in mask <m> of the nth bit set of rank <r>, between
|
|
||||||
* 0 and LONGBITS-1 included, starting from the left. For example ranks 0,1,2,3
|
|
||||||
* for mask 0x55 will be 6, 4, 2 and 0 respectively. This algorithm is based on
|
|
||||||
* a popcount variant and is described here :
|
|
||||||
* https://graphics.stanford.edu/~seander/bithacks.html
|
|
||||||
*/
|
|
||||||
unsigned int mask_find_rank_bit(unsigned int r, unsigned long m);
|
|
||||||
unsigned int mask_find_rank_bit_fast(unsigned int r, unsigned long m,
|
|
||||||
unsigned long a, unsigned long b,
|
|
||||||
unsigned long c, unsigned long d);
|
|
||||||
void mask_prep_rank_map(unsigned long m,
|
|
||||||
unsigned long *a, unsigned long *b,
|
|
||||||
unsigned long *c, unsigned long *d);
|
|
||||||
|
|
||||||
/* sets the address family to AF_UNSPEC so that is_addr() does not match */
|
/* sets the address family to AF_UNSPEC so that is_addr() does not match */
|
||||||
static inline void clear_addr(struct sockaddr_storage *addr)
|
static inline void clear_addr(struct sockaddr_storage *addr)
|
||||||
{
|
{
|
||||||
@ -1451,39 +1021,6 @@ static inline unsigned char utf8_return_length(unsigned char code)
|
|||||||
return code & 0x0f;
|
return code & 0x0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Turns 64-bit value <a> from host byte order to network byte order.
|
|
||||||
* The principle consists in letting the compiler detect we're playing
|
|
||||||
* with a union and simplify most or all operations. The asm-optimized
|
|
||||||
* htonl() version involving bswap (x86) / rev (arm) / other is a single
|
|
||||||
* operation on little endian, or a NOP on big-endian. In both cases,
|
|
||||||
* this lets the compiler "see" that we're rebuilding a 64-bit word from
|
|
||||||
* two 32-bit quantities that fit into a 32-bit register. In big endian,
|
|
||||||
* the whole code is optimized out. In little endian, with a decent compiler,
|
|
||||||
* a few bswap and 2 shifts are left, which is the minimum acceptable.
|
|
||||||
*/
|
|
||||||
static inline unsigned long long my_htonll(unsigned long long a)
|
|
||||||
{
|
|
||||||
#if defined(__x86_64__)
|
|
||||||
__asm__ volatile("bswap %0" : "=r"(a) : "0"(a));
|
|
||||||
return a;
|
|
||||||
#else
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
unsigned int w1;
|
|
||||||
unsigned int w2;
|
|
||||||
} by32;
|
|
||||||
unsigned long long by64;
|
|
||||||
} w = { .by64 = a };
|
|
||||||
return ((unsigned long long)htonl(w.by32.w1) << 32) | htonl(w.by32.w2);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Turns 64-bit value <a> from network byte order to host byte order. */
|
|
||||||
static inline unsigned long long my_ntohll(unsigned long long a)
|
|
||||||
{
|
|
||||||
return my_htonll(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* returns a 64-bit a timestamp with the finest resolution available. The
|
/* returns a 64-bit a timestamp with the finest resolution available. The
|
||||||
* unit is intentionally not specified. It's mostly used to compare dates.
|
* unit is intentionally not specified. It's mostly used to compare dates.
|
||||||
*/
|
*/
|
||||||
|
494
include/haproxy/intops.h
Normal file
494
include/haproxy/intops.h
Normal file
@ -0,0 +1,494 @@
|
|||||||
|
/*
|
||||||
|
* include/haproxy/intops.h
|
||||||
|
* Functions for integer operations.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 Willy Tarreau - w@1wt.eu
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation, version 2.1
|
||||||
|
* exclusively.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _HAPROXY_INTOPS_H
|
||||||
|
#define _HAPROXY_INTOPS_H
|
||||||
|
|
||||||
|
#include <haproxy/api.h>
|
||||||
|
|
||||||
|
/* exported functions, mostly integer parsing */
|
||||||
|
/* rounds <i> down to the closest value having max 2 digits */
|
||||||
|
unsigned int round_2dig(unsigned int i);
|
||||||
|
unsigned int full_hash(unsigned int a);
|
||||||
|
int varint_bytes(uint64_t v);
|
||||||
|
unsigned int read_uint(const char **s, const char *end);
|
||||||
|
long long read_int64(const char **s, const char *end);
|
||||||
|
unsigned long long read_uint64(const char **s, const char *end);
|
||||||
|
unsigned int str2ui(const char *s);
|
||||||
|
unsigned int str2uic(const char *s);
|
||||||
|
unsigned int strl2ui(const char *s, int len);
|
||||||
|
unsigned int strl2uic(const char *s, int len);
|
||||||
|
int strl2ic(const char *s, int len);
|
||||||
|
int strl2irc(const char *s, int len, int *ret);
|
||||||
|
int strl2llrc(const char *s, int len, long long *ret);
|
||||||
|
int strl2llrc_dotted(const char *text, int len, long long *ret);
|
||||||
|
unsigned int mask_find_rank_bit(unsigned int r, unsigned long m);
|
||||||
|
unsigned int mask_find_rank_bit_fast(unsigned int r, unsigned long m,
|
||||||
|
unsigned long a, unsigned long b,
|
||||||
|
unsigned long c, unsigned long d);
|
||||||
|
void mask_prep_rank_map(unsigned long m,
|
||||||
|
unsigned long *a, unsigned long *b,
|
||||||
|
unsigned long *c, unsigned long *d);
|
||||||
|
|
||||||
|
|
||||||
|
/* Multiply the two 32-bit operands and shift the 64-bit result right 32 bits.
|
||||||
|
* This is used to compute fixed ratios by setting one of the operands to
|
||||||
|
* (2^32*ratio).
|
||||||
|
*/
|
||||||
|
static inline unsigned int mul32hi(unsigned int a, unsigned int b)
|
||||||
|
{
|
||||||
|
return ((unsigned long long)a * b) >> 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* gcc does not know when it can safely divide 64 bits by 32 bits. Use this
|
||||||
|
* function when you know for sure that the result fits in 32 bits, because
|
||||||
|
* it is optimal on x86 and on 64bit processors.
|
||||||
|
*/
|
||||||
|
static inline unsigned int div64_32(unsigned long long o1, unsigned int o2)
|
||||||
|
{
|
||||||
|
unsigned long long result;
|
||||||
|
#ifdef __i386__
|
||||||
|
asm("divl %2"
|
||||||
|
: "=A" (result)
|
||||||
|
: "A"(o1), "rm"(o2));
|
||||||
|
#else
|
||||||
|
result = o1 / o2;
|
||||||
|
#endif
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* rotate left a 64-bit integer by <bits:[0-5]> bits */
|
||||||
|
static inline uint64_t rotl64(uint64_t v, uint8_t bits)
|
||||||
|
{
|
||||||
|
#if !defined(__ARM_ARCH_8A) && !defined(__x86_64__)
|
||||||
|
bits &= 63;
|
||||||
|
#endif
|
||||||
|
v = (v << bits) | (v >> (-bits & 63));
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* rotate right a 64-bit integer by <bits:[0-5]> bits */
|
||||||
|
static inline uint64_t rotr64(uint64_t v, uint8_t bits)
|
||||||
|
{
|
||||||
|
#if !defined(__ARM_ARCH_8A) && !defined(__x86_64__)
|
||||||
|
bits &= 63;
|
||||||
|
#endif
|
||||||
|
v = (v >> bits) | (v << (-bits & 63));
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Simple popcountl implementation. It returns the number of ones in a word.
|
||||||
|
* Described here : https://graphics.stanford.edu/~seander/bithacks.html
|
||||||
|
*/
|
||||||
|
static inline unsigned int my_popcountl(unsigned long a)
|
||||||
|
{
|
||||||
|
a = a - ((a >> 1) & ~0UL/3);
|
||||||
|
a = (a & ~0UL/15*3) + ((a >> 2) & ~0UL/15*3);
|
||||||
|
a = (a + (a >> 4)) & ~0UL/255*15;
|
||||||
|
return (unsigned long)(a * (~0UL/255)) >> (sizeof(unsigned long) - 1) * 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* returns non-zero if <a> has at least 2 bits set */
|
||||||
|
static inline unsigned long atleast2(unsigned long a)
|
||||||
|
{
|
||||||
|
return a & (a - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Simple ffs implementation. It returns the position of the lowest bit set to
|
||||||
|
* one, starting at 1. It is illegal to call it with a==0 (undefined result).
|
||||||
|
*/
|
||||||
|
static inline unsigned int my_ffsl(unsigned long a)
|
||||||
|
{
|
||||||
|
unsigned long cnt;
|
||||||
|
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
__asm__("bsf %1,%0\n" : "=r" (cnt) : "rm" (a));
|
||||||
|
cnt++;
|
||||||
|
#else
|
||||||
|
|
||||||
|
cnt = 1;
|
||||||
|
#if LONG_MAX > 0x7FFFFFFFL /* 64bits */
|
||||||
|
if (!(a & 0xFFFFFFFFUL)) {
|
||||||
|
a >>= 32;
|
||||||
|
cnt += 32;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!(a & 0XFFFFU)) {
|
||||||
|
a >>= 16;
|
||||||
|
cnt += 16;
|
||||||
|
}
|
||||||
|
if (!(a & 0XFF)) {
|
||||||
|
a >>= 8;
|
||||||
|
cnt += 8;
|
||||||
|
}
|
||||||
|
if (!(a & 0xf)) {
|
||||||
|
a >>= 4;
|
||||||
|
cnt += 4;
|
||||||
|
}
|
||||||
|
if (!(a & 0x3)) {
|
||||||
|
a >>= 2;
|
||||||
|
cnt += 2;
|
||||||
|
}
|
||||||
|
if (!(a & 0x1)) {
|
||||||
|
cnt += 1;
|
||||||
|
}
|
||||||
|
#endif /* x86_64 */
|
||||||
|
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Simple fls implementation. It returns the position of the highest bit set to
|
||||||
|
* one, starting at 1. It is illegal to call it with a==0 (undefined result).
|
||||||
|
*/
|
||||||
|
static inline unsigned int my_flsl(unsigned long a)
|
||||||
|
{
|
||||||
|
unsigned long cnt;
|
||||||
|
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
__asm__("bsr %1,%0\n" : "=r" (cnt) : "rm" (a));
|
||||||
|
cnt++;
|
||||||
|
#else
|
||||||
|
|
||||||
|
cnt = 1;
|
||||||
|
#if LONG_MAX > 0x7FFFFFFFUL /* 64bits */
|
||||||
|
if (a & 0xFFFFFFFF00000000UL) {
|
||||||
|
a >>= 32;
|
||||||
|
cnt += 32;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (a & 0XFFFF0000U) {
|
||||||
|
a >>= 16;
|
||||||
|
cnt += 16;
|
||||||
|
}
|
||||||
|
if (a & 0XFF00) {
|
||||||
|
a >>= 8;
|
||||||
|
cnt += 8;
|
||||||
|
}
|
||||||
|
if (a & 0xf0) {
|
||||||
|
a >>= 4;
|
||||||
|
cnt += 4;
|
||||||
|
}
|
||||||
|
if (a & 0xc) {
|
||||||
|
a >>= 2;
|
||||||
|
cnt += 2;
|
||||||
|
}
|
||||||
|
if (a & 0x2) {
|
||||||
|
cnt += 1;
|
||||||
|
}
|
||||||
|
#endif /* x86_64 */
|
||||||
|
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build a word with the <bits> lower bits set (reverse of my_popcountl) */
|
||||||
|
static inline unsigned long nbits(int bits)
|
||||||
|
{
|
||||||
|
if (--bits < 0)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return (2UL << bits) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Turns 64-bit value <a> from host byte order to network byte order.
|
||||||
|
* The principle consists in letting the compiler detect we're playing
|
||||||
|
* with a union and simplify most or all operations. The asm-optimized
|
||||||
|
* htonl() version involving bswap (x86) / rev (arm) / other is a single
|
||||||
|
* operation on little endian, or a NOP on big-endian. In both cases,
|
||||||
|
* this lets the compiler "see" that we're rebuilding a 64-bit word from
|
||||||
|
* two 32-bit quantities that fit into a 32-bit register. In big endian,
|
||||||
|
* the whole code is optimized out. In little endian, with a decent compiler,
|
||||||
|
* a few bswap and 2 shifts are left, which is the minimum acceptable.
|
||||||
|
*/
|
||||||
|
static inline unsigned long long my_htonll(unsigned long long a)
|
||||||
|
{
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
__asm__ volatile("bswap %0" : "=r"(a) : "0"(a));
|
||||||
|
return a;
|
||||||
|
#else
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
unsigned int w1;
|
||||||
|
unsigned int w2;
|
||||||
|
} by32;
|
||||||
|
unsigned long long by64;
|
||||||
|
} w = { .by64 = a };
|
||||||
|
return ((unsigned long long)htonl(w.by32.w1) << 32) | htonl(w.by32.w2);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Turns 64-bit value <a> from network byte order to host byte order. */
|
||||||
|
static inline unsigned long long my_ntohll(unsigned long long a)
|
||||||
|
{
|
||||||
|
return my_htonll(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sets bit <bit> into map <map>, which must be long-aligned */
|
||||||
|
static inline void ha_bit_set(unsigned long bit, long *map)
|
||||||
|
{
|
||||||
|
map[bit / (8 * sizeof(*map))] |= 1UL << (bit & (8 * sizeof(*map) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clears bit <bit> from map <map>, which must be long-aligned */
|
||||||
|
static inline void ha_bit_clr(unsigned long bit, long *map)
|
||||||
|
{
|
||||||
|
map[bit / (8 * sizeof(*map))] &= ~(1UL << (bit & (8 * sizeof(*map) - 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flips bit <bit> from map <map>, which must be long-aligned */
|
||||||
|
static inline void ha_bit_flip(unsigned long bit, long *map)
|
||||||
|
{
|
||||||
|
map[bit / (8 * sizeof(*map))] ^= 1UL << (bit & (8 * sizeof(*map) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* returns non-zero if bit <bit> from map <map> is set, otherwise 0 */
|
||||||
|
static inline int ha_bit_test(unsigned long bit, const long *map)
|
||||||
|
{
|
||||||
|
return !!(map[bit / (8 * sizeof(*map))] & 1UL << (bit & (8 * sizeof(*map) - 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* hash a 32-bit integer to another 32-bit integer. This code may be large when
|
||||||
|
* inlined, use full_hash() instead.
|
||||||
|
*/
|
||||||
|
static inline unsigned int __full_hash(unsigned int a)
|
||||||
|
{
|
||||||
|
/* This function is one of Bob Jenkins' full avalanche hashing
|
||||||
|
* functions, which when provides quite a good distribution for little
|
||||||
|
* input variations. The result is quite suited to fit over a 32-bit
|
||||||
|
* space with enough variations so that a randomly picked number falls
|
||||||
|
* equally before any server position.
|
||||||
|
* Check http://burtleburtle.net/bob/hash/integer.html for more info.
|
||||||
|
*/
|
||||||
|
a = (a+0x7ed55d16) + (a<<12);
|
||||||
|
a = (a^0xc761c23c) ^ (a>>19);
|
||||||
|
a = (a+0x165667b1) + (a<<5);
|
||||||
|
a = (a+0xd3a2646c) ^ (a<<9);
|
||||||
|
a = (a+0xfd7046c5) + (a<<3);
|
||||||
|
a = (a^0xb55a4f09) ^ (a>>16);
|
||||||
|
|
||||||
|
/* ensure values are better spread all around the tree by multiplying
|
||||||
|
* by a large prime close to 3/4 of the tree.
|
||||||
|
*/
|
||||||
|
return a * 3221225473U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return integer equivalent of character <c> for a hex digit (0-9, a-f, A-F),
|
||||||
|
* otherwise -1. This compact form helps gcc produce efficient code.
|
||||||
|
*/
|
||||||
|
static inline int hex2i(int c)
|
||||||
|
{
|
||||||
|
if ((unsigned char)(c -= '0') > 9) {
|
||||||
|
if ((unsigned char)(c -= 'A' - '0') > 5 &&
|
||||||
|
(unsigned char)(c -= 'a' - 'A') > 5)
|
||||||
|
c = -11;
|
||||||
|
c += 10;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This one is 6 times faster than strtoul() on athlon, but does
|
||||||
|
* no check at all.
|
||||||
|
*/
|
||||||
|
static inline unsigned int __str2ui(const char *s)
|
||||||
|
{
|
||||||
|
unsigned int i = 0;
|
||||||
|
while (*s) {
|
||||||
|
i = i * 10 - '0';
|
||||||
|
i += (unsigned char)*s++;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This one is 5 times faster than strtoul() on athlon with checks.
|
||||||
|
* It returns the value of the number composed of all valid digits read.
|
||||||
|
*/
|
||||||
|
static inline unsigned int __str2uic(const char *s)
|
||||||
|
{
|
||||||
|
unsigned int i = 0;
|
||||||
|
unsigned int j;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
j = (*s++) - '0';
|
||||||
|
if (j > 9)
|
||||||
|
break;
|
||||||
|
i *= 10;
|
||||||
|
i += j;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This one is 28 times faster than strtoul() on athlon, but does
|
||||||
|
* no check at all!
|
||||||
|
*/
|
||||||
|
static inline unsigned int __strl2ui(const char *s, int len)
|
||||||
|
{
|
||||||
|
unsigned int i = 0;
|
||||||
|
|
||||||
|
while (len-- > 0) {
|
||||||
|
i = i * 10 - '0';
|
||||||
|
i += (unsigned char)*s++;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This one is 7 times faster than strtoul() on athlon with checks.
|
||||||
|
* It returns the value of the number composed of all valid digits read.
|
||||||
|
*/
|
||||||
|
static inline unsigned int __strl2uic(const char *s, int len)
|
||||||
|
{
|
||||||
|
unsigned int i = 0;
|
||||||
|
unsigned int j, k;
|
||||||
|
|
||||||
|
while (len-- > 0) {
|
||||||
|
j = (*s++) - '0';
|
||||||
|
k = i * 10;
|
||||||
|
if (j > 9)
|
||||||
|
break;
|
||||||
|
i = k + j;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function reads an unsigned integer from the string pointed to by <s>
|
||||||
|
* and returns it. The <s> pointer is adjusted to point to the first unread
|
||||||
|
* char. The function automatically stops at <end>.
|
||||||
|
*/
|
||||||
|
static inline unsigned int __read_uint(const char **s, const char *end)
|
||||||
|
{
|
||||||
|
const char *ptr = *s;
|
||||||
|
unsigned int i = 0;
|
||||||
|
unsigned int j, k;
|
||||||
|
|
||||||
|
while (ptr < end) {
|
||||||
|
j = *ptr - '0';
|
||||||
|
k = i * 10;
|
||||||
|
if (j > 9)
|
||||||
|
break;
|
||||||
|
i = k + j;
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
*s = ptr;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* returns the number of bytes needed to encode <v> 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.
|
||||||
|
*/
|
||||||
|
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 <i> into a varint (variable-length integer). The encoded
|
||||||
|
* value is copied in <*buf>. Here is the encoding format:
|
||||||
|
*
|
||||||
|
* 0 <= X < 240 : 1 byte (7.875 bits) [ XXXX XXXX ]
|
||||||
|
* 240 <= X < 2288 : 2 bytes (11 bits) [ 1111 XXXX ] [ 0XXX XXXX ]
|
||||||
|
* 2288 <= X < 264432 : 3 bytes (18 bits) [ 1111 XXXX ] [ 1XXX XXXX ] [ 0XXX XXXX ]
|
||||||
|
* 264432 <= X < 33818864 : 4 bytes (25 bits) [ 1111 XXXX ] [ 1XXX XXXX ]*2 [ 0XXX XXXX ]
|
||||||
|
* 33818864 <= X < 4328786160 : 5 bytes (32 bits) [ 1111 XXXX ] [ 1XXX XXXX ]*3 [ 0XXX XXXX ]
|
||||||
|
* ...
|
||||||
|
*
|
||||||
|
* On success, it returns the number of written bytes and <*buf> is moved after
|
||||||
|
* the encoded value. Otherwise, it returns -1. */
|
||||||
|
static inline int encode_varint(uint64_t i, char **buf, char *end)
|
||||||
|
{
|
||||||
|
unsigned char *p = (unsigned char *)*buf;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (p >= (unsigned char *)end)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (i < 240) {
|
||||||
|
*p++ = i;
|
||||||
|
*buf = (char *)p;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*p++ = (unsigned char)i | 240;
|
||||||
|
i = (i - 240) >> 4;
|
||||||
|
while (i >= 128) {
|
||||||
|
if (p >= (unsigned char *)end)
|
||||||
|
return -1;
|
||||||
|
*p++ = (unsigned char)i | 128;
|
||||||
|
i = (i - 128) >> 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p >= (unsigned char *)end)
|
||||||
|
return -1;
|
||||||
|
*p++ = (unsigned char)i;
|
||||||
|
|
||||||
|
r = ((char *)p - *buf);
|
||||||
|
*buf = (char *)p;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decode a varint from <*buf> and save the decoded value in <*i>. See
|
||||||
|
* 'spoe_encode_varint' for details about varint.
|
||||||
|
* On success, it returns the number of read bytes and <*buf> is moved after the
|
||||||
|
* varint. Otherwise, it returns -1. */
|
||||||
|
static inline int decode_varint(char **buf, char *end, uint64_t *i)
|
||||||
|
{
|
||||||
|
unsigned char *p = (unsigned char *)*buf;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (p >= (unsigned char *)end)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
*i = *p++;
|
||||||
|
if (*i < 240) {
|
||||||
|
*buf = (char *)p;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = 4;
|
||||||
|
do {
|
||||||
|
if (p >= (unsigned char *)end)
|
||||||
|
return -1;
|
||||||
|
*i += (uint64_t)*p << r;
|
||||||
|
r += 7;
|
||||||
|
} while (*p++ >= 128);
|
||||||
|
|
||||||
|
r = ((char *)p - *buf);
|
||||||
|
*buf = (char *)p;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _HAPROXY_INTOPS_H */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local variables:
|
||||||
|
* c-indent-level: 8
|
||||||
|
* c-basic-offset: 8
|
||||||
|
* End:
|
||||||
|
*/
|
Loading…
x
Reference in New Issue
Block a user