diff options
Diffstat (limited to 'fluent-bit/lib/avro/src/string.c')
-rw-r--r-- | fluent-bit/lib/avro/src/string.c | 304 |
1 files changed, 304 insertions, 0 deletions
diff --git a/fluent-bit/lib/avro/src/string.c b/fluent-bit/lib/avro/src/string.c new file mode 100644 index 00000000..f5cde949 --- /dev/null +++ b/fluent-bit/lib/avro/src/string.c @@ -0,0 +1,304 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#include "avro_private.h" +#include "avro/data.h" +#include "avro/allocation.h" +#include "avro/errors.h" + +#ifndef AVRO_STRING_DEBUG +#define AVRO_STRING_DEBUG 0 +#endif + +#if AVRO_STRING_DEBUG +#include <stdio.h> +#define DEBUG(...) \ + do { \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ + } while (0) +#else +#define DEBUG(...) /* don't print messages */ +#endif + + +/* + * A resizable wrapped buffer implementation. This implementation makes + * actual copies in its copy method; if we wanted a zero-copy solution + * here, then we'd have to keep track of all copies of the buffer, so + * that we can update pointers whenever the buffer is resized (since + * this might change the location of the memory region). + */ + +struct avro_wrapped_resizable { + size_t buf_size; +}; + +#define avro_wrapped_resizable_size(sz) \ + (sizeof(struct avro_wrapped_resizable) + (sz)) + +static void +avro_wrapped_resizable_free(avro_wrapped_buffer_t *self) +{ + DEBUG("--- Freeing resizable <%p:%" PRIsz "> (%p)", self->buf, self->size, self->user_data); + struct avro_wrapped_resizable *resizable = (struct avro_wrapped_resizable *) self->user_data; + avro_free(resizable, avro_wrapped_resizable_size(resizable->buf_size)); +} + +static int +avro_wrapped_resizable_resize(avro_wrapped_buffer_t *self, size_t desired) +{ + struct avro_wrapped_resizable *resizable = (struct avro_wrapped_resizable *) self->user_data; + + /* + * If we've already allocated enough memory for the desired + * size, there's nothing to do. + */ + + if (resizable->buf_size >= desired) { + return 0; + } + + size_t new_buf_size = resizable->buf_size * 2; + if (desired > new_buf_size) { + new_buf_size = desired; + } + + DEBUG("--- Resizing <%p:%" PRIsz "> (%p) -> %" PRIsz, + self->buf, self->buf_size, self->user_data, new_buf_size); + + struct avro_wrapped_resizable *new_resizable = + (struct avro_wrapped_resizable *) avro_realloc(resizable, + avro_wrapped_resizable_size(resizable->buf_size), + avro_wrapped_resizable_size(new_buf_size)); + if (new_resizable == NULL) { + return ENOMEM; + } + DEBUG("--- New buffer <%p:%" PRIsz ">", new_buf, new_buf_size); + + new_resizable->buf_size = new_buf_size; + + char *old_buf = (char *) resizable; + char *new_buf = (char *) new_resizable; + + ptrdiff_t offset = (char *) self->buf - old_buf; + DEBUG("--- Old data pointer is %p", self->buf); + self->buf = new_buf + offset; + self->user_data = new_resizable; + DEBUG("--- New data pointer is %p", self->buf); + return 0; +} + +static int +avro_wrapped_resizable_new(avro_wrapped_buffer_t *dest, size_t buf_size) +{ + size_t allocated_size = avro_wrapped_resizable_size(buf_size); + struct avro_wrapped_resizable *resizable = + (struct avro_wrapped_resizable *) avro_malloc(allocated_size); + if (resizable == NULL) { + return ENOMEM; + } + + resizable->buf_size = buf_size; + + dest->buf = ((char *) resizable) + sizeof(struct avro_wrapped_resizable); + DEBUG("--- Creating resizable <%p:%" PRIsz "> (%p)", dest->buf, buf_size, resizable); + dest->size = buf_size; + dest->user_data = resizable; + dest->free = avro_wrapped_resizable_free; + dest->copy = NULL; + dest->slice = NULL; + return 0; +} + +#define is_resizable(buf) \ + ((buf).free == avro_wrapped_resizable_free) + + + +void +avro_raw_string_init(avro_raw_string_t *str) +{ + memset(str, 0, sizeof(avro_raw_string_t)); +} + + +void +avro_raw_string_clear(avro_raw_string_t *str) +{ + /* + * If the string's buffer is one that we control, then we don't + * free it; that lets us reuse the storage on the next call to + * avro_raw_string_set[_length]. + */ + + if (is_resizable(str->wrapped)) { + DEBUG("--- Clearing resizable buffer"); + str->wrapped.size = 0; + } else { + DEBUG("--- Freeing wrapped buffer"); + avro_wrapped_buffer_free(&str->wrapped); + avro_raw_string_init(str); + } +} + + +void +avro_raw_string_done(avro_raw_string_t *str) +{ + avro_wrapped_buffer_free(&str->wrapped); + avro_raw_string_init(str); +} + + +/** + * Makes sure that the string's buffer is one that we allocated + * ourselves, and that the buffer is big enough to hold a string of the + * given length. + */ + +static int +avro_raw_string_ensure_buf(avro_raw_string_t *str, size_t length) +{ + int rval; + + DEBUG("--- Ensuring resizable buffer of size %" PRIsz, length); + if (is_resizable(str->wrapped)) { + /* + * If we've already got a resizable buffer, just have it + * resize itself. + */ + + return avro_wrapped_resizable_resize(&str->wrapped, length); + } else { + /* + * Stash a copy of the old wrapped buffer, and then + * create a new resizable buffer to store our content + * in. + */ + + avro_wrapped_buffer_t orig = str->wrapped; + check(rval, avro_wrapped_resizable_new(&str->wrapped, length)); + + /* + * If there was any content in the old wrapped buffer, + * copy it into the new resizable one. + */ + + if (orig.size > 0) { + size_t to_copy = + (orig.size < length)? orig.size: length; + memcpy((void *) str->wrapped.buf, orig.buf, to_copy); + } + avro_wrapped_buffer_free(&orig); + + return 0; + } +} + + +void +avro_raw_string_set_length(avro_raw_string_t *str, + const void *src, size_t length) +{ + avro_raw_string_ensure_buf(str, length+1); + memcpy((void *) str->wrapped.buf, src, length); + ((char *) str->wrapped.buf)[length] = '\0'; + str->wrapped.size = length; +} + + +void avro_raw_string_append_length(avro_raw_string_t *str, + const void *src, + size_t length) +{ + if (avro_raw_string_length(str) == 0) { + return avro_raw_string_set_length(str, src, length); + } + + avro_raw_string_ensure_buf(str, str->wrapped.size + length); + memcpy((char *) str->wrapped.buf + str->wrapped.size, src, length); + str->wrapped.size += length; +} + + +void +avro_raw_string_set(avro_raw_string_t *str, const char *src) +{ + size_t length = strlen(src); + avro_raw_string_ensure_buf(str, length+1); + memcpy((void *) str->wrapped.buf, src, length+1); + str->wrapped.size = length+1; +} + + +void +avro_raw_string_append(avro_raw_string_t *str, const char *src) +{ + if (avro_raw_string_length(str) == 0) { + return avro_raw_string_set(str, src); + } + + /* Assume that str->wrapped.size includes a NUL terminator */ + size_t length = strlen(src); + avro_raw_string_ensure_buf(str, str->wrapped.size + length); + memcpy((char *) str->wrapped.buf + str->wrapped.size - 1, src, length+1); + str->wrapped.size += length; +} + + +void +avro_raw_string_give(avro_raw_string_t *str, + avro_wrapped_buffer_t *src) +{ + DEBUG("--- Giving control of <%p:%" PRIsz "> (%p) to string", + src->buf, src->size, src); + avro_wrapped_buffer_free(&str->wrapped); + avro_wrapped_buffer_move(&str->wrapped, src); +} + +int +avro_raw_string_grab(const avro_raw_string_t *str, + avro_wrapped_buffer_t *dest) +{ + return avro_wrapped_buffer_copy(dest, &str->wrapped, 0, str->wrapped.size); +} + + +int +avro_raw_string_equals(const avro_raw_string_t *str1, + const avro_raw_string_t *str2) +{ + if (str1 == str2) { + return 1; + } + + if (!str1 || !str2) { + return 0; + } + + if (str1->wrapped.size != str2->wrapped.size) { + return 0; + } + + return (memcmp(str1->wrapped.buf, str2->wrapped.buf, + str1->wrapped.size) == 0); +} |