diff options
| author | kr.angelov <kr.angelov@gmail.com> | 2013-09-17 12:45:00 +0000 |
|---|---|---|
| committer | kr.angelov <kr.angelov@gmail.com> | 2013-09-17 12:45:00 +0000 |
| commit | 2a49e4e1d64ef2df0bb2a8a3822f7fa1048e687f (patch) | |
| tree | a4584c3831aac1a692c8be37c0c6747480874c00 /src/runtime/c/gu/seq.c | |
| parent | f5461eb3d4eb2605b546a4ed202c12bcdaa1f4e4 (diff) | |
a major refactoring in the C runtime. GuList is now removed and replaced with GuSeq. The GuSeq/GuBuf API is simplified
Diffstat (limited to 'src/runtime/c/gu/seq.c')
| -rw-r--r-- | src/runtime/c/gu/seq.c | 201 |
1 files changed, 111 insertions, 90 deletions
diff --git a/src/runtime/c/gu/seq.c b/src/runtime/c/gu/seq.c index 5f5532013..cb6de42c9 100644 --- a/src/runtime/c/gu/seq.c +++ b/src/runtime/c/gu/seq.c @@ -1,35 +1,27 @@ #include <gu/out.h> #include <gu/seq.h> #include <gu/fun.h> +#include <gu/str.h> #include <gu/assert.h> #include <string.h> #include <stdlib.h> +struct GuSeq { + size_t len; + uint8_t data[0]; +}; struct GuBuf { - uint8_t* data; + GuSeq* seq; size_t elem_size; size_t avail_len; GuFinalizer fin; }; -GuBuf* -gu_seq_buf(GuSeq seq) -{ - gu_require(gu_tagged_tag(seq.w_) == 0); - return gu_word_ptr(seq.w_); -} - -GuSeq -gu_buf_seq(GuBuf* buf) -{ - return (GuSeq) { .w_ = gu_ptr_word(buf) }; -} - size_t -gu_buf_length(GuBuf* dyn) +gu_buf_length(GuBuf* buf) { - return (size_t)(((GuWord*)(void*)dyn)[-1] >> 1); + return buf->seq->len; } size_t @@ -38,58 +30,82 @@ gu_buf_avail(GuBuf* buf) return buf->avail_len; } - -static void -gu_buf_set_length(GuBuf* dyn, size_t new_len) -{ - ((GuWord*)(void*)dyn)[-1] = ((GuWord) new_len) << 1 | 0x1; -} - static void gu_buf_fini(GuFinalizer* fin) { GuBuf* buf = gu_container(fin, GuBuf, fin); - gu_mem_buf_free(buf->data); + if (buf->avail_len > 0) + gu_mem_buf_free(buf->seq); } GuBuf* gu_make_buf(size_t elem_size, GuPool* pool) { - GuBuf* buf = gu_new_prefixed(unsigned, GuBuf, pool); - gu_buf_set_length(buf, 0); + GuBuf* buf = gu_new(GuBuf, pool); + buf->seq = gu_empty_seq(); buf->elem_size = elem_size; - buf->data = NULL; buf->avail_len = 0; buf->fin.fn = gu_buf_fini; gu_pool_finally(pool, &buf->fin); - gu_buf_set_length(buf, 0); return buf; } -static const GuWord gu_empty_seq_[2] = {0, 0}; +size_t +gu_seq_length(GuSeq* seq) +{ + return seq->len; +} + +void* +gu_seq_data(GuSeq* seq) +{ + return seq->data; +} -GuSeq +static GuSeq gu_empty_seq_ = {0}; + +GuSeq* gu_empty_seq() { - return (GuSeq) { gu_tagged((void*)&gu_empty_seq_[1], 0) }; + return &gu_empty_seq_; } -GuSeq +GuSeq* gu_make_seq(size_t elem_size, size_t length, GuPool* pool) { - size_t size = elem_size * length; - if (0 < length && length <= GU_TAG_MAX) { - void* buf = gu_malloc(pool, size); - return (GuSeq) { gu_tagged(buf, length) }; - } else if (size == 0) { + GuSeq* seq = gu_malloc(pool, sizeof(GuSeq) + elem_size * length); + seq->len = length; + return seq; +} + +GuSeq* +gu_alloc_seq_(size_t elem_size, size_t length) +{ + if (length == 0) return gu_empty_seq(); - } else { - void* buf = gu_malloc_prefixed(pool, - gu_alignof(GuWord), - sizeof(GuWord), - 0, size); - ((GuWord*) buf)[-1] = ((GuWord) length) << 1; - return (GuSeq) { gu_tagged(buf, 0) }; - } + + size_t real_size; + GuSeq* seq = gu_mem_buf_alloc(sizeof(GuSeq) + elem_size * length, &real_size); + seq->len = (real_size - sizeof(GuSeq)) / elem_size; + return seq; +} + +GuSeq* +gu_realloc_seq_(GuSeq* seq, size_t elem_size, size_t length) +{ + size_t real_size; + GuSeq* new_seq = (seq == NULL || seq == gu_empty_seq()) ? + gu_mem_buf_alloc(sizeof(GuSeq) + elem_size * length, &real_size) : + gu_mem_buf_realloc(seq, sizeof(GuSeq) + elem_size * length, &real_size); + new_seq->len = (real_size - sizeof(GuSeq)) / elem_size; + return new_seq; +} + +void +gu_seq_free(GuSeq* seq) +{ + if (seq == NULL || seq == gu_empty_seq()) + return; + gu_mem_buf_free(seq); } static void @@ -98,17 +114,30 @@ gu_buf_require(GuBuf* buf, size_t req_len) if (req_len <= buf->avail_len) { return; } - size_t req_size = buf->elem_size * req_len; + + size_t req_size = sizeof(GuSeq) + buf->elem_size * req_len; size_t real_size; - buf->data = gu_mem_buf_realloc(buf->data, req_size, - &real_size); - buf->avail_len = real_size / buf->elem_size; + + if (buf->seq == NULL || buf->seq == gu_empty_seq()) { + buf->seq = gu_mem_buf_alloc(req_size, &real_size); + buf->seq->len = 0; + } else { + buf->seq = gu_mem_buf_realloc(buf->seq, req_size, &real_size); + } + + buf->avail_len = (real_size - sizeof(GuSeq)) / buf->elem_size; } void* gu_buf_data(GuBuf* buf) { - return buf->data; + return &buf->seq->data; +} + +GuSeq* +gu_buf_data_seq(GuBuf* buf) +{ + return buf->seq; } void* @@ -117,8 +146,8 @@ gu_buf_extend_n(GuBuf* buf, size_t n_elems) size_t len = gu_buf_length(buf); size_t new_len = len + n_elems; gu_buf_require(buf, new_len); - gu_buf_set_length(buf, new_len); - return &buf->data[buf->elem_size * len]; + buf->seq->len = new_len; + return &buf->seq->data[buf->elem_size * len]; } void* @@ -130,7 +159,6 @@ gu_buf_extend(GuBuf* buf) void gu_buf_push_n(GuBuf* buf, const void* data, size_t n_elems) { - void* p = gu_buf_extend_n(buf, n_elems); memcpy(p, data, buf->elem_size * n_elems); } @@ -140,8 +168,8 @@ gu_buf_trim_n(GuBuf* buf, size_t n_elems) { gu_require(n_elems <= gu_buf_length(buf)); size_t new_len = gu_buf_length(buf) - n_elems; - gu_buf_set_length(buf, new_len); - return &buf->data[buf->elem_size * new_len]; + buf->seq->len = new_len; + return &buf->seq->data[buf->elem_size * new_len]; } const void* @@ -153,7 +181,7 @@ gu_buf_trim(GuBuf* buf) void gu_buf_flush(GuBuf* buf) { - gu_buf_set_length(buf, 0); + buf->seq->len = 0; } void @@ -163,11 +191,11 @@ gu_buf_pop_n(GuBuf* buf, size_t n_elems, void* data_out) memcpy(data_out, p, buf->elem_size * n_elems); } -GuSeq +GuSeq* gu_buf_freeze(GuBuf* buf, GuPool* pool) { size_t len = gu_buf_length(buf); - GuSeq seq = gu_make_seq(buf->elem_size, len, pool); + GuSeq* seq = gu_make_seq(buf->elem_size, len, pool); void* bufdata = gu_buf_data(buf); void* seqdata = gu_seq_data(seq); memcpy(seqdata, bufdata, buf->elem_size * len); @@ -182,32 +210,32 @@ gu_quick_sort(GuBuf *buf, GuOrder *order, int left, int right) void* pivot = alloca(buf->elem_size); memcpy(pivot, - &buf->data[buf->elem_size * left], + &buf->seq->data[buf->elem_size * left], buf->elem_size); while (left < right) { - while ((order->compare(order, &buf->data[buf->elem_size * right], pivot) >= 0) && (left < right)) + while ((order->compare(order, &buf->seq->data[buf->elem_size * right], pivot) >= 0) && (left < right)) right--; if (left != right) { - memcpy(&buf->data[buf->elem_size * left], - &buf->data[buf->elem_size * right], + memcpy(&buf->seq->data[buf->elem_size * left], + &buf->seq->data[buf->elem_size * right], buf->elem_size); left++; } - while ((order->compare(order, &buf->data[buf->elem_size * left], pivot) <= 0) && (left < right)) + while ((order->compare(order, &buf->seq->data[buf->elem_size * left], pivot) <= 0) && (left < right)) left++; if (left != right) { - memcpy(&buf->data[buf->elem_size * right], - &buf->data[buf->elem_size * left], + memcpy(&buf->seq->data[buf->elem_size * right], + &buf->seq->data[buf->elem_size * left], buf->elem_size); right--; } } - memcpy(&buf->data[buf->elem_size * left], + memcpy(&buf->seq->data[buf->elem_size * left], pivot, buf->elem_size); int index = left; @@ -235,7 +263,7 @@ gu_buf_binsearch(GuBuf *buf, GuOrder *order, void *value) while (i <= j) { size_t k = (i+j) / 2; - int cmp = order->compare(order, value, &buf->data[buf->elem_size * k]); + int cmp = order->compare(order, value, &buf->seq->data[buf->elem_size * k]); if (cmp < 0) { j = k-1; @@ -243,7 +271,7 @@ gu_buf_binsearch(GuBuf *buf, GuOrder *order, void *value) i = k+1; } else { memcpy(value, - &buf->data[buf->elem_size * k], + &buf->seq->data[buf->elem_size * k], buf->elem_size); return true; } @@ -258,16 +286,16 @@ gu_heap_siftdown(GuBuf *buf, GuOrder *order, { while (pos > startpos) { int parentpos = (pos - 1) >> 1; - void *parent = &buf->data[buf->elem_size * parentpos]; + void *parent = &buf->seq->data[buf->elem_size * parentpos]; if (order->compare(order, value, parent) >= 0) break; - memcpy(&buf->data[buf->elem_size * pos], parent, buf->elem_size); + memcpy(&buf->seq->data[buf->elem_size * pos], parent, buf->elem_size); pos = parentpos; } - memcpy(&buf->data[buf->elem_size * pos], value, buf->elem_size); + memcpy(&buf->seq->data[buf->elem_size * pos], value, buf->elem_size); } static void @@ -282,13 +310,13 @@ gu_heap_siftup(GuBuf *buf, GuOrder *order, int rightpos = childpos + 1; if (rightpos < endpos && order->compare(order, - &buf->data[buf->elem_size * childpos], - &buf->data[buf->elem_size * rightpos]) >= 0) { + &buf->seq->data[buf->elem_size * childpos], + &buf->seq->data[buf->elem_size * rightpos]) >= 0) { childpos = rightpos; } - memcpy(&buf->data[buf->elem_size * pos], - &buf->data[buf->elem_size * childpos], buf->elem_size); + memcpy(&buf->seq->data[buf->elem_size * pos], + &buf->seq->data[buf->elem_size * childpos], buf->elem_size); pos = childpos; childpos = 2*pos + 1; } @@ -309,7 +337,7 @@ gu_buf_heap_pop(GuBuf *buf, GuOrder *order, void* data_out) const void* last = gu_buf_trim(buf); // raises an error if empty if (gu_buf_length(buf) > 0) { - memcpy(data_out, buf->data, buf->elem_size); + memcpy(data_out, buf->seq->data, buf->elem_size); gu_heap_siftup(buf, order, last, 0); } else { memcpy(data_out, last, buf->elem_size); @@ -321,7 +349,7 @@ gu_buf_heap_replace(GuBuf *buf, GuOrder *order, void *value, void *data_out) { gu_require(gu_buf_length(buf) > 0); - memcpy(data_out, buf->data, buf->elem_size); + memcpy(data_out, buf->seq->data, buf->elem_size); gu_heap_siftup(buf, order, value, 0); } @@ -332,7 +360,7 @@ gu_buf_heapify(GuBuf *buf, GuOrder *order) void *value = alloca(buf->elem_size); for (size_t i = 0; i < middle; i++) { - memcpy(value, &buf->data[buf->elem_size * i], buf->elem_size); + memcpy(value, &buf->seq->data[buf->elem_size * i], buf->elem_size); gu_heap_siftup(buf, order, value, i); } } @@ -370,7 +398,7 @@ gu_buf_outbuf_begin(GuOutStream* stream, size_t req, size_t* sz_out, GuExn* err) size_t avail = buf->avail_len; gu_assert(len < avail); *sz_out = esz * (avail - len); - return &buf->data[len * esz]; + return &buf->seq->data[len * esz]; } static void @@ -383,7 +411,7 @@ gu_buf_outbuf_end(GuOutStream* stream, size_t sz, GuExn* err) size_t elem_size = buf->elem_size; gu_require(sz % elem_size == 0); gu_require(sz < elem_size * (len - buf->avail_len)); - gu_buf_set_length(buf, len + (sz / elem_size)); + buf->seq->len = len + (sz / elem_size); } GuOut* @@ -398,23 +426,16 @@ gu_buf_out(GuBuf* buf, GuPool* pool) return gu_new_out(&bout->stream, pool); } -const GuSeq -gu_null_seq = GU_NULL_SEQ; - - #include <gu/type.h> GU_DEFINE_KIND(GuSeq, GuOpaque); GU_DEFINE_KIND(GuBuf, abstract); -GU_DEFINE_TYPE(GuChars, GuSeq, gu_type(char)); -GU_DEFINE_TYPE(GuBytes, GuSeq, gu_type(uint8_t)); - char* -gu_chars_str(GuChars chars, GuPool* pool) +gu_char_buf_str(GuCharBuf* chars, GuPool* pool) { - size_t len = gu_seq_length(chars); - char* data = gu_seq_data(chars); + size_t len = gu_buf_length(chars); + char* data = gu_buf_data(chars); char* str = gu_new_str(len, pool); memcpy(str, data, len); return str; |
