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.
296 lines
7.2 KiB
296 lines
7.2 KiB
/* -*- coding: utf-8 -*-
|
|
* ----------------------------------------------------------------------
|
|
* Copyright © 2011-2012, RedJack, LLC.
|
|
* All rights reserved.
|
|
*
|
|
* Please see the COPYING file in this distribution for license
|
|
* details.
|
|
* ----------------------------------------------------------------------
|
|
*/
|
|
|
|
#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);
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------
|
|
* Slices
|
|
*/
|
|
|
|
void
|
|
cork_slice_clear(struct cork_slice *slice)
|
|
{
|
|
slice->buf = NULL;
|
|
slice->size = 0;
|
|
slice->iface = NULL;
|
|
slice->user_data = NULL;
|
|
}
|
|
|
|
|
|
int
|
|
cork_slice_copy(struct cork_slice *dest, const struct cork_slice *slice,
|
|
size_t offset, size_t length)
|
|
{
|
|
if ((slice != NULL) &&
|
|
(offset <= slice->size) &&
|
|
((offset + length) <= slice->size)) {
|
|
/*
|
|
DEBUG("Slicing <%p:%zu> at %zu:%zu, gives <%p:%zu>",
|
|
slice->buf, slice->size,
|
|
offset, length,
|
|
slice->buf + offset, length);
|
|
*/
|
|
return slice->iface->copy(dest, slice, offset, length);
|
|
}
|
|
|
|
else {
|
|
/*
|
|
DEBUG("Cannot slice <%p:%zu> at %zu:%zu",
|
|
slice->buf, slice->size,
|
|
offset, length);
|
|
*/
|
|
cork_slice_clear(dest);
|
|
cork_slice_invalid_slice_set
|
|
((slice == NULL)? 0: slice->size, offset, length);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
cork_slice_copy_offset(struct cork_slice *dest, const struct cork_slice *slice,
|
|
size_t offset)
|
|
{
|
|
if (slice == NULL) {
|
|
cork_slice_clear(dest);
|
|
cork_slice_invalid_slice_set(0, offset, 0);
|
|
return -1;
|
|
} else {
|
|
return cork_slice_copy
|
|
(dest, slice, offset, slice->size - offset);
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
cork_slice_light_copy(struct cork_slice *dest, const struct cork_slice *slice,
|
|
size_t offset, size_t length)
|
|
{
|
|
if ((slice != NULL) &&
|
|
(offset <= slice->size) &&
|
|
((offset + length) <= slice->size)) {
|
|
/*
|
|
DEBUG("Slicing <%p:%zu> at %zu:%zu, gives <%p:%zu>",
|
|
slice->buf, slice->size,
|
|
offset, length,
|
|
slice->buf + offset, length);
|
|
*/
|
|
return slice->iface->light_copy(dest, slice, offset, length);
|
|
}
|
|
|
|
else {
|
|
/*
|
|
DEBUG("Cannot slice <%p:%zu> at %zu:%zu",
|
|
slice->buf, slice->size,
|
|
offset, length);
|
|
*/
|
|
cork_slice_clear(dest);
|
|
cork_slice_invalid_slice_set
|
|
((slice == NULL)? 0: slice->size, offset, length);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
cork_slice_light_copy_offset(struct cork_slice *dest,
|
|
const struct cork_slice *slice, size_t offset)
|
|
{
|
|
if (slice == NULL) {
|
|
cork_slice_clear(dest);
|
|
cork_slice_invalid_slice_set(0, offset, 0);
|
|
return -1;
|
|
} else {
|
|
return cork_slice_light_copy
|
|
(dest, slice, offset, slice->size - offset);
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
cork_slice_slice(struct cork_slice *slice, size_t offset, size_t length)
|
|
{
|
|
if ((slice != NULL) &&
|
|
(offset <= slice->size) &&
|
|
((offset + length) <= slice->size)) {
|
|
/*
|
|
DEBUG("Slicing <%p:%zu> at %zu:%zu, gives <%p:%zu>",
|
|
slice->buf, slice->size,
|
|
offset, length,
|
|
slice->buf + offset, length);
|
|
*/
|
|
if (slice->iface->slice == NULL) {
|
|
slice->buf += offset;
|
|
slice->size = length;
|
|
return 0;
|
|
} else {
|
|
return slice->iface->slice(slice, offset, length);
|
|
}
|
|
}
|
|
|
|
else {
|
|
/*
|
|
DEBUG("Cannot slice <%p:%zu> at %zu:%zu",
|
|
slice->buf, slice->size,
|
|
offset, length);
|
|
*/
|
|
cork_slice_invalid_slice_set(slice->size, offset, length);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
cork_slice_slice_offset(struct cork_slice *slice, size_t offset)
|
|
{
|
|
if (slice == NULL) {
|
|
cork_slice_invalid_slice_set(0, offset, 0);
|
|
return -1;
|
|
} else {
|
|
return cork_slice_slice
|
|
(slice, offset, slice->size - offset);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
cork_slice_finish(struct cork_slice *slice)
|
|
{
|
|
/*
|
|
DEBUG("Finalizing <%p:%zu>", dest->buf, dest->size);
|
|
*/
|
|
|
|
if (slice->iface != NULL && slice->iface->free != NULL) {
|
|
slice->iface->free(slice);
|
|
}
|
|
|
|
cork_slice_clear(slice);
|
|
}
|
|
|
|
|
|
bool
|
|
cork_slice_equal(const struct cork_slice *slice1,
|
|
const struct cork_slice *slice2)
|
|
{
|
|
if (slice1 == slice2) {
|
|
return true;
|
|
}
|
|
|
|
if (slice1->size != slice2->size) {
|
|
return false;
|
|
}
|
|
|
|
return (memcmp(slice1->buf, slice2->buf, slice1->size) == 0);
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------
|
|
* Slices of static content
|
|
*/
|
|
|
|
static struct cork_slice_iface cork_static_slice;
|
|
|
|
static int
|
|
cork_static_slice_copy(struct cork_slice *dest, const struct cork_slice *src,
|
|
size_t offset, size_t length)
|
|
{
|
|
dest->buf = src->buf + offset;
|
|
dest->size = length;
|
|
dest->iface = &cork_static_slice;
|
|
dest->user_data = NULL;
|
|
return 0;
|
|
}
|
|
|
|
static struct cork_slice_iface cork_static_slice = {
|
|
NULL,
|
|
cork_static_slice_copy,
|
|
cork_static_slice_copy,
|
|
NULL
|
|
};
|
|
|
|
void
|
|
cork_slice_init_static(struct cork_slice *dest, const void *buf, size_t size)
|
|
{
|
|
dest->buf = buf;
|
|
dest->size = size;
|
|
dest->iface = &cork_static_slice;
|
|
dest->user_data = NULL;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------
|
|
* Copy-once slices
|
|
*/
|
|
|
|
static struct cork_slice_iface cork_copy_once_slice;
|
|
|
|
static int
|
|
cork_copy_once_slice__copy(struct cork_slice *dest,
|
|
const struct cork_slice *src,
|
|
size_t offset, size_t length)
|
|
{
|
|
struct cork_managed_buffer *mbuf =
|
|
cork_managed_buffer_new_copy(src->buf, src->size);
|
|
rii_check(cork_managed_buffer_slice(dest, mbuf, offset, length));
|
|
rii_check(cork_managed_buffer_slice
|
|
((struct cork_slice *) src, mbuf, 0, src->size));
|
|
cork_managed_buffer_unref(mbuf);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
cork_copy_once_slice__light_copy(struct cork_slice *dest,
|
|
const struct cork_slice *src,
|
|
size_t offset, size_t length)
|
|
{
|
|
dest->buf = src->buf + offset;
|
|
dest->size = length;
|
|
dest->iface = &cork_copy_once_slice;
|
|
dest->user_data = NULL;
|
|
return 0;
|
|
}
|
|
|
|
static struct cork_slice_iface cork_copy_once_slice = {
|
|
NULL,
|
|
cork_copy_once_slice__copy,
|
|
cork_copy_once_slice__light_copy,
|
|
NULL
|
|
};
|
|
|
|
void
|
|
cork_slice_init_copy_once(struct cork_slice *dest, const void *buf, size_t size)
|
|
{
|
|
dest->buf = buf;
|
|
dest->size = size;
|
|
dest->iface = &cork_copy_once_slice;
|
|
dest->user_data = NULL;
|
|
}
|