/*****************************************************************************

Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved.

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; version 2 of the License.

This program 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 General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA

*****************************************************************************/

/******************************************************************//**
@file include/fts0vlc.ic
Full text variable length integer encoding/decoding.

Created 2007-03-27 Sunny Bains
*******************************************************/

#ifndef INNOBASE_FTS0VLC_IC
#define INNOBASE_FTS0VLC_IC

#include "fts0types.h"

/******************************************************************//**
Return length of val if it were encoded using our VLC scheme.
FIXME: We will need to be able encode 8 bytes value
@return length of value encoded, in bytes */
UNIV_INLINE
ulint
fts_get_encoded_len(
/*================*/
	ulint	val)	/* in: value to encode */
{
	if (val <= 127) {
		return(1);
	} else if (val <= 16383) {
		return(2);
	} else if (val <= 2097151) {
		return(3);
	} else if (val <= 268435455) {
		return(4);
	} else {
		/* Possibly we should care that on 64-bit machines ulint can
		contain values that we can't encode in 5 bytes, but
		fts_encode_int doesn't handle them either so it doesn't much
		matter. */

		return(5);
	}
}

/******************************************************************//**
Encode an integer using our VLC scheme and return the length in bytes.
@return length of value encoded, in bytes */
UNIV_INLINE
ulint
fts_encode_int(
/*===========*/
	ulint	val,	/* in: value to encode */
	byte*	buf)	/* in: buffer, must have enough space */
{
	ulint	len;

	if (val <= 127) {
		*buf = (byte) val;

		len = 1;
	} else if (val <= 16383) {
		*buf++ = (byte)(val >> 7);
		*buf = (byte)(val & 0x7F);

		len = 2;
	} else if (val <= 2097151) {
		*buf++ = (byte)(val >> 14);
		*buf++ = (byte)((val >> 7) & 0x7F);
		*buf = (byte)(val & 0x7F);

		len = 3;
	} else if (val <= 268435455) {
		*buf++ = (byte)(val >> 21);
		*buf++ = (byte)((val >> 14) & 0x7F);
		*buf++ = (byte)((val >> 7) & 0x7F);
		*buf = (byte)(val & 0x7F);

		len = 4;
	} else {
		/* Best to keep the limitations of the 32/64 bit versions
		identical, at least for the time being. */
		ut_ad(val <= 4294967295u);

		*buf++ = (byte)(val >> 28);
		*buf++ = (byte)((val >> 21) & 0x7F);
		*buf++ = (byte)((val >> 14) & 0x7F);
		*buf++ = (byte)((val >> 7) & 0x7F);
		*buf = (byte)(val & 0x7F);

		len = 5;
	}

	/* High-bit on means "last byte in the encoded integer". */
	*buf |= 0x80;

	return(len);
}

/******************************************************************//**
Decode and return the integer that was encoded using our VLC scheme.
@return value decoded */
UNIV_INLINE
ulint
fts_decode_vlc(
/*===========*/
	byte**	ptr)	/* in: ptr to decode from, this ptr is
			incremented by the number of bytes decoded */
{
	ulint	val = 0;

	for (;;) {
		byte	b = **ptr;

		++*ptr;
		val |= (b & 0x7F);

		/* High-bit on means "last byte in the encoded integer". */
		if (b & 0x80) {
			break;
		} else {
			val <<= 7;
		}
	}

	return(val);
}

#endif
