Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
tree: de6a984c5e
Fetching contributors…

Cannot retrieve contributors at this time

556 lines (427 sloc) 15.165 kB
/*
Copyright (C) 2010-2012, Parrot Foundation.
=head1 NAME
src/pmc/bytebuffer.pmc - A byte buffer
=head1 DESCRIPTION
C<ByteBuffer> provides a resizable byte buffer with random access to
individual bytes and conversions from and to parrot strings.
=cut
*/
/* HEADERIZER HFILE: none */
/* HEADERIZER BEGIN: static */
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
PARROT_CANNOT_RETURN_NULL
PARROT_WARN_UNUSED_RESULT
static STRING * build_string(PARROT_INTERP,
ARGIN_NULLOK(const unsigned char *content),
INTVAL size,
ARGIN(const STR_VTABLE *encoding))
__attribute__nonnull__(1)
__attribute__nonnull__(4);
PARROT_CANNOT_RETURN_NULL
PARROT_WARN_UNUSED_RESULT
static STRING * build_string_from_string(PARROT_INTERP,
ARGIN_NULLOK(STRING *from),
INTVAL pos,
INTVAL size,
ARGIN(const STR_VTABLE *encoding))
__attribute__nonnull__(1)
__attribute__nonnull__(5);
PARROT_WARN_UNUSED_RESULT
static INTVAL grow_to(INTVAL position);
#define ASSERT_ARGS_build_string __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(encoding))
#define ASSERT_ARGS_build_string_from_string __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(encoding))
#define ASSERT_ARGS_grow_to __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
/* HEADERIZER END: static */
pmclass ByteBuffer auto_attrs {
ATTR INTVAL allocated_size;
ATTR INTVAL size;
ATTR STRING *source;
ATTR unsigned char *content;
/*
=head2 Vtable functions
=over 4
=item C<void init()>
Create an empty buffer
=item C<void init_int()>
Create a buffer of initial_size capacity.
=item C<void mark()>
Mark the source string if any.
=item C<void destroy()>
Free the buffer when destroying.
=cut
*/
VTABLE void init() {
PObj_custom_mark_destroy_SETALL(SELF);
}
VTABLE void init_int(INTVAL initial_size) {
unsigned char *content;
if (initial_size < 0)
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
_("ByteBuffer: Cannot set buffer size to a negative number (%d)"), initial_size);
STATICSELF.init();
SET_ATTR_size(INTERP, SELF, initial_size);
SET_ATTR_allocated_size(INTERP, SELF, initial_size);
content = (unsigned char *)Parrot_gc_allocate_memory_chunk(INTERP, initial_size);
SET_ATTR_content(INTERP, SELF, content);
}
VTABLE void mark() {
STRING * source;
GET_ATTR_source(INTERP, SELF, source);
if (!STRING_IS_NULL(source))
Parrot_gc_mark_STRING_alive(INTERP, source);
}
VTABLE void destroy() {
INTVAL allocated_size;
GET_ATTR_allocated_size(INTERP, SELF, allocated_size);
if (allocated_size) {
unsigned char *content;
GET_ATTR_content(INTERP, SELF, content);
Parrot_gc_free_memory_chunk(INTERP, content);
}
}
/*
=item C<INTVAL elements()>
Get current size.
=cut
*/
VTABLE INTVAL elements() {
INTVAL size;
GET_ATTR_size(INTERP, SELF, size);
return size;
}
/*
=item C<void set_integer_native()>
Resize the buffer to the given value.
=cut
*/
VTABLE void set_integer_native(INTVAL set_size) {
INTVAL size, allocated_size;
unsigned char *content;
if (set_size < 0)
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
"Negative size in ByteBuffer");
GET_ATTR_allocated_size(INTERP, SELF, allocated_size);
if (set_size == 0) {
if (allocated_size == 0)
SET_ATTR_source(INTERP, SELF, STRINGNULL);
else {
GET_ATTR_content(INTERP, SELF, content);
Parrot_gc_free_memory_chunk(INTERP, content);
}
SET_ATTR_allocated_size(INTERP, SELF, 0);
SET_ATTR_size(INTERP, SELF, 0);
SET_ATTR_content(INTERP, SELF, NULL);
}
else {
GET_ATTR_size(INTERP, SELF, size);
/* If reducing size, just change the size value */
if (set_size > size) {
const INTVAL copysize = set_size < size ? set_size : size;
if (allocated_size == 0) {
content = (unsigned char *)Parrot_gc_allocate_memory_chunk(INTERP, set_size);
if (size > 0) {
STRING * source;
GET_ATTR_source(INTERP, SELF, source);
memcpy(content, source->strstart, copysize);
}
SET_ATTR_source(INTERP, SELF, STRINGNULL);
}
else {
GET_ATTR_content(INTERP, SELF, content);
content = (unsigned char *)
Parrot_gc_reallocate_memory_chunk(INTERP, content, set_size);
}
if (copysize < set_size)
memset(content + copysize, '\0', set_size - copysize);
SET_ATTR_allocated_size(INTERP, SELF, set_size);
SET_ATTR_content(INTERP, SELF, content);
}
SET_ATTR_size(INTERP, SELF, set_size);
}
}
/*
=item C<void set_string_native()>
Reset the buffer with the content of the string.
=cut
*/
VTABLE void set_string_native(STRING *new_string) {
INTVAL allocated_size;
INTVAL new_length;
GET_ATTR_allocated_size(INTERP, SELF, allocated_size);
new_length = Parrot_str_byte_length(interp, new_string);
if (allocated_size) {
unsigned char *content;
GET_ATTR_content(INTERP, SELF, content);
if (allocated_size < new_length) {
content = (unsigned char *)Parrot_gc_reallocate_memory_chunk(INTERP,
content, new_length);
}
memcpy(content, new_string->strstart, new_length);
SET_ATTR_content(INTERP, SELF, content);
}
else {
unsigned char * const content = (unsigned char *)
Parrot_gc_allocate_memory_chunk(INTERP, new_length);
memcpy(content, new_string->strstart, new_length);
SET_ATTR_content(INTERP, SELF, content);
}
SET_ATTR_source(INTERP, SELF, new_string);
SET_ATTR_size(INTERP, SELF, new_length);
SET_ATTR_allocated_size(INTERP, SELF, new_length);
}
/*
=item C<INTVAL get_integer_keyed_int()>
Get the value of the byte at position or 0 if out of bounds.
=cut
*/
VTABLE INTVAL get_integer_keyed_int(INTVAL position) {
INTVAL size;
GET_ATTR_size(INTERP, SELF, size);
if (position < 0 || position >= size)
return 0;
else {
unsigned char *content;
GET_ATTR_content(INTERP, SELF, content);
if (content == NULL) {
STRING *source;
GET_ATTR_source(INTERP, SELF, source);
if (STRING_IS_NULL(source))
return 0;
content = (unsigned char*)source->strstart;
}
return content[position];
}
}
/*
=item C<void set_integer_keyed_int()>
Set the value of the byte at position, resizing the buffer if the position
is out of current size.
=cut
*/
VTABLE void set_integer_keyed_int(INTVAL position, INTVAL value) {
unsigned char *content;
INTVAL size, allocated_size;
if (position < 0)
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
"Negative position not allowed");
GET_ATTR_allocated_size(INTERP, SELF, allocated_size);
if (position >= allocated_size) {
const INTVAL newsize = grow_to(position);
if (allocated_size == 0) {
INTVAL copysize = newsize;
STRING * source;
content = (unsigned char *)Parrot_gc_allocate_memory_chunk(INTERP, newsize);
GET_ATTR_source(INTERP, SELF, source);
if (!STRING_IS_NULL(source)) {
const INTVAL srclen = Parrot_str_byte_length(INTERP, source);
if (srclen < copysize)
copysize = srclen;
memcpy(content, source->strstart, copysize);
SET_ATTR_source(INTERP, SELF, STRINGNULL);
}
}
else {
GET_ATTR_content(INTERP, SELF, content);
content = (unsigned char *)
Parrot_gc_reallocate_memory_chunk(INTERP, content, newsize);
}
SET_ATTR_content(INTERP, SELF, content);
SET_ATTR_allocated_size(INTERP, SELF, newsize);
}
else
GET_ATTR_content(INTERP, SELF, content);
GET_ATTR_size(INTERP, SELF, size);
if (position >= size) {
size = position + 1;
SET_ATTR_size(INTERP, SELF, size);
}
content[position] = value;
}
/*
=item C<void push_integer(INTVAL value)>
Extends the buffer by adding a byte of value C<value> to the end.
=cut
*/
VTABLE void push_integer(INTVAL value) {
INTVAL size;
GET_ATTR_size(INTERP, SELF, size);
SELF.set_integer_keyed_int(size, value);
}
/*
=item C<PMC *get_pointer()>
Return a pointer to the content. Use with care.
=cut
*/
VTABLE void *get_pointer() {
unsigned char *content;
GET_ATTR_content(INTERP, SELF, content);
if (content == NULL) {
STRING *source;
GET_ATTR_source(INTERP, SELF, source);
if (! STRING_IS_NULL(source))
content = (unsigned char*)source->strstart;
}
return (void *)content;
}
/*
=item C<PMC *get_iter()>
Return a new Iterator for this PMC.
=cut
*/
VTABLE PMC *get_iter() {
return Parrot_pmc_new_init(INTERP, enum_class_ArrayIterator, SELF);
}
/*
=back
=head2 Methods
=over 4
=item C<get_string(string encoding)>
Create a string with the buffer content and the encoding specified.
=cut
*/
METHOD get_string(STRING *encodingname) {
STRING *result;
unsigned char *content;
INTVAL size;
const STR_VTABLE *encoding = Parrot_find_encoding_by_string(INTERP, encodingname);
GET_ATTR_content(INTERP, SELF, content);
GET_ATTR_size(INTERP, SELF, size);
if (content == NULL) {
STRING *source;
GET_ATTR_source(INTERP, SELF, source);
result = build_string_from_string(interp, source, 0, size, encoding);
}
else
result = build_string(INTERP, content, size, encoding);
RETURN(STRING *result);
}
/*
=item C<get_string_as(string as)>
Create a string with the buffer content and the same encoding
as the string argument.
=cut
*/
METHOD get_string_as(STRING *as :optional) {
STRING *result;
unsigned char *content;
INTVAL size;
const STR_VTABLE * const encoding =
STRING_IS_NULL(as) ? Parrot_default_encoding_ptr : as->encoding;
GET_ATTR_content(INTERP, SELF, content);
GET_ATTR_size(INTERP, SELF, size);
if (content == NULL) {
STRING *source;
GET_ATTR_source(INTERP, SELF, source);
result = build_string_from_string(interp, source, 0, size, encoding);
}
else
result = build_string(INTERP, content, size, encoding);
RETURN(STRING *result);
}
/*
=item C<get_chars(int pos, int length, string encoding)>
Get a string from the buffer content with the specified encoding and
length in codepoints.
=cut
*/
METHOD get_chars(INTVAL pos, INTVAL length, STRING *encodingname)
{
const STR_VTABLE * const encoding = Parrot_find_encoding_by_string(INTERP, encodingname);
STRING *result;
unsigned char *content;
INTVAL size;
GET_ATTR_content(interp, SELF, content);
GET_ATTR_size(interp, SELF, size);
if (pos < 0 || pos > size)
Parrot_ex_throw_from_c_args(INTERP, NULL,
EXCEPTION_OUT_OF_BOUNDS,
"get_chars: index out of bounds");
if (content == NULL) {
STRING *source;
GET_ATTR_source(INTERP, SELF, source);
if (! STRING_IS_NULL(source))
content = (unsigned char*)source->strstart;
}
result = Parrot_str_extract_chars(INTERP, (char *)content + pos,
size - pos, length, encoding);
RETURN(STRING *result);
}
} /* pmclass end */
/*
=back
=head2 Auxiliar functions
=over 4
=item C<static INTVAL grow_to(INTVAL position)>
Calculate new size enough for using position and with some margin to
decrease the number of reallocations.
=item C<static STRING * build_string(PARROT_INTERP, const unsigned char
*content, INTVAL size, const STR_VTABLE *encoding)>
Build a string from the buffer content with the encoding specified.
=item C<static STRING * build_string_from_string(PARROT_INTERP, STRING *from,
INTVAL pos, INTVAL size, const STR_VTABLE *encoding)>
Build a string from part of a string content with the encoding specified.
=cut
*/
PARROT_WARN_UNUSED_RESULT
static INTVAL
grow_to(INTVAL position)
{
ASSERT_ARGS(grow_to)
const UINTVAL blocksize = 2048;
const UINTVAL minsize = position + 1;
return (INTVAL) (minsize < 64 ? 64 :
minsize < 256 ? 256 :
minsize < 1024 ? 1024 :
((minsize + blocksize - 1) / blocksize) * blocksize);
}
PARROT_CANNOT_RETURN_NULL
PARROT_WARN_UNUSED_RESULT
static STRING *
build_string(PARROT_INTERP, ARGIN_NULLOK(const unsigned char *content),
INTVAL size, ARGIN(const STR_VTABLE *encoding))
{
ASSERT_ARGS(build_string)
if (encoding == NULL)
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_ENCODING,
"Invalid encoding");
else {
STRING * const result = Parrot_str_new_init(interp,
(const char *)content, size, encoding, 0);
return result;
}
}
PARROT_CANNOT_RETURN_NULL
PARROT_WARN_UNUSED_RESULT
static STRING *
build_string_from_string(PARROT_INTERP, ARGIN_NULLOK(STRING *from),
INTVAL pos, INTVAL size, ARGIN(const STR_VTABLE *encoding))
{
ASSERT_ARGS(build_string_from_string)
STRING *result;
if (STRING_IS_NULL(from))
result = Parrot_str_new_init(interp, NULL, 0, encoding, 0);
else {
result = Parrot_str_new_noinit(interp, size);
memcpy(result->strstart, from->strstart + pos, size);
result->bufused = size;
result->encoding = encoding;
encoding->scan(interp, result);
}
return result;
}
/*
=back
=cut
*/
/*
* Local variables:
* c-file-style: "parrot"
* End:
* vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
*/
Jump to Line
Something went wrong with that request. Please try again.