piece-chain

Research & implementation of a Piece Chain
git clone git://src.gearsix.net/piece-chain.git
Log | Files | Refs | Atom | README

commit 9b76662831fccb39c45ec4cc5e2223fe150a0fbd
Author: gearsix <gearsix@tuta.io>
Date:   Sat, 30 Apr 2022 13:39:24 +0100

git init; Piece, Buf, palloc, psplit, bufinit, bufidx.

Diffstat:
AMakefile | 8++++++++
Abuf.c | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuf.h | 20++++++++++++++++++++
Atest.c | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 207 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile @@ -0,0 +1,8 @@ +SRC := buf.c +OUT := ec +OPTS := -g -Wall -Wpedantic -std=c89 + +all: + ${CC} $(OPTS) $(SRC) main.c -o $(OUT) +test: + ${CC} $(OPTS) $(SRC) test.c -o $(OUT) diff --git a/buf.c b/buf.c @@ -0,0 +1,91 @@ + +#include "buf.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +Piece *palloc() +{ + static Piece *pieceblk = NULL; + static size_t nblk = 0, npieces = 0; + static const size_t blksiz = BUFSIZ/sizeof(Piece); + + if (npieces + 1 > blksiz * nblk) + pieceblk = realloc(pieceblk, (++nblk * blksiz) * sizeof(Piece)); + if (!pieceblk) { perror("failed to allocate pieceblk memory"); exit(1); } + return &pieceblk[npieces++]; +} + +Piece *psplit(Piece *p, long int offset) +{ + Piece *q = palloc(); + if (offset > 0) { + memcpy(q, p, sizeof(Piece)); + + q->off += offset; + q->len -= p->len = offset; + q->next = p->next; + q->prev = p; + p->next = q->next->prev =q; + + p = q; + } + return p; +} + +struct Buf *bufinit(const char *fpath) +{ + Buf *b = calloc(1, sizeof(Buf)); + + b->append = tmpfile(); + + b->pos = palloc(); + b->pos->prev = b->tail = palloc(); + b->pos->next = b->head = palloc(); + b->head->prev = b->tail->next = b->pos; + + if (fpath) { + b->read = fopen(fpath, "rb"); + if (ferror(b->read)) perror(fpath); + + b->pos->f = b->read; + fseek(b->read, 0, SEEK_END); + b->size = b->pos->len = ftell(b->read); + } + + return b; +} + +Piece *bufidx(Buf *b, size_t pos) +{ + size_t idx = b->idx, offset; + Piece *p = b->pos; + + if (pos >= idx) { + while (pos >= idx + p->len && p->next) { + idx += p->len; + p = p->next; + } + } else { + do { + p = p->prev; + idx -= p->len; + } while(pos > idx && p->prev); + } + + if (idx == pos) { + b->idx = idx; + b->pos = p; + } else { + offset = (idx >= pos) ? idx - pos : pos - idx; + b->pos = psplit(p, offset); + b->idx = pos; + } + + return b->pos; +} + +void bufins(Buf *b, size_t pos, const char *buf) +{ +} diff --git a/buf.h b/buf.h @@ -0,0 +1,20 @@ +/* TODO */ +#include <stdio.h> + +typedef struct Piece { + FILE *f; + size_t off, len; + + struct Piece *undo, *redo; + struct Piece *prev, *next; +} Piece; + +typedef struct Buf { + FILE *read, *append; + size_t size, idx; + struct Piece *tail, *pos, *head; +} Buf; + +Buf *bufinit(const char *fpath); + +Piece *bufidx(Buf *b, size_t pos); diff --git a/test.c b/test.c @@ -0,0 +1,88 @@ +#include "buf.h" +#include <stdio.h> +#include <assert.h> +#include <string.h> + +#define INFILE "in.txt" +#define INBUF "hello world" +#define OUTFILE "out.txt" +#define OUTBUF "hey buddy!" /* tests will aim to change INBUF to this */ + +Buf *b; + +void setup() +{ + FILE *in = fopen(INFILE, "w+b"); + if (ferror(in)) perror("fopen in.txt"); + fputs(INBUF, in); + fclose(in); + + return; +} + +void print(Buf *b) +{ + Piece *p; + + printf("b->tail: %p\tb->pos: %p\tb->head: %p\n\n", + (void *)b->tail, (void *)b->pos, (void *)b->head); + + for (p = b->tail; p != NULL; p = p->next) + printf("%p\n", (void *)p); +} + +void test_bufinit() +{ + Piece *p; + b = bufinit(INFILE); + + assert(b->read); + assert(b->append); + + p = b->tail; + assert(p); + assert(p->f == NULL); + assert(p->off == 0); + assert(p->len == 0); + assert(p->next == b->pos); + assert(p->prev == NULL); + + p = b->pos; + assert(p); + assert(p->f == b->read); + assert(p->off == 0); + assert(p->len == strlen(INBUF)); + assert(p->prev == b->tail); + assert(p->next == b->head); + + p = b->head; + assert(p); + assert(p); + assert(p->f == NULL); + assert(p->off == 0); + assert(p->len == 0); + assert(p->next == NULL); + assert(p->prev == b->pos); +} + +void test_bufidx() +{ + Piece *p; size_t idx = 5; + p = bufidx(b, idx); + + assert(p == b->pos); + assert(p->f == b->read); + assert(p->off == idx); + assert(p->len == strlen(INBUF) - idx); + assert(p->prev != b->tail); + assert(p->next == b->head); +} + +int main() +{ + setup(); + test_bufinit(); + test_bufidx(); + puts("success - no assertions failed"); + return 0; +}