summaryrefslogtreecommitdiff
path: root/src/runtime/c/gu/in.c
diff options
context:
space:
mode:
authorkr.angelov <kr.angelov@gmail.com>2012-01-20 13:41:10 +0000
committerkr.angelov <kr.angelov@gmail.com>2012-01-20 13:41:10 +0000
commit2eee382a62a909d5a3f2f5eda94f30fe68fd5335 (patch)
treeb0b0d513535895f244214aebf6358e172b8dce6d /src/runtime/c/gu/in.c
parentb9728357126f8b9a6311cca17d9f0dcc2a7bfb9b (diff)
initial import of the C runtime
Diffstat (limited to 'src/runtime/c/gu/in.c')
-rw-r--r--src/runtime/c/gu/in.c421
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);