Alien-LibJIT
view release on metacpan or search on metacpan
libjit/jit/jit-varint.c view on Meta::CPAN
/*
* jit-varint.c - Variable length integer encoding.
*
* Copyright (C) 2011 Aleksey Demakov
*
* The libjit 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, either version 2.1 of
* the License, or (at your option) any later version.
*
* The libjit 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 the libjit library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <jit/jit.h>
#include "jit-varint.h"
/*
* Flush the current encode buffer.
*/
static int
flush_encoder(jit_varint_encoder_t *encoder)
{
jit_varint_data_t data;
/* Allocate a new jit_varint_data structure to hold the data */
data = jit_malloc(sizeof(struct jit_varint_data) + encoder->len);
if(!data)
{
return 0;
}
/* Copy the temporary debug data into the new structure */
jit_memcpy(data->data, encoder->buf, encoder->len);
/* Link the structure into the debug list */
data->next = 0;
if(encoder->last)
{
encoder->last->next = data;
}
else
{
encoder->data = data;
}
encoder->last = data;
/* Reset the temporary debug buffer */
encoder->len = 0;
return 1;
}
void
_jit_varint_init_encoder(jit_varint_encoder_t *encoder)
{
encoder->len = 0;
encoder->data = 0;
encoder->last = 0;
}
void
_jit_varint_init_decoder(jit_varint_decoder_t *decoder, jit_varint_data_t data)
{
decoder->len = 0;
decoder->data = data;
decoder->end = (data == 0);
}
int
_jit_varint_encode_end(jit_varint_encoder_t *encoder)
{
if(!encoder->len)
{
return 1;
}
/* Mark the end of the data */
encoder->buf[encoder->len++] = 0xFF;
/* Flush the data that we have collected so far */
return flush_encoder(encoder);
}
/*
* Compress a "long" value so that it takes up less bytes.
* This is used to store offsets within functions and
* debug line numbers, which are usually small integers.
*/
int
_jit_varint_encode_uint(jit_varint_encoder_t *encoder, jit_uint value)
{
if(encoder->len + 6 > sizeof(encoder->buf))
{
/* Overflow occurred: end current buffer */
if(!_jit_varint_encode_end(encoder))
{
return 0;
}
}
/* Write the value to the temporary buffer */
if(value < 0x80)
{
/* 0xxx xxxx */
encoder->buf[encoder->len++] = (unsigned char) (value);
}
else if(value < 0x4000)
{
/* 10xx xxxx | xxxx xxxx */
encoder->buf[encoder->len++] = (unsigned char) (value >> 8) | 0x80;
encoder->buf[encoder->len++] = (unsigned char) (value);
}
else if(value < 0x200000)
{
/* 110x xxxx | xxxx xxxx | xxxx xxxx */
encoder->buf[encoder->len++] = (unsigned char) (value >> 16) | 0xC0;
encoder->buf[encoder->len++] = (unsigned char) (value >> 8);
encoder->buf[encoder->len++] = (unsigned char) (value);
}
else if(value < 0x10000000)
{
/* 1110 xxxx | xxxx xxxx | xxxx xxxx | xxxx xxxx */
encoder->buf[encoder->len++] = (unsigned char) (value >> 24) | 0xE0;
encoder->buf[encoder->len++] = (unsigned char) (value >> 16);
encoder->buf[encoder->len++] = (unsigned char) (value >> 8);
encoder->buf[encoder->len++] = (unsigned char) (value);
}
else
{
/* 1111 0000 | xxxx xxxx | xxxx xxxx | xxxx xxxx | xxxx xxxx */
encoder->buf[encoder->len++] = 0xF0;
encoder->buf[encoder->len++] = (unsigned char) (value >> 24);
encoder->buf[encoder->len++] = (unsigned char) (value >> 16);
encoder->buf[encoder->len++] = (unsigned char) (value >> 8);
encoder->buf[encoder->len++] = (unsigned char) (value);
}
return 1;
}
jit_varint_data_t
_jit_varint_get_data(jit_varint_encoder_t *encoder)
{
return encoder->data;
}
void
( run in 0.340 second using v1.01-cache-2.11-cpan-02777c243ea )