ref: a8c9ee3f9f94a4789bb7b86a8dbc7392e6b94985
parent: f7b9f1912c0f10033006bb55deb3d48768b9f3a6
author: qwx <qwx@sciops.net>
date: Fri Mar 25 21:12:17 EDT 2022
asif: better vectors implementation using linked lists of bins
--- a/asif.h
+++ b/asif.h
@@ -16,22 +16,30 @@
void vinsert(VArray*, char*);
VArray* valloc(ulong, int);
+enum{
+ Shardsz = 128,
+};
+typedef struct VShard VShard;
typedef struct Vector Vector;
-struct Vector{
+struct VShard{
void *p;
- ulong n;
- ulong elsz;
- ulong bufsz;
- ulong totsz;
- int firstempty;
+ void *head;
+ int len;
+ VShard *prev;
+ VShard *next;
};
-void freevec(Vector*);
-void clearvec(Vector*);
-void popsparsevec(Vector*, int);
-void* pushsparsevec(Vector*, void*);
-void* popvec(Vector*);
-void* pushvec(Vector*, void*);
-void* newvec(Vector*, int, int);
+struct Vector{
+ int len;
+ int elsz;
+ VShard vl;
+ void *tmp;
+};
+void vecfree(Vector*);
+void* vechpop(Vector*);
+void* vectpop(Vector*);
+void vecpush(Vector*, void*);
+void* vecget(Vector*, int);
+Vector* vec(int);
typedef struct QNode QNode;
struct QNode{
--- a/vec.c
+++ b/vec.c
@@ -2,108 +2,138 @@
#include <libc.h>
#include "asif.h"
-enum{
- Nvecinc = 64,
-};
-
-void
-freevec(Vector *v)
+static void
+shardlink(Vector *v, VShard *s)
{
- if(v == nil)
- return;
- free(v->p);
+ s->next = &v->vl;
+ s->prev = v->vl.prev;
+ s->prev->next = s;
+ v->vl.prev = s;
}
-void
-clearvec(Vector *v)
+static void
+shardunlink(Vector *v, VShard *s)
{
- assert(v != nil);
- if(v->p == nil)
- return;
- memset(v->p, 0, v->totsz);
- v->firstempty = 0;
- v->n = 0;
+ memset(s->p, 0, Shardsz * v->elsz);
+ s->head = s->p;
+ s->prev->next = s->next;
+ s->next->prev = s->prev;
}
-static void *
-growvec(Vector *v, int n)
+static VShard *
+shard(Vector *v)
{
- assert(v != nil);
- if(n < v->bufsz)
- return (uchar *)v->p + n * v->elsz;
- v->p = erealloc(v->p, v->totsz + Nvecinc * v->elsz, v->totsz);
- v->bufsz += Nvecinc;
- v->totsz += Nvecinc * v->elsz;
- return (uchar *)v->p + n * v->elsz;
+ VShard *s;
+
+ s = emalloc(sizeof *s);
+ s->p = emalloc(v->elsz * Shardsz);
+ s->head = s->p;
+ shardlink(v, s);
+ return s;
}
void
-popsparsevec(Vector *v, int n)
+vecfree(Vector *v)
{
- assert(v != nil && v->elsz > 0 && n >= 0 && n < v->n);
- memset((uchar *)v->p + n * v->elsz, 0, v->elsz);
- if(n < v->firstempty)
- v->firstempty = n;
+ VShard *s, *t;
+
+ free(v->tmp);
+ for(s=v->vl.next; s!=&v->vl; s=t){
+ t = s->next;
+ free(s->p);
+ free(s);
+ }
+ free(v);
}
-/* assumes that zeroed element means empty; could fill with
- * magic values instead */
-void *
-pushsparsevec(Vector *v, void *e)
+static void *
+shardpop(Vector *v, VShard *s, int i)
{
- int n;
- uchar *p, *q;
+ uchar *p;
- assert(v != nil && v->elsz > 0);
- n = v->firstempty;
- p = growvec(v, n);
- for(n++, q=p+v->elsz; n<v->n; n++, q+=v->elsz)
- if(memcmp(p, q, v->elsz) == 0)
- break;
- v->firstempty = n;
- memcpy(p, e, v->elsz);
- v->n++;
- return p;
+ assert(s != &v->vl);
+ assert(i >= 0 && i < s->len);
+ p = (uchar *)s->head + i * v->elsz;
+ memcpy(v->tmp, p, v->elsz);
+ s->len--;
+ v->len--;
+ if(i == 0)
+ s->head = (uchar *)s->head + v->elsz;
+ if(s->len == 0){
+ shardunlink(v, s);
+ shardlink(v, s);
+ }
+ return v->tmp;
}
void *
-popvec(Vector *v)
+vechpop(Vector *v)
{
uchar *p;
+ VShard *s;
- assert(v != nil && v->elsz > 0);
- if(v->n <= 0)
+ if(v->len <= 0)
return nil;
- p = (uchar *)v->p + v->elsz * (v->n - 1);
- if(v->firstempty > v->n - 1)
- v->firstempty = v->n - 1;
- v->n--;
- return p;
+ s = v->vl.next;
+ assert(s != &v->vl);
+ return shardpop(v, s, 0);
}
void *
-pushvec(Vector *v, void *e)
+vectpop(Vector *v)
{
+ VShard *s;
+
+ if(v->len <= 0)
+ return nil;
+ for(s=v->vl.prev; s != &v->vl && s->len == 0; s=s->prev)
+ ;
+ assert(s != &v->vl);
+ return shardpop(v, s, s->len - 1);
+}
+
+void
+vecpush(Vector *v, void *e)
+{
uchar *p;
+ VShard *s;
- assert(v != nil && v->elsz > 0);
- p = growvec(v, v->n);
+ for(s=v->vl.prev; s != &v->vl && s->len >= Shardsz; s=s->prev)
+ ;
+ if(s == &v->vl)
+ s = shard(v);
+ p = (uchar *)s->head + s->len * v->elsz;
memcpy(p, e, v->elsz);
- v->n++;
- v->firstempty = v->n;
- if(v->firstempty > v->n)
- v->firstempty = v->n;
- return p;
+ s->len++;
+ v->len++;
}
void *
-newvec(Vector *v, int nel, int elsz)
+vecget(Vector *v, int i)
{
- assert(v != nil && elsz > 0);
+ uchar *p;
+ VShard *s;
+
+ assert(i >= 0 && i < v->len);
+ for(s=v->vl.next; s != &v->vl && i > s->len; s=s->next)
+ i -= s->len;
+ assert(s != &v->vl);
+ assert(s->len > 0);
+ assert(i >= 0 && i < s->len);
+ return (uchar *)s->head + i * v->elsz;
+}
+
+Vector *
+vec(int elsz)
+{
+ Vector *v;
+ VShard *s;
+
+ assert(elsz > 0);
+ v = emalloc(sizeof *v);
v->elsz = elsz;
- nel = nel + Nvecinc-1 & ~(Nvecinc-1);
- v->bufsz = nel;
- v->totsz = nel * elsz;
- v->p = emalloc(v->totsz);
- return v->p;
+ v->vl.next = v->vl.prev = &v->vl;
+ v->tmp = emalloc(elsz);
+ shard(v);
+ return v;
}