You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

239 lines
6.3 KiB

/* -*- coding: utf-8 -*-
* ----------------------------------------------------------------------
* Copyright © 2011-2012, RedJack, LLC.
* All rights reserved.
*
* Please see the COPYING file in this distribution for license
* details.
* ----------------------------------------------------------------------
*/
#include <stdlib.h>
#include <string.h>
#include "libcork/core/error.h"
#include "libcork/core/types.h"
#include "libcork/ds/managed-buffer.h"
#include "libcork/ds/slice.h"
#include "libcork/helpers/errors.h"
/*-----------------------------------------------------------------------
* Error handling
*/
static void
cork_slice_invalid_slice_set(size_t buf_size, size_t requested_offset,
size_t requested_length)
{
cork_error_set
(CORK_SLICE_ERROR, CORK_SLICE_INVALID_SLICE,
"Cannot slice %zu-byte buffer at %zu:%zu",
buf_size, requested_offset, requested_length);
}
/*-----------------------------------------------------------------------
* Managed buffers
*/
struct cork_managed_buffer_wrapped {
struct cork_managed_buffer parent;
void *buf;
size_t size;
cork_managed_buffer_freer free;
};
static void
cork_managed_buffer_wrapped__free(struct cork_managed_buffer *vself)
{
struct cork_managed_buffer_wrapped *self =
cork_container_of(vself, struct cork_managed_buffer_wrapped, parent);
self->free(self->buf, self->size);
free(self);
}
static struct cork_managed_buffer_iface CORK_MANAGED_BUFFER_WRAPPED = {
cork_managed_buffer_wrapped__free
};
struct cork_managed_buffer *
cork_managed_buffer_new(const void *buf, size_t size,
cork_managed_buffer_freer free)
{
/*
DEBUG("Creating new struct cork_managed_buffer [%p:%zu], refcount now 1",
buf, size);
*/
struct cork_managed_buffer_wrapped *self =
cork_new(struct cork_managed_buffer_wrapped);
self->parent.buf = buf;
self->parent.size = size;
self->parent.ref_count = 1;
self->parent.iface = &CORK_MANAGED_BUFFER_WRAPPED;
self->buf = (void *) buf;
self->size = size;
self->free = free;
return &self->parent;
}
struct cork_managed_buffer_copied {
struct cork_managed_buffer parent;
};
#define cork_managed_buffer_copied_data(self) \
(((void *) (self)) + sizeof(struct cork_managed_buffer_copied))
#define cork_managed_buffer_copied_sizeof(sz) \
((sz) + sizeof(struct cork_managed_buffer_copied))
static void
cork_managed_buffer_copied__free(struct cork_managed_buffer *vself)
{
struct cork_managed_buffer_copied *self =
cork_container_of(vself, struct cork_managed_buffer_copied, parent);
free(self);
}
static struct cork_managed_buffer_iface CORK_MANAGED_BUFFER_COPIED = {
cork_managed_buffer_copied__free
};
struct cork_managed_buffer *
cork_managed_buffer_new_copy(const void *buf, size_t size)
{
size_t allocated_size = cork_managed_buffer_copied_sizeof(size);
struct cork_managed_buffer_copied *self = malloc(allocated_size);
if (self == NULL) {
return NULL;
}
self->parent.buf = cork_managed_buffer_copied_data(self);
self->parent.size = size;
self->parent.ref_count = 1;
self->parent.iface = &CORK_MANAGED_BUFFER_COPIED;
memcpy((void *) self->parent.buf, buf, size);
return &self->parent;
}
static void
cork_managed_buffer_free(struct cork_managed_buffer *self)
{
/*
DEBUG("Freeing struct cork_managed_buffer [%p:%zu]", self->buf, self->size);
*/
self->iface->free(self);
}
struct cork_managed_buffer *
cork_managed_buffer_ref(struct cork_managed_buffer *self)
{
/*
int old_count = self->ref_count++;
DEBUG("Referencing struct cork_managed_buffer [%p:%zu], refcount now %d",
self->buf, self->size, old_count + 1);
*/
self->ref_count++;
return self;
}
void
cork_managed_buffer_unref(struct cork_managed_buffer *self)
{
/*
int old_count = self->ref_count--;
DEBUG("Dereferencing struct cork_managed_buffer [%p:%zu], refcount now %d",
self->buf, self->size, old_count - 1);
*/
if (--self->ref_count == 0) {
cork_managed_buffer_free(self);
}
}
static struct cork_slice_iface CORK_MANAGED_BUFFER__SLICE;
static void
cork_managed_buffer__slice_free(struct cork_slice *self)
{
struct cork_managed_buffer *mbuf = self->user_data;
cork_managed_buffer_unref(mbuf);
}
static int
cork_managed_buffer__slice_copy(struct cork_slice *dest,
const struct cork_slice *src,
size_t offset, size_t length)
{
struct cork_managed_buffer *mbuf = src->user_data;
dest->buf = src->buf + offset;
dest->size = length;
dest->iface = &CORK_MANAGED_BUFFER__SLICE;
dest->user_data = cork_managed_buffer_ref(mbuf);
return 0;
}
static struct cork_slice_iface CORK_MANAGED_BUFFER__SLICE = {
cork_managed_buffer__slice_free,
cork_managed_buffer__slice_copy,
cork_managed_buffer__slice_copy,
NULL
};
int
cork_managed_buffer_slice(struct cork_slice *dest,
struct cork_managed_buffer *buffer,
size_t offset, size_t length)
{
if ((buffer != NULL) &&
(offset <= buffer->size) &&
((offset + length) <= buffer->size)) {
/*
DEBUG("Slicing [%p:%zu] at %zu:%zu, gives <%p:%zu>",
buffer->buf, buffer->size,
offset, length,
buffer->buf + offset, length);
*/
dest->buf = buffer->buf + offset;
dest->size = length;
dest->iface = &CORK_MANAGED_BUFFER__SLICE;
dest->user_data = cork_managed_buffer_ref(buffer);
return 0;
}
else {
/*
DEBUG("Cannot slice [%p:%zu] at %zu:%zu",
buffer->buf, buffer->size,
offset, length);
*/
cork_slice_clear(dest);
cork_slice_invalid_slice_set(0, offset, 0);
return -1;
}
}
int
cork_managed_buffer_slice_offset(struct cork_slice *dest,
struct cork_managed_buffer *buffer,
size_t offset)
{
if (buffer == NULL) {
cork_slice_clear(dest);
cork_slice_invalid_slice_set(0, offset, 0);
return -1;
} else {
return cork_managed_buffer_slice
(dest, buffer, offset, buffer->size - offset);
}
}