#define KINO_USE_SHORT_NAMES
#define CHY_USE_SHORT_NAMES
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#define KINO_WANT_BYTEBUF_VTABLE
#include "KinoSearch/Util/ByteBuf.r"
#include "KinoSearch/Util/Carp.h"
#include "KinoSearch/Util/MemManager.h"
#include "KinoSearch/Util/MathUtils.h"
/* Maximum number of characters in a stringified 64-bit integer, including
* minus sign if negative.
*/
#define MAX_I64_CHARS 20
ByteBuf*
BB_to_string(ByteBuf *self)
{
REFCOUNT_INC(self);
return self;
}
ByteBuf*
BB_new(size_t future_size)
{
CREATE(self, ByteBuf, BYTEBUF);
/* derive */
self->ptr = MALLOCATE(future_size + 1, char);
/* init */
*self->ptr = '\0';
/* assign */
self->len = 0;
self->cap = future_size + 1;
return self;
}
ByteBuf*
BB_new_str(const char *ptr, size_t len)
{
CREATE(self, ByteBuf, BYTEBUF);
/* derive */
self->ptr = MALLOCATE(len + 1, char);
/* copy */
memcpy(self->ptr, ptr, len);
/* assign */
self->len = len;
self->cap = len + 1;
self->ptr[len] = '\0'; /* null terminate */
return self;
}
ByteBuf*
BB_new_steal(char *ptr, size_t len, size_t cap)
{
CREATE(self, ByteBuf, BYTEBUF);
/* assign the passed in values */
self->ptr = ptr;
self->len = len;
self->cap = cap;
return self;
}
ByteBuf*
BB_new_i64(i64_t num) {
CREATE(self, ByteBuf, BYTEBUF);
self->ptr = MALLOCATE(MAX_I64_CHARS + 1, char);
self->cap = MAX_I64_CHARS + 1;
self->len = sprintf(self->ptr, "%"I64P, num);
return self;
}
ByteBuf*
BB_clone(ByteBuf *self)
{
return BB_new_str(self->ptr, self->len);
}
bool_t
BB_equals(ByteBuf *self, ByteBuf *other)
{
if (self->len != other->len)
return false;
return (memcmp(self->ptr, other->ptr, self->len) == 0);
}
i32_t
BB_hash_code(ByteBuf *self)
{
size_t len = self->len;
const u8_t *ptr = (const u8_t*)self->ptr;
u32_t hashvalue = 0;
while (len--) {
hashvalue += *ptr++;
hashvalue += (hashvalue << 10);
hashvalue ^= (hashvalue >> 6);
}
hashvalue += (hashvalue << 3);
hashvalue ^= (hashvalue >> 11);
hashvalue += (hashvalue << 15);
return (i32_t) hashvalue;
}
void
BB_copy_str(ByteBuf *self, char* ptr, size_t len)
{
BB_GROW(self, len);
memcpy(self->ptr, ptr, len);
self->len = len;
self->ptr[len] = '\0';
}
void
BB_copy_bb(ByteBuf *self, const ByteBuf *other)
{
BB_GROW(self, other->len);
memcpy(self->ptr, other->ptr, other->len);
self->len = other->len;
self->ptr[other->len] = '\0';
}
void
BB_cat_str(ByteBuf *self, char* ptr, size_t len)
{
const size_t new_len = self->len + len;
BB_GROW(self, new_len);
memcpy((self->ptr + self->len), ptr, len);
self->len = new_len;
self->ptr[new_len] = '\0';
}
void
BB_cat_bb(ByteBuf *self, const ByteBuf *other)
{
const size_t new_len = self->len + other->len;
BB_GROW(self, new_len);
memcpy((self->ptr + self->len), other->ptr, other->len);
self->len = new_len;
self->ptr[new_len] = '\0';
}
void
BB_cat_i64(ByteBuf *self, i64_t num)
{
BB_GROW(self, self->len + MAX_I64_CHARS);
self->len += sprintf(BBEND(self), "%"I64P, num);
}
i64_t
BB_to_i64(ByteBuf *self)
{
char *ptr = self->ptr;
const i64_t NUM_CHAR_OFFSET = '0';
i64_t retval = 0;
bool_t is_negative = false;
/* advance past minus sign */
if (*ptr == '-') {
ptr++;
is_negative = true;
}
for( ; isdigit(*ptr); ptr++) {
retval *= 10;
retval += *ptr - NUM_CHAR_OFFSET;
}
if (is_negative)
retval = 0 - retval;
return retval;
}
void
BB_grow(ByteBuf *self, size_t new_len)
{
/* bail out if the buffer's already at least as big as required */
if (self->cap > new_len)
return;
self->ptr = REALLOCATE(self->ptr, (new_len + 1), char);
self->cap = new_len + 1;
}
bool_t
BB_starts_with(ByteBuf *self, const ByteBuf *prefix)
{
size_t len = prefix->len;
if ( len <= self->len
&& (memcmp(self->ptr, prefix->ptr, len) == 0)
) {
return true;
}
else {
return false;
}
}
bool_t
BB_ends_with_str(ByteBuf *self, const char *postfix, size_t postfix_len)
{
if (postfix_len <= self->len) {
char *start = BBEND(self) - postfix_len;
if (memcmp(start, postfix, postfix_len) == 0)
return true;
}
return false;
}
void
BB_serialize(ByteBuf *self, ByteBuf *target)
{
const size_t space_required = target->len + self->len + VINT_MAX_BYTES;
char *ptr, *start;
/* make room */
BB_GROW(target, space_required);
ptr = BBEND(target);
start = ptr;
/* header u32_t length, followed by content */
ENCODE_VINT(self->len, ptr);
target->len += ptr - start;
memcpy(ptr, self->ptr, self->len);
target->len += self->len;
}
ByteBuf*
BB_deserialize(struct kino_ViewByteBuf *serialized_vbb)
{
ByteBuf *const serialized_bb = (ByteBuf*)serialized_vbb;
u32_t size;
ByteBuf *self;
/* copy string after verifying no invalid memory reads */
DECODE_VINT(size, serialized_bb->ptr);
if (serialized_bb->len < size) {
CONFESS("Not enough characters in serialized object: %u %u", size,
serialized_bb->len);
}
self = BB_new_str(serialized_bb->ptr, size);
/* consume characters */
serialized_bb->ptr += size;
serialized_bb->len -= size;
return self;
}
void
BB_destroy(ByteBuf *self)
{
free(self->ptr);
free(self);
}
int
BB_compare(const void *va, const void *vb)
{
const ByteBuf *a = *(const ByteBuf**)va;
const ByteBuf *b = *(const ByteBuf**)vb;
const size_t len = a->len < b->len ? a->len : b->len;
i32_t comparison = memcmp(a->ptr, b->ptr, len);
if (comparison == 0 && a->len != b->len)
comparison = a->len < b->len ? -1 : 1;
return comparison;
}
bool_t
BB_less_than(const void *va, const void *vb)
{
const ByteBuf *a = *(const ByteBuf**)va;
const ByteBuf *b = *(const ByteBuf**)vb;
const size_t len = a->len < b->len ? a->len : b->len;
int comparison = memcmp(a->ptr, b->ptr, len);
if (comparison == 0)
comparison = a->len - b->len;
return comparison < 0;
}
/* Copyright 2006-2007 Marvin Humphrey
*
* This program is free software; you can redistribute it and/or modify
* under the same terms as Perl itself.
*/