diff options
| author | kr.angelov <kr.angelov@gmail.com> | 2012-01-20 13:41:10 +0000 |
|---|---|---|
| committer | kr.angelov <kr.angelov@gmail.com> | 2012-01-20 13:41:10 +0000 |
| commit | 2eee382a62a909d5a3f2f5eda94f30fe68fd5335 (patch) | |
| tree | b0b0d513535895f244214aebf6358e172b8dce6d /src/runtime/c/gu/in.c | |
| parent | b9728357126f8b9a6311cca17d9f0dcc2a7bfb9b (diff) | |
initial import of the C runtime
Diffstat (limited to 'src/runtime/c/gu/in.c')
| -rw-r--r-- | src/runtime/c/gu/in.c | 421 |
1 files changed, 421 insertions, 0 deletions
diff --git a/src/runtime/c/gu/in.c b/src/runtime/c/gu/in.c new file mode 100644 index 000000000..4238475f8 --- /dev/null +++ b/src/runtime/c/gu/in.c @@ -0,0 +1,421 @@ +#include <gu/in.h> +#include <gu/bits.h> +#include <math.h> + +GU_DEFINE_TYPE(GuEOF, abstract, _); + + +static bool +gu_in_is_buffering(GuIn* in) +{ + return (in->buf_end != NULL); +} + +static void +gu_in_end_buffering(GuIn* in, GuExn* err) +{ + if (!gu_in_is_buffering(in)) { + return; + } + if (in->stream->end_buffer) { + size_t len = ((ptrdiff_t) in->buf_size) + in->buf_curr; + in->stream->end_buffer(in->stream, len, err); + } + in->buf_curr = 0; + in->buf_size = 0; + in->buf_end = NULL; +} + +static bool +gu_in_begin_buffering(GuIn* in, GuExn* err) +{ + if (gu_in_is_buffering(in)) { + if (in->buf_curr < 0) { + return true; + } else { + gu_in_end_buffering(in, err); + if (!gu_ok(err)) return false; + } + } + if (!in->stream->begin_buffer) { + return false; + } + size_t sz = 0; + const uint8_t* new_buf = + in->stream->begin_buffer(in->stream, &sz, err); + if (new_buf) { + in->buf_end = &new_buf[sz]; + in->buf_curr = -(ptrdiff_t) sz; + in->buf_size = sz; + return true; + } + return false; +} + +static size_t +gu_in_input(GuIn* in, uint8_t* dst, size_t sz, GuExn* err) +{ + if (sz == 0) { + return 0; + } + gu_in_end_buffering(in, err); + if (!gu_ok(err)) { + return 0; + } + GuInStream* stream = in->stream; + if (stream->input) { + return stream->input(stream, dst, sz, err); + } + gu_raise(err, GuEOF); + return 0; +} + +size_t +gu_in_some(GuIn* in, uint8_t* dst, size_t sz, GuExn* err) +{ + gu_require(sz <= PTRDIFF_MAX); + if (!gu_in_begin_buffering(in, err)) { + if (!gu_ok(err)) return 0; + return gu_in_input(in, dst, sz, err); + } + size_t real_sz = GU_MIN(sz, (size_t)(-in->buf_curr)); + memcpy(dst, &in->buf_end[in->buf_curr], real_sz); + in->buf_curr += real_sz; + return real_sz; +} + +void +gu_in_bytes_(GuIn* in, uint8_t* dst, size_t sz, GuExn* err) +{ + size_t avail_sz = GU_MIN(sz, (size_t)(-in->buf_curr)); + memcpy(dst, &in->buf_end[in->buf_curr], avail_sz); + in->buf_curr += avail_sz; + if (avail_sz < sz) { + gu_in_input(in, &dst[avail_sz], sz - avail_sz, err); + } +} + +const uint8_t* +gu_in_begin_span(GuIn* in, size_t *sz_out, GuExn* err) +{ + if (!gu_in_begin_buffering(in, err)) { + return NULL; + } + *sz_out = (size_t) -in->buf_curr; + return &in->buf_end[in->buf_curr]; +} + +void +gu_in_end_span(GuIn* in, size_t consumed) +{ + gu_require(consumed <= (size_t) -in->buf_curr); + in->buf_curr += (ptrdiff_t) consumed; +} + +uint8_t +gu_in_u8_(GuIn* in, GuExn* err) +{ + if (gu_in_begin_buffering(in, err) && in->buf_curr < 0) { + return in->buf_end[in->buf_curr++]; + } + uint8_t u = 0; + size_t r = gu_in_input(in, &u, 1, err); + if (r < 1) { + gu_raise(err, GuEOF); + return 0; + } + return u; +} + +static uint64_t +gu_in_be(GuIn* in, GuExn* err, int n) +{ + uint8_t buf[8]; + gu_in_bytes(in, buf, n, err); + uint64_t u = 0; + for (int i = 0; i < n; i++) { + u = u << 8 | buf[i]; + } + return u; +} + +static uint64_t +gu_in_le(GuIn* in, GuExn* err, int n) +{ + uint8_t buf[8]; + gu_in_bytes(in, buf, n, err); + uint64_t u = 0; + for (int i = 0; i < n; i++) { + u = u << 8 | buf[i]; + } + return u; +} + +int8_t +gu_in_s8(GuIn* in, GuExn* err) +{ + return gu_decode_2c8(gu_in_u8(in, err), err); +} + + +uint16_t +gu_in_u16le(GuIn* in, GuExn* err) +{ + return gu_in_le(in, err, 2); +} + +int16_t +gu_in_s16le(GuIn* in, GuExn* err) +{ + return gu_decode_2c16(gu_in_u16le(in, err), err); +} + +uint16_t +gu_in_u16be(GuIn* in, GuExn* err) +{ + return gu_in_be(in, err, 2); +} + +int16_t +gu_in_s16be(GuIn* in, GuExn* err) +{ + return gu_decode_2c16(gu_in_u16be(in, err), err); +} + + +uint32_t +gu_in_u32le(GuIn* in, GuExn* err) +{ + return gu_in_le(in, err, 4); +} + +int32_t +gu_in_s32le(GuIn* in, GuExn* err) +{ + return gu_decode_2c32(gu_in_u32le(in, err), err); +} + +uint32_t +gu_in_u32be(GuIn* in, GuExn* err) +{ + return gu_in_be(in, err, 4); +} + +int32_t +gu_in_s32be(GuIn* in, GuExn* err) +{ + return gu_decode_2c32(gu_in_u32be(in, err), err); +} + + +uint64_t +gu_in_u64le(GuIn* in, GuExn* err) +{ + return gu_in_le(in, err, 8); +} + +int64_t +gu_in_s64le(GuIn* in, GuExn* err) +{ + return gu_decode_2c64(gu_in_u64le(in, err), err); +} + +uint64_t +gu_in_u64be(GuIn* in, GuExn* err) +{ + return gu_in_be(in, err, 8); +} + +int64_t +gu_in_s64be(GuIn* in, GuExn* err) +{ + return gu_decode_2c64(gu_in_u64be(in, err), err); +} + +double +gu_in_f64le(GuIn* in, GuExn* err) +{ + return gu_decode_double(gu_in_u64le(in, err)); +} + +double +gu_in_f64be(GuIn* in, GuExn* err) +{ + return gu_decode_double(gu_in_u64le(in, err)); +} + + +static void +gu_in_fini(GuFinalizer* fin) +{ + GuIn* in = gu_container(fin, GuIn, fini); + GuPool* pool = gu_local_pool(); + GuExn* err = gu_exn(NULL, type, pool); + gu_in_end_buffering(in, err); + gu_pool_free(pool); +} + +GuIn +gu_init_in(GuInStream* stream) +{ + return (GuIn) { + .buf_end = NULL, + .buf_curr = 0, + .buf_size = 0, + .stream = stream, + .fini.fn = gu_in_fini + }; +} + +GuIn* +gu_new_in(GuInStream* stream, GuPool* pool) +{ + GuIn* in = gu_new(GuIn, pool); + *in = gu_init_in(stream); + return in; +} + + +typedef struct GuProxyInStream GuProxyInStream; + +struct GuProxyInStream { + GuInStream stream; + GuIn* real_in; +}; + +static const uint8_t* +gu_proxy_in_begin_buffer(GuInStream* self, size_t* sz_out, GuExn* err) +{ + GuProxyInStream* pis = gu_container(self, GuProxyInStream, stream); + return gu_in_begin_span(pis->real_in, sz_out, err); +} + +static void +gu_proxy_in_end_buffer(GuInStream* self, size_t sz, GuExn* err) +{ + GuProxyInStream* pis = gu_container(self, GuProxyInStream, stream); + gu_in_end_span(pis->real_in, sz); +} + +static size_t +gu_proxy_in_input(GuInStream* self, uint8_t* dst, size_t sz, GuExn* err) +{ + GuProxyInStream* pis = gu_container(self, GuProxyInStream, stream); + return gu_in_some(pis->real_in, dst, sz, err); +} + +GuInStream* +gu_in_proxy_stream(GuIn* in, GuPool* pool) +{ + return &gu_new_s( + pool, GuProxyInStream, + .stream.begin_buffer = gu_proxy_in_begin_buffer, + .stream.end_buffer = gu_proxy_in_end_buffer, + .stream.input = gu_proxy_in_input, + .real_in = in)->stream; +} + +enum { + GU_BUFFERED_IN_BUF_SIZE = 4096 +}; + +typedef struct GuBufferedInStream GuBufferedInStream; + +struct GuBufferedInStream { + GuInStream stream; + size_t alloc; + size_t have; + size_t curr; + GuIn* in; + uint8_t buf[]; +}; + +static const uint8_t* +gu_buffered_in_begin_buffer(GuInStream* self, size_t* sz_out, GuExn* err) +{ + GuBufferedInStream* bis = + gu_container(self, GuBufferedInStream, stream); + if (bis->curr == bis->have) { + bis->curr = 0; + bis->have = gu_in_some(bis->in, bis->buf, bis->alloc, err); + if (!gu_ok(err)) return NULL; + } + *sz_out = bis->have - bis->curr; + return &bis->buf[bis->curr]; +} + +static void +gu_buffered_in_end_buffer(GuInStream* self, size_t consumed, GuExn* err) +{ + GuBufferedInStream* bis = + gu_container(self, GuBufferedInStream, stream); + gu_require(consumed < bis->have - bis->curr); + bis->curr += consumed; +} + +static size_t +gu_buffered_in_input(GuInStream* self, uint8_t* dst, size_t sz, GuExn* err) +{ + GuBufferedInStream* bis = + gu_container(self, GuBufferedInStream, stream); + return gu_in_some(bis->in, dst, sz, err); +} + +GuIn* +gu_buffered_in(GuIn* in, size_t buf_sz, GuPool* pool) +{ + GuBufferedInStream* bis = gu_new_flex(pool, GuBufferedInStream, + buf, buf_sz); + bis->stream = (GuInStream) { + .begin_buffer = gu_buffered_in_begin_buffer, + .end_buffer = gu_buffered_in_end_buffer, + .input = gu_buffered_in_input + }; + bis->have = bis->curr = 0; + bis->alloc = buf_sz; + return gu_new_in(&bis->stream, pool); +} + +typedef struct GuDataIn GuDataIn; + +struct GuDataIn { + GuInStream stream; + const uint8_t* data; + size_t sz; +}; + +static const uint8_t* +gu_data_in_begin_buffer(GuInStream* self, size_t* sz_out, GuExn* err) +{ + (void) err; + GuDataIn* di = gu_container(self, GuDataIn, stream); + const uint8_t* buf = di->data; + if (buf) { + *sz_out = di->sz; + di->data = NULL; + di->sz = 0; + } + return buf; +} + +GuIn* +gu_data_in(const uint8_t* data, size_t sz, GuPool* pool) +{ + GuDataIn* di = gu_new_s(pool, GuDataIn, + .stream.begin_buffer = gu_data_in_begin_buffer, + .data = data, + .sz = sz); + return gu_new_in(&di->stream, pool); +} + +extern inline uint8_t +gu_in_u8(GuIn* restrict in, GuExn* err); + +extern inline void +gu_in_bytes(GuIn* in, uint8_t* buf, size_t sz, GuExn* err); + +extern inline int +gu_in_peek_u8(GuIn* restrict in); + +extern inline void +gu_in_consume(GuIn* restrict in, size_t sz); |
