/* Copyright (c) 2024, Peter McGoron * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1) Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2) Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "uns.h" #include "uns_string.h" enum { ALLEN_IND = 0, LEN_IND = 1, BYTES_IND = 2, NUMBER_OF_IND = 3 }; static size_t get_size_t(Uns_GC gc, struct uns_ctr *root, size_t i) { size_t r; /* TODO: record type checking */ void *p = uns_get(gc, root->p, i, NULL); memcpy(&r, p, sizeof(r)); return r; } static void set_size_t(Uns_GC gc, struct uns_ctr *root, size_t i, size_t val) { void *p = uns_get(gc, root->p, i, NULL); memcpy(p, &val, sizeof(val)); } #define set_allen(gc,root,val) set_size_t(gc, root, ALLEN_IND, val) #define set_len(gc,root,val) set_size_t(gc, root, LEN_IND, val) static size_t uns_string_allen(Uns_GC gc, struct uns_ctr *root) { return get_size_t(gc, root, ALLEN_IND); } size_t uns_string_len(Uns_GC gc, struct uns_ctr *root) { return get_size_t(gc, root, LEN_IND); } char *uns_string_ptr(Uns_GC gc, struct uns_ctr *root) { return uns_get(gc, root->p, BYTES_IND, NULL); } void uns_string_alloc(Uns_GC gc, struct uns_ctr *root, size_t start_len) { unsigned char *p; root->p = uns_alloc_rec(gc, NUMBER_OF_IND, 0); /* The following is incorrect: * gc->record_set_ptr(root->p, ALLEN_IND, gc->alloc(gc, sizeof(size_t))); * This is because gc->alloc() can cause a collection, invalidating root->p, * but root->p may have already been put on the stack. */ p = uns_alloc(gc, sizeof(size_t), 0); uns_set(gc, root->p, ALLEN_IND, UNS_POINTER, p); set_allen(gc, root, start_len); p = uns_alloc(gc, sizeof(size_t), 0); uns_set(gc, root->p, LEN_IND, UNS_POINTER, p); set_len(gc, root, 0); p = uns_alloc(gc, start_len, 0); uns_set(gc, root->p, BYTES_IND, UNS_POINTER, p); } void uns_string_resize(Uns_GC gc, struct uns_ctr *root, size_t newlen) { struct uns_ctr tmp_new = {0}; size_t old_len = uns_string_len(gc, root); /* The temporary string needs to be added to the roots list because * there are multiple allocations that happen in the body of the string. */ uns_root_add(gc, &tmp_new); uns_string_alloc(gc, &tmp_new, newlen); if (newlen <= old_len) set_len(gc, &tmp_new, newlen); else set_len(gc, &tmp_new, old_len); memcpy(uns_string_ptr(gc, &tmp_new), uns_string_ptr(gc, root), uns_string_len(gc, root)); root->p = tmp_new.p; uns_root_remove(gc, &tmp_new); } void uns_string_ensure(Uns_GC gc, struct uns_ctr *root, size_t extent) { size_t used = uns_string_len(gc, root); size_t allen = uns_string_allen(gc, root); if (used + extent > allen) uns_string_resize(gc, root, used + extent); } void uns_string_append_bytes(Uns_GC gc, struct uns_ctr *to, const void *from, size_t bytes) { size_t len = uns_string_len(gc, to); uns_string_ensure(gc, to, bytes); memcpy(uns_string_ptr(gc, to) + len, from, bytes); set_len(gc, to, len + bytes); } void uns_string_append_char(Uns_GC gc, struct uns_ctr *root, char c) { uns_string_append_bytes(gc, root, &c, 1); } char *uns_string_cstring(Uns_GC gc, struct uns_ctr *root) { char *p; uns_string_ensure(gc, root, 1); p = uns_string_ptr(gc, root); p[uns_string_len(gc, root)] = 0; return p; }