1 /* 2 * librdkafka - The Apache Kafka C/C++ library 3 * 4 * Copyright (c) 2016 Magnus Edenhill 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright notice, 11 * this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 30 #ifndef _RDVARINT_H 31 #define _RDVARINT_H 32 33 #include "rd.h" 34 #include "rdbuf.h" 35 36 /** 37 * @name signed varint zig-zag encoder/decoder 38 * @{ 39 * 40 */ 41 42 /** 43 * @brief unsigned-varint encodes unsigned integer \p num into buffer 44 * at \p dst of size \p dstsize. 45 * @returns the number of bytes written to \p dst, or 0 if not enough space. 46 */ 47 48 static RD_INLINE RD_UNUSED 49 size_t rd_uvarint_enc_u64 (char *dst, size_t dstsize, uint64_t num) { 50 size_t of = 0; 51 52 do { 53 if (unlikely(of >= dstsize)) 54 return 0; /* Not enough space */ 55 56 dst[of++] = (num & 0x7f) | (num > 0x7f ? 0x80 : 0); 57 num >>= 7; 58 } while (num); 59 60 return of; 61 } 62 63 /** 64 * @brief encodes a signed integer using zig-zag encoding. 65 * @sa rd_uvarint_enc_u64 66 */ 67 static RD_INLINE RD_UNUSED 68 size_t rd_uvarint_enc_i64 (char *dst, size_t dstsize, int64_t num) { 69 return rd_uvarint_enc_u64(dst, dstsize, (num << 1) ^ (num >> 63)); 70 } 71 72 73 static RD_INLINE RD_UNUSED 74 size_t rd_uvarint_enc_i32 (char *dst, size_t dstsize, int32_t num) { 75 return rd_uvarint_enc_i64(dst, dstsize, num); 76 } 77 78 79 80 /** 81 * @brief Use on return value from rd_uvarint_dec() to check if 82 * decoded varint fit the size_t. 83 * 84 * @returns 1 on overflow, else 0. 85 */ 86 #define RD_UVARINT_OVERFLOW(DEC_RETVAL) (DEC_RETVAL > SIZE_MAX) 87 88 /** 89 * @returns 1 if there were not enough bytes to decode the varint, else 0. 90 */ 91 #define RD_UVARINT_UNDERFLOW(DEC_RETVAL) (DEC_RETVAL == 0) 92 93 94 /** 95 * @param DEC_RETVAL the return value from \c rd_uvarint_dec() 96 * @returns 1 if varint decoding failed, else 0. 97 * @warning \p DEC_RETVAL will be evaluated twice. 98 */ 99 #define RD_UVARINT_DEC_FAILED(DEC_RETVAL) \ 100 (RD_UVARINT_UNDERFLOW(DEC_RETVAL) || RD_UVARINT_OVERFLOW(DEC_RETVAL)) 101 102 103 /** 104 * @brief Decodes the unsigned-varint in buffer \p src of size \p srcsize 105 * and stores the decoded unsigned integer in \p nump. 106 * 107 * @remark Use RD_UVARINT_OVERFLOW(returnvalue) to check if the varint 108 * could not fit \p nump, and RD_UVARINT_UNDERFLOW(returnvalue) to 109 * check if there were not enough bytes available in \p src to 110 * decode the full varint. 111 * 112 * @returns the number of bytes read from \p src. 113 */ 114 static RD_INLINE RD_UNUSED 115 size_t rd_uvarint_dec (const char *src, size_t srcsize, uint64_t *nump) { 116 size_t of = 0; 117 uint64_t num = 0; 118 int shift = 0; 119 120 do { 121 if (unlikely(srcsize-- == 0)) 122 return 0; /* Underflow */ 123 num |= (uint64_t)(src[(int)of] & 0x7f) << shift; 124 shift += 7; 125 } while (src[(int)of++] & 0x80); 126 127 *nump = num; 128 return of; 129 } 130 131 static RD_INLINE RD_UNUSED 132 size_t rd_varint_dec_i64 (const char *src, size_t srcsize, int64_t *nump) { 133 uint64_t n; 134 size_t r; 135 136 r = rd_uvarint_dec(src, srcsize, &n); 137 if (likely(!RD_UVARINT_DEC_FAILED(r))) 138 *nump = (int64_t)(n >> 1) ^ -(int64_t)(n & 1); 139 140 return r; 141 } 142 143 144 /** 145 * @returns the maximum encoded size for a type 146 */ 147 #define RD_UVARINT_ENC_SIZEOF(TYPE) \ 148 (sizeof(TYPE) + 1 + (sizeof(TYPE)/7)) 149 150 /** 151 * @returns the encoding size of the value 0 152 */ 153 #define RD_UVARINT_ENC_SIZE_0() ((size_t)1) 154 155 156 int unittest_rdvarint (void); 157 158 /**@}*/ 159 160 161 #endif /* _RDVARINT_H */ 162