piece-chain

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

commit 936af64091d463485cd5df7a4a60886de31e8f6f
parent 78db499bbb1371ff05d832c65ea3da4466567007
Author: gearsix <gearsix@tuta.io>
Date:   Mon,  4 Jul 2022 15:28:06 +0100

added pfree; palloc recycles free'd pieces; test_bufins now passes.

Diffstat:
Mbuf.c | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Mbuf.h | 2++
Mtest.c | 43++++++++++++++++++++++++-------------------
3 files changed, 80 insertions(+), 45 deletions(-)

diff --git a/buf.c b/buf.c @@ -5,24 +5,49 @@ #include <stdlib.h> #include <string.h> -Piece *palloc() +static const size_t blksiz = BUFSIZ/sizeof(Piece); +static Piece **nextp = NULL; + +static size_t pfree(Piece *p) { - static Piece *pieceblk = NULL; - static size_t nblk = 0, npieces = 0; - static const size_t blksiz = BUFSIZ/sizeof(Piece); + static Piece **freeblk = NULL; + static size_t nblk = 0, nfree = 0; + + if (!p) { + if (!nextp && nfree > 0) + nextp = &freeblk[--nfree]; + return nfree; + } + + if (nfree + 1 > blksiz * nblk) + freeblk = realloc(freeblk, (++nblk * blksiz) * sizeof(Piece *)); + if (!freeblk) { perror("failed to allocate freeblk"); exit(1); } - 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++]; + freeblk[nfree++] = p; + nextp = &freeblk[nfree - 1]; + return nfree; } -void pfree(Piece *p) +static Piece *palloc() { + Piece *p; + static Piece *pieceblk = NULL; + static size_t nblk = 0, npieces = 0; + if (pfree(NULL) > 0) { + p = *nextp; + nextp = NULL; + } else { + if (npieces + 1 > blksiz * nblk) + pieceblk = realloc(pieceblk, (++nblk * blksiz) * sizeof(Piece)); + if (!pieceblk) { perror("failed to allocate pieceblk"); exit(1); } + p = &pieceblk[npieces++]; + } + + return memset(p, 0, sizeof(Piece)); } -Piece *psplit(Piece *p, long int offset) +static Piece *psplit(Piece *p, long int offset) { Piece *q = palloc(); if (offset > 0) { @@ -32,7 +57,8 @@ Piece *psplit(Piece *p, long int offset) q->len -= p->len = offset; q->next = p->next; q->prev = p; - p->next = q->next->prev =q; + p->next = q; + if (q->next) q->next->prev = q; p = q; } @@ -42,13 +68,9 @@ Piece *psplit(Piece *p, long int offset) 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; + b->append = tmpfile(); + b->tail = b->pos = b->head = palloc(); if (fpath) { b->read = fopen(fpath, "rb"); @@ -85,33 +107,39 @@ Piece *bufidx(Buf *b, size_t pos) } else { offset = (idx >= pos) ? idx - pos : pos - idx; b->pos = psplit(p, offset); + if (!b->pos->next) b->head = b->pos; b->idx = pos; } return b->pos; } -void bufins(Buf *b, size_t pos, const char *s) +size_t bufins(Buf *b, size_t pos, const char *s) { const size_t slen = strlen(s); Piece *p = palloc(); - bufidx(pos); + b->pos = bufidx(b, pos)->prev; p->f = b->append; p->off = ftell(b->append); - p->len = strlen(buf); + p->len = slen; /* p->undo = ?? */ p->redo = NULL; - p->prev = b->pos->prev; + p->prev = b->pos; p->next = b->pos->next; - b->pos->next = p; - fprintf(b->append, "%s", buf); + b->pos->next = b->pos->next->prev = p; + + fprintf(b->append, "%s", s); if (ferror(b->append)) { perror("failed to write to append file"); - --npieces; - memset(ins, 0, sizeof(Piece)); + pfree(p); + p = 0; + } else { + b->idx += slen; + b->pos = p->next; } - return (ins->f == 0) ? b->size : (b->size += slen); + + return (p == 0) ? b->size : (b->size += slen); } diff --git a/buf.h b/buf.h @@ -18,3 +18,5 @@ typedef struct Buf { Buf *bufinit(const char *fpath); Piece *bufidx(Buf *b, size_t pos); + +size_t bufins(Buf *b, size_t pos, const char *s); diff --git a/test.c b/test.c @@ -39,30 +39,16 @@ void test_bufinit() 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); + assert(b->pos == b->tail); + assert(b->pos == b->head); 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->prev == NULL); assert(p->next == NULL); - assert(p->prev == b->pos); } void test_bufidx() @@ -71,11 +57,29 @@ void test_bufidx() p = bufidx(b, idx); assert(p == b->pos); + assert(p == b->head); + assert(p->prev == b->tail); 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); +} + +void test_bufins() +{ + const char *buf = "y"; + const size_t idx = 2, len = strlen(buf); + bufins(b, idx, buf); + + assert(b->size == strlen(INBUF) + len); + assert(b->idx == idx + len); + assert(b->pos == b->tail->next->next); + assert(b->pos->f == b->read); + assert(b->pos->off == 2); + assert(b->pos->len == 3); + assert(b->pos->undo == NULL); + assert(b->pos->redo == NULL); + assert(b->pos->prev == b->tail->next); + assert(b->pos->next == b->head); } int main() @@ -83,6 +87,7 @@ int main() setup(); test_bufinit(); test_bufidx(); + test_bufins(); puts("success - no assertions failed"); return 0; }