|
|
/* -*- 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); } }
|