blob: b30eff67ee62143e16f106b57bcebbdf4cacd337 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// This file contains code derived from sqlite4, distributed in the public domain.
//
// A variable length integer is an encoding of 64-bit unsigned integers
// into between 1 and 9 bytes. The encoding is designed so that small
// (and common) values take much less space that larger values. Additional
// properties:
//
// * The length of the varint can be determined after examining just
// the first byte of the encoding.
//
// * Varints compare in numerical order using memcmp().
//
//************************************************************************
//
// Treat each byte of the encoding as an unsigned integer between 0 and 255.
// Let the bytes of the encoding be called A0, A1, A2, ..., A8.
//
// DECODE
//
// If A0 is between 0 and 240 inclusive, then the result is the value of A0.
//
// If A0 is between 241 and 248 inclusive, then the result is
// 240+256*(A0-241)+A1.
//
// If A0 is 249 then the result is 2288+256*A1+A2.
//
// If A0 is 250 then the result is A1..A3 as a 3-byte big-ending integer.
//
// If A0 is 251 then the result is A1..A4 as a 4-byte big-ending integer.
//
// If A0 is 252 then the result is A1..A5 as a 5-byte big-ending integer.
//
// If A0 is 253 then the result is A1..A6 as a 6-byte big-ending integer.
//
// If A0 is 254 then the result is A1..A7 as a 7-byte big-ending integer.
//
// If A0 is 255 then the result is A1..A8 as a 8-byte big-ending integer.
//
// ENCODE
//
// Let the input value be V.
//
// If V<=240 then output a single by A0 equal to V.
//
// If V<=2287 then output A0 as (V-240)/256 + 241 and A1 as (V-240)%256.
//
// If V<=67823 then output A0 as 249, A1 as (V-2288)/256, and A2
// as (V-2288)%256.
//
// If V<=16777215 then output A0 as 250 and A1 through A3 as a big-endian
// 3-byte integer.
//
// If V<=4294967295 then output A0 as 251 and A1..A4 as a big-ending
// 4-byte integer.
//
// If V<=1099511627775 then output A0 as 252 and A1..A5 as a big-ending
// 5-byte integer.
//
// If V<=281474976710655 then output A0 as 253 and A1..A6 as a big-ending
// 6-byte integer.
//
// If V<=72057594037927935 then output A0 as 254 and A1..A7 as a
// big-ending 7-byte integer.
//
// Otherwise then output A0 as 255 and A1..A8 as a big-ending 8-byte integer.
//
// SUMMARY
//
// Bytes Max Value Digits
// ------- --------- ---------
// 1 240 2.3
// 2 2287 3.3
// 3 67823 4.8
// 4 2**24-1 7.2
// 5 2**32-1 9.6
// 6 2**40-1 12.0
// 7 2**48-1 14.4
// 8 2**56-1 16.8
// 9 2**64-1 19.2
#include <cstddef>
#include <glog/logging.h>
#include "kudu/util/faststring.h"
#include "kudu/util/memcmpable_varint.h"
#include "kudu/util/slice.h"
namespace kudu {
////////////////////////////////////////////////////////////
// Begin code ripped from sqlite4
////////////////////////////////////////////////////////////
// This function is borrowed from sqlite4/varint.c
static void varintWrite32(uint8_t *z, uint32_t y) {
z[0] = (uint8_t)(y>>24);
z[1] = (uint8_t)(y>>16);
z[2] = (uint8_t)(y>>8);
z[3] = (uint8_t)(y);
}
// Write a varint into z[]. The buffer z[] must be at least 9 characters
// long to accommodate the largest possible varint. Return the number of
// bytes of z[] used.
//
// This function is borrowed from sqlite4/varint.c
static size_t sqlite4PutVarint64(uint8_t *z, uint64_t x) {
uint64_t w, y;
if (x <= 240) {
z[0] = (uint8_t)x;
return 1;
}
if (x <= 2287) {
y = (uint64_t)(x - 240);
z[0] = (uint8_t)(y/256 + 241);
z[1] = (uint8_t)(y%256);
return 2;
}
if (x <= 67823) {
y = (uint64_t)(x - 2288);
z[0] = 249;
z[1] = (uint8_t)(y/256);
z[2] = (uint8_t)(y%256);
return 3;
}
y = (uint64_t)x;
w = (uint64_t)(x>>32);
if (w == 0) {
if (y <= 16777215) {
z[0] = 250;
z[1] = (uint8_t)(y>>16);
z[2] = (uint8_t)(y>>8);
z[3] = (uint8_t)(y);
return 4;
}
z[0] = 251;
varintWrite32(z+1, y);
return 5;
}
if (w <= 255) {
z[0] = 252;
z[1] = (uint8_t)w;
varintWrite32(z+2, y);
return 6;
}
if (w <= 65535) {
z[0] = 253;
z[1] = (uint8_t)(w>>8);
z[2] = (uint8_t)w;
varintWrite32(z+3, y);
return 7;
}
if (w <= 16777215) {
z[0] = 254;
z[1] = (uint8_t)(w>>16);
z[2] = (uint8_t)(w>>8);
z[3] = (uint8_t)w;
varintWrite32(z+4, y);
return 8;
}
z[0] = 255;
varintWrite32(z+1, w);
varintWrite32(z+5, y);
return 9;
}
// Decode the varint in the first n bytes z[]. Write the integer value
// into *pResult and return the number of bytes in the varint.
//
// If the decode fails because there are not enough bytes in z[] then
// return 0;
//
// Borrowed from sqlite4 varint.c
static int sqlite4GetVarint64(
const uint8_t *z,
int n,
uint64_t *p_result) {
unsigned int x;
if ( n < 1) return 0;
if (z[0] <= 240) {
*p_result = z[0];
return 1;
}
if (z[0] <= 248) {
if ( n < 2) return 0;
*p_result = (z[0]-241)*256 + z[1] + 240;
return 2;
}
if (n < z[0]-246 ) return 0;
if (z[0] == 249) {
*p_result = 2288 + 256*z[1] + z[2];
return 3;
}
if (z[0] == 250) {
*p_result = (z[1]<<16) + (z[2]<<8) + z[3];
return 4;
}
x = (z[1]<<24) + (z[2]<<16) + (z[3]<<8) + z[4];
if (z[0] == 251) {
*p_result = x;
return 5;
}
if (z[0] == 252) {
*p_result = (((uint64_t)x)<<8) + z[5];
return 6;
}
if (z[0] == 253) {
*p_result = (((uint64_t)x)<<16) + (z[5]<<8) + z[6];
return 7;
}
if (z[0] == 254) {
*p_result = (((uint64_t)x)<<24) + (z[5]<<16) + (z[6]<<8) + z[7];
return 8;
}
*p_result = (((uint64_t)x)<<32) +
(0xffffffff & ((z[5]<<24) + (z[6]<<16) + (z[7]<<8) + z[8]));
return 9;
}
////////////////////////////////////////////////////////////
// End code ripped from sqlite4
////////////////////////////////////////////////////////////
void PutMemcmpableVarint64(faststring *dst, uint64_t value) {
uint8_t buf[9];
int used = sqlite4PutVarint64(buf, value);
DCHECK_LE(used, sizeof(buf));
dst->append(buf, used);
}
bool GetMemcmpableVarint64(Slice *input, uint64_t *value) {
size_t size = sqlite4GetVarint64(input->data(), input->size(), value);
input->remove_prefix(size);
return size > 0;
}
} // namespace kudu