aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Noll <nbnoll@eml.cc>2020-04-18 13:40:53 -0700
committerNicholas Noll <nbnoll@eml.cc>2020-04-18 13:40:53 -0700
commit21055a1e5d34dda1b8151dd46a6bedca22bd73d9 (patch)
tree721044b20eb1c6f00d63a70f59a07f8b40e45ee1
parent392c9aff947a41e7e0da0b1a9612e174cfa956a7 (diff)
feat: added prototype of io/buffered io
-rw-r--r--compile_commands.json44
-rw-r--r--include/bufio.h27
-rw-r--r--include/io.h34
-rw-r--r--src/bufio/buffer.c24
-rw-r--r--src/bufio/impl.h34
-rw-r--r--src/bufio/reader.c198
-rw-r--r--src/bufio/rules.mk38
-rw-r--r--src/bufio/writer.c95
-rw-r--r--src/test.c2
9 files changed, 490 insertions, 6 deletions
diff --git a/compile_commands.json b/compile_commands.json
index bc87fa4..a125285 100644
--- a/compile_commands.json
+++ b/compile_commands.json
@@ -9,6 +9,38 @@
"-fms-extensions",
"-Iinclude",
"-o",
+ "build/bufio/bufio.o",
+ "src/bufio/bufio.c"
+ ],
+ "directory": "/home/nolln/root",
+ "file": "src/bufio/bufio.c"
+ },
+ {
+ "arguments": [
+ "clang",
+ "-c",
+ "-g",
+ "-fno-strict-aliasing",
+ "-fwrapv",
+ "-fms-extensions",
+ "-Iinclude",
+ "-o",
+ "build/error.o",
+ "src/error.c"
+ ],
+ "directory": "/home/nolln/root",
+ "file": "src/error.c"
+ },
+ {
+ "arguments": [
+ "clang",
+ "-c",
+ "-g",
+ "-fno-strict-aliasing",
+ "-fwrapv",
+ "-fms-extensions",
+ "-Iinclude",
+ "-o",
"build/string.o",
"src/string.c"
],
@@ -41,11 +73,11 @@
"-fms-extensions",
"-Iinclude",
"-o",
- "build/coro.o",
- "src/coro.c"
+ "build/test.o",
+ "src/test.c"
],
"directory": "/home/nolln/root",
- "file": "src/coro.c"
+ "file": "src/test.c"
},
{
"arguments": [
@@ -57,10 +89,10 @@
"-fms-extensions",
"-Iinclude",
"-o",
- "build/error.o",
- "src/error.c"
+ "build/coro.o",
+ "src/coro.c"
],
"directory": "/home/nolln/root",
- "file": "src/error.c"
+ "file": "src/coro.c"
}
] \ No newline at end of file
diff --git a/include/bufio.h b/include/bufio.h
new file mode 100644
index 0000000..b672563
--- /dev/null
+++ b/include/bufio.h
@@ -0,0 +1,27 @@
+#pragma once
+
+typedef struct bufio·Reader bufio·Reader;
+
+bufio·Reader *bufio·newreader(io·Reader r);
+error bufio·freereader(bufio·Reader *r);
+
+int bufio·read(bufio·Reader *r, byte *buf, int n);
+int bufio·readln(bufio·Reader *r, byte *buf, int n, error* err);
+byte bufio·get(bufio·Reader *r);
+error bufio·unget(bufio·Reader *r);
+byte bufio·peek(bufio·Reader *r);
+int bufio·peekfor(bufio·Reader *r, byte *buf, int n);
+void bufio·discard(bufio·Reader *r, int n);
+void bufio·clear(bufio·Reader *r);
+
+typedef struct bufio·Writer bufio·Writer;
+
+bufio·Writer *bufio·newwriter(io·Writer w);
+error bufio·freewriter(bufio·Writer *w);
+
+int bufio·write(bufio·Writer *w, byte *buf, int n);
+error bufio·put(bufio·Writer *w, byte b);
+error bufio·flush(bufio·Writer* w);
+
+/* TODO */
+typedef struct bufio·Scanner bufio·Scanner;
diff --git a/include/io.h b/include/io.h
new file mode 100644
index 0000000..9813b85
--- /dev/null
+++ b/include/io.h
@@ -0,0 +1,34 @@
+#pragma once
+
+typedef struct io·Reader
+{
+ Iface impl;
+ int (*read)(void*, byte *buf, int n);
+} io·Reader;
+
+typedef struct io·ByteReader
+{
+ Iface impl;
+ int (*read)(void*, byte *buf, int n);
+ byte (*get)(void*);
+} io·ByteReader;
+
+typedef struct io·Writer
+{
+ Iface impl;
+ int (*write)(void*, byte *buf, int n);
+} io·Writer;
+
+typedef struct io·ReadWriter
+{
+ Iface impl;
+ int (*read)(void*, byte *buf, int n);
+ int (*write)(void*, byte *buf, int n);
+} io·ReadWriter;
+
+typedef enum io·SeekPos
+{
+ SEEK·set,
+ SEEK·cur,
+ SEEK·end,
+} io·SeekPos;
diff --git a/src/bufio/buffer.c b/src/bufio/buffer.c
new file mode 100644
index 0000000..8963652
--- /dev/null
+++ b/src/bufio/buffer.c
@@ -0,0 +1,24 @@
+#include "impl.h"
+
+// NewBuffer allocates a bytes buffer with size 'size'.
+// This is unallocated usage.
+// Returns the fat pointer by value.
+
+void*
+newbuffer(uintptr off, uintptr size)
+{
+ if (size == 0 || size > BUF·max) size = BUF·size;
+
+ void *mem = malloc(off + sizeof(Buffer) + size);
+ Buffer *buf = mem + off;
+
+ buf->eof = 0;
+ buf->off = 0;
+ buf->base = buf->b + BUF·ungets;
+ buf->end = buf->b + size;
+ buf->size = buf->end - buf->base;
+
+ memset(buf->b, 0, size);
+
+ return mem;
+}
diff --git a/src/bufio/impl.h b/src/bufio/impl.h
new file mode 100644
index 0000000..f5c3bcf
--- /dev/null
+++ b/src/bufio/impl.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <u.h>
+#include <io.h>
+#include <bufio.h>
+
+enum
+{
+ BUF·max = 4 * 8096,
+ BUF·size = 4 * 4096,
+ BUF·ungets = 8,
+ BUF·err = -1,
+ BUF·eof = +1,
+};
+
+typedef struct Buffer
+{
+ uint8 eof;
+ int64 off;
+ int64 size;
+
+ byte* base;
+ byte* pos;
+ byte* end;
+ byte b[];
+} Buffer;
+
+void* newbuffer(uintptr off, uintptr size);
+
+struct bufio·Scanner
+{
+ io·Reader r;
+ Buffer buf;
+};
diff --git a/src/bufio/reader.c b/src/bufio/reader.c
new file mode 100644
index 0000000..915c531
--- /dev/null
+++ b/src/bufio/reader.c
@@ -0,0 +1,198 @@
+#include "impl.h"
+
+struct bufio·Reader
+{
+ io·Reader r;
+ Buffer buf;
+};
+
+bufio·Reader*
+bufio·newreader(io·Reader r)
+{
+ bufio·Reader* br = newbuffer(offsetof(bufio·Reader, buf), 0);
+ br->r = r;
+ br->buf.pos = br->buf.end;
+
+ return br;
+}
+
+error
+bufio·freereader(bufio·Reader* r)
+{
+ free(r);
+ return 0;
+}
+
+static int
+refill(bufio·Reader* r)
+{
+ if (r->buf.eof) return BUF·err;
+
+ int nr = r->r.read(r->r.impl, r->buf.base, r->buf.size);
+ if (nr <= 0) {
+ r->buf.eof = 1;
+ goto end;
+ }
+
+ r->buf.off += nr;
+ r->buf.pos = r->buf.base;
+
+ if (nr < r->buf.size) {
+ int d = (r->buf.size - nr);
+ r->buf.eof = 1;
+ memmove(r->buf.pos + d, r->buf.pos, nr);
+ memmove(r->buf.pos + d - BUF·ungets, r->buf.b, BUF·ungets);
+ r->buf.pos += d;
+ }
+end:
+ return nr;
+}
+
+// Read will attempt to read n bytes from the buffer, starting at the offet
+// offset. Returns the actual number of bytes read from the stream. Input buf
+// can not alias b
+int
+bufio·read(bufio·Reader* r, byte* buf, int count)
+{
+ if (count == 0 || buf == nil || r->buf.off == BUF·eof) return BUF·err;
+
+ int remain = count;
+ byte* rdr = buf;
+
+ int n, nr;
+ while (remain) {
+ int bdiff = r->buf.end - r->buf.pos;
+ n = (bdiff > remain) ? remain : bdiff;
+ if (!n) {
+ if (r->buf.eof | (refill(r) <= 0)) break;
+ }
+
+ memmove(rdr, r->buf.pos, n);
+ rdr += n;
+ r->buf.pos += n;
+ remain -= n;
+ }
+ return count - remain;
+}
+
+int
+bufio·readln(bufio·Reader* r, byte* buf, int count, error* err)
+{
+ byte *it, *end, *cnt;
+ int nb;
+Search:
+ nb = 0;
+ cnt = r->buf.pos + count;
+ end = MIN(r->buf.end, cnt);
+
+ for (it = r->buf.pos; it != end && *it != EOF; ++it, nb++) {
+ if (*it == '\n') {
+ *err = 0;
+ goto End;
+ }
+ }
+
+ if (it == r->buf.end) {
+ memmove(buf, r->buf.pos, nb);
+ r->buf.pos = r->buf.end;
+ if (refill(r) <= 0) {
+ *err = 1;
+ return nb;
+ }
+ Assert(nb < count);
+ count -= nb;
+ buf += nb;
+ goto Search;
+ }
+
+ if (it == cnt) {
+ Assert(nb == count);
+ *err = 2;
+ }
+
+ Assert(*it == EOF || *err == 2);
+
+End:
+ memmove(buf, r->buf.pos, nb);
+ r->buf.pos = it;
+ return nb;
+}
+
+// advanceBuffer moves the buffer ahead by n without reading.
+void
+bufio·discard(bufio·Reader* r, int count)
+{
+ if (count > BUF·max)
+ panicf("can't discard %d bytes", count);
+ byte stack[BUF·max];
+
+ bufio·read(r, stack, count);
+}
+
+// ReadByte reads a single byte from the buffered stream.
+byte
+bufio·get(bufio·Reader* r)
+{
+getbyte:
+ if (r->buf.pos < r->buf.end) { return *r->buf.pos++; }
+
+ memmove(r->buf.b, r->buf.end - BUF·ungets, BUF·ungets);
+ if (refill(r) <= 0) { return EOF; }
+ goto getbyte;
+}
+
+error
+bufio·unget(bufio·Reader* r)
+{
+ if (r->buf.pos == r->buf.b) { return BUF·err; }
+
+ r->buf.pos--;
+ return 0;
+}
+
+byte
+bufio·peek(bufio·Reader* r)
+{
+ if (r->buf.pos != r->buf.end) return *r->buf.pos;
+
+ byte* old = r->buf.pos;
+ byte c = bufio·get(r);
+ if (r->buf.pos != old && (bufio·unget(r) == BUF·err)) {
+ panicf("buffer failure, can't move backwards");
+ }
+
+ return c;
+}
+
+// peekBytes has the same behavior as read, but doesn't advance the buffer.
+int
+bufio·peekfor(bufio·Reader* r, byte* buf, int count)
+{
+ if (count == 0 || buf == nil) return 0;
+
+ int delta = r->buf.end - r->buf.pos;
+ if (delta > count) {
+ memcpy(buf, r->buf.pos, count);
+ return count;
+ }
+
+ byte c, *it;
+ for (it = buf; it != buf + count; ++it) {
+ c = bufio·get(r);
+ *it = c;
+ if (c == EOF) break;
+ }
+
+ int diff = it - buf;
+ for (int n = 0; n < diff; n++) {
+ bufio·unget(r);
+ }
+
+ return diff;
+}
+
+void
+bufio·clear(bufio·Reader* r)
+{
+ memset(r->buf.b, 0, r->buf.size);
+}
diff --git a/src/bufio/rules.mk b/src/bufio/rules.mk
new file mode 100644
index 0000000..e400860
--- /dev/null
+++ b/src/bufio/rules.mk
@@ -0,0 +1,38 @@
+# ---- Push on stack ----
+SP := $(SP).x
+DIRSTACK_$(SP) := $(d)
+d := $(DIR)
+
+# Iterate through subdirectory tree
+# ...
+
+# Local variables
+SRCS_$(d) := $(wildcard $(d)/*.c)
+OBJS_$(d) := $(SRCS_$(d):.c=.o)
+OBJS_$(d) := $(patsubst $(SRC_DIR)/%, $(OBJ_DIR)/%, $(OBJS_$(d)))
+
+OBJS := $(OBJS) $(OBJS_$(d))
+
+DEPS_$(d) := $(OBJS_$(d):.o=.d)
+
+DEPS := $(DEPS) $(DEPS_$(d))
+
+LIBS_$(d) := $(d)/libbufio.a
+LIBS_$(d) := $(patsubst $(SRC_DIR)/%, $(OBJ_DIR)/%, $(LIBS_$(d)))
+BINS_$(d) :=
+
+LIBS := $(LIBS) $(LIBS_$(d))
+
+# Local rules
+# $(LIBS_$(d)) := TGTFLAGS :=
+# $(LIBS_$(d)) := TGTINCS :=
+# $(LIBS_$(d)) := TGTLIBS :=
+
+$(LIBS_$(d)): $(OBJS_$(d))
+ $(ARCHIVE)
+
+# ---- Pop off stack ----
+-include $(DEPS_$(d))
+
+d := $(DIRSTACK_$(SP))
+SP := $(basename $(SP))
diff --git a/src/bufio/writer.c b/src/bufio/writer.c
new file mode 100644
index 0000000..07573d5
--- /dev/null
+++ b/src/bufio/writer.c
@@ -0,0 +1,95 @@
+#include "impl.h"
+
+struct bufio·Writer
+{
+ io·Writer w;
+ Buffer buf;
+};
+
+// Constructor/destructor.
+
+bufio·Writer*
+bufio·newwriter(io·Writer w)
+{
+ bufio·Writer* bw = newbuffer(offsetof(bufio·Writer, buf), 0);
+ bw->w = w;
+ bw->buf.pos = bw->buf.base;
+
+ return bw;
+}
+
+error
+bufio·freewriter(bufio·Writer* w)
+{
+ free(w);
+
+ return 0;
+}
+
+// Write will write n bytes from the input buffer into the storage buffer.
+// Returns the actual number of bytes written.
+int
+bufio·write(bufio·Writer* w, byte* buf, int count)
+{
+ int remain = count;
+ byte* wtr = buf;
+
+ int n, nw;
+ while (remain > 0) {
+ int bdiff = w->buf.end - w->buf.pos;
+ n = (bdiff > remain) ? remain : bdiff;
+ if (!n) {
+ if (w->buf.eof) break;
+ nw = w->w.write(w->w.impl, buf, count);
+ if (nw < w->buf.size) {
+ w->buf.eof = 1;
+ return BUF·err;
+ }
+ w->buf.off += nw;
+ w->buf.pos = w->buf.base;
+ }
+ memmove(w->buf.pos, wtr, n);
+ wtr += n;
+ w->buf.pos += n;
+ remain -= n;
+ }
+
+ return count - remain;
+}
+
+error
+bufio·put(bufio·Writer* w, byte c)
+{
+ int diff;
+putbyte:
+ diff = w->buf.end - w->buf.pos;
+ if (diff) {
+ *w->buf.pos++ = c;
+ return 0;
+ }
+ if (bufio·flush(w) != BUF·err) goto putbyte;
+
+ return BUF·err;
+}
+
+error
+bufio·flush(bufio·Writer* w)
+{
+ int active = (w->buf.eof == 0);
+
+ int n, nw;
+ if (active && w) {
+ n = w->buf.pos - w->buf.base;
+ if (!n) return 0;
+
+ nw = w->w.write(w->w.impl, w->buf.base, n);
+ if (nw == n) {
+ w->buf.off += n;
+ return 0;
+ }
+ w->buf.eof = 1;
+ w->buf.pos = w->buf.end;
+ }
+
+ return BUF·err;
+}
diff --git a/src/test.c b/src/test.c
index e9743cb..3f8e608 100644
--- a/src/test.c
+++ b/src/test.c
@@ -34,6 +34,8 @@ filter(coro *c, uintptr data)
coro *seq;
struct PrimeMsg *msg;
+ // Need to copy relevant variables onto the local stack
+ // Data is volatile.
msg = (struct PrimeMsg*)data;
seq = msg->seq;
p = msg->p;