import xhash, xrope, xfile, and xvect
This commit is contained in:
parent
aa3b385e27
commit
1861aff2d1
|
@ -0,0 +1,78 @@
|
|||
#ifndef XFILE_H__
|
||||
#define XFILE_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct {
|
||||
int ungot;
|
||||
int flags;
|
||||
/* operators */
|
||||
struct {
|
||||
void *cookie;
|
||||
int (*read)(void *, char *, int);
|
||||
int (*write)(void *, const char *, int);
|
||||
long (*seek)(void *, long, int);
|
||||
int (*flush)(void *);
|
||||
int (*close)(void *);
|
||||
} vtable;
|
||||
} xFILE;
|
||||
|
||||
/* generic file constructor */
|
||||
xFILE *xfunopen(void *cookie, int (*read)(void *, char *, int), int (*write)(void *, const char *, int), long (*seek)(void *, long, int), int (*flush)(void *), int (*close)(void *));
|
||||
|
||||
/* resource aquisition */
|
||||
xFILE *xfopen(const char *, const char *);
|
||||
xFILE *xfpopen(FILE *);
|
||||
xFILE *xmopen();
|
||||
int xfclose(xFILE *);
|
||||
|
||||
/* buffer management */
|
||||
int xfflush(xFILE *);
|
||||
|
||||
/* direct IO with buffering */
|
||||
size_t xfread(void *, size_t, size_t, xFILE *);
|
||||
size_t xfwrite(const void *, size_t, size_t, xFILE *);
|
||||
|
||||
/* indicator positioning */
|
||||
long xfseek(xFILE *, long offset, int whence);
|
||||
long xftell(xFILE *);
|
||||
void xrewind(xFILE *);
|
||||
|
||||
/* stream status */
|
||||
void xclearerr(xFILE *);
|
||||
int xfeof(xFILE *);
|
||||
int xferror(xFILE *);
|
||||
|
||||
/* character IO */
|
||||
int xfgetc(xFILE *);
|
||||
char *xfgets(char *, int, xFILE *);
|
||||
int xfputc(int, xFILE *);
|
||||
int xfputs(const char *, xFILE *);
|
||||
char xgetc(xFILE *);
|
||||
int xgetchar(void);
|
||||
int xputc(int, xFILE *);
|
||||
int xputchar(int);
|
||||
int xputs(char *);
|
||||
int xungetc(int, xFILE *);
|
||||
|
||||
/* formatted I/O */
|
||||
int xprintf(const char *, ...);
|
||||
int xfprintf(xFILE *, const char *, ...);
|
||||
int xvfprintf(xFILE *, const char *, va_list);
|
||||
|
||||
/* standard I/O */
|
||||
extern xFILE *xstdin;
|
||||
extern xFILE *xstdout;
|
||||
extern xFILE *xstderr;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,407 @@
|
|||
#ifndef XHASH_H__
|
||||
#define XHASH_H__
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013-2014 by Yuichi Nishiwaki <yuichi.nishiwaki@gmail.com>
|
||||
*/
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* simple object to object hash table */
|
||||
|
||||
#define XHASH_INIT_SIZE 11
|
||||
#define XHASH_RESIZE_RATIO 0.75
|
||||
|
||||
#define XHASH_ALIGNMENT 3 /* quad word alignment */
|
||||
#define XHASH_MASK (~((1 << XHASH_ALIGNMENT) - 1))
|
||||
#define XHASH_ALIGN(i) ((((i) - 1) & XHASH_MASK) + (1 << XHASH_ALIGNMENT))
|
||||
|
||||
typedef struct xh_entry {
|
||||
struct xh_entry *next;
|
||||
int hash;
|
||||
const char *key; /* == val + XHASH_ALIGN(vwidth) */
|
||||
char val[];
|
||||
} xh_entry;
|
||||
|
||||
#define xh_key(e,type) (*(type *)((e)->key))
|
||||
#define xh_val(e,type) (*(type *)((e)->val))
|
||||
|
||||
typedef int (*xh_hashf)(const void *, void *);
|
||||
typedef int (*xh_equalf)(const void *, const void *, void *);
|
||||
|
||||
typedef struct xhash {
|
||||
xh_entry **buckets;
|
||||
size_t size, count, kwidth, vwidth;
|
||||
xh_hashf hashf;
|
||||
xh_equalf equalf;
|
||||
void *data;
|
||||
} xhash;
|
||||
|
||||
static inline void xh_init_(xhash *x, size_t, size_t, xh_hashf, xh_equalf, void *);
|
||||
static inline xh_entry *xh_get_(xhash *x, const void *key);
|
||||
static inline xh_entry *xh_put_(xhash *x, const void *key, void *val);
|
||||
static inline void xh_del_(xhash *x, const void *key);
|
||||
static inline void xh_clear(xhash *x);
|
||||
static inline void xh_destroy(xhash *x);
|
||||
|
||||
/* string map */
|
||||
static inline void xh_init_str(xhash *x, size_t width);
|
||||
static inline xh_entry *xh_get_str(xhash *x, const char *key);
|
||||
static inline xh_entry *xh_put_str(xhash *x, const char *key, void *);
|
||||
static inline void xh_del_str(xhash *x, const char *key);
|
||||
|
||||
/* object map */
|
||||
static inline void xh_init_ptr(xhash *x, size_t width);
|
||||
static inline xh_entry *xh_get_ptr(xhash *x, const void *key);
|
||||
static inline xh_entry *xh_put_ptr(xhash *x, const void *key, void *);
|
||||
static inline void xh_del_ptr(xhash *x, const void *key);
|
||||
|
||||
/* int map */
|
||||
static inline void xh_init_int(xhash *x, size_t width);
|
||||
static inline xh_entry *xh_get_int(xhash *x, int key);
|
||||
static inline xh_entry *xh_put_int(xhash *x, int key, void *);
|
||||
static inline void xh_del_int(xhash *x, int key);
|
||||
|
||||
typedef struct xh_iter {
|
||||
xhash *x;
|
||||
xh_entry *e, *next;
|
||||
size_t bidx;
|
||||
} xh_iter;
|
||||
|
||||
static inline void xh_begin(xh_iter *it, xhash *x);
|
||||
static inline int xh_next(xh_iter *it);
|
||||
|
||||
|
||||
static inline void
|
||||
xh_bucket_realloc(xhash *x, size_t newsize)
|
||||
{
|
||||
x->size = newsize;
|
||||
x->buckets = realloc(x->buckets, (x->size + 1) * sizeof(xh_entry *));
|
||||
memset(x->buckets, 0, (x->size + 1) * sizeof(xh_entry *));
|
||||
}
|
||||
|
||||
static inline void
|
||||
xh_init_(xhash *x, size_t kwidth, size_t vwidth, xh_hashf hashf, xh_equalf equalf, void *data)
|
||||
{
|
||||
x->size = 0;
|
||||
x->buckets = NULL;
|
||||
x->count = 0;
|
||||
x->kwidth = kwidth;
|
||||
x->vwidth = vwidth;
|
||||
x->hashf = hashf;
|
||||
x->equalf = equalf;
|
||||
x->data = data;
|
||||
|
||||
xh_bucket_realloc(x, XHASH_INIT_SIZE);
|
||||
}
|
||||
|
||||
static inline xh_entry *
|
||||
xh_get_(xhash *x, const void *key)
|
||||
{
|
||||
int hash;
|
||||
size_t idx;
|
||||
xh_entry *e;
|
||||
|
||||
hash = x->hashf(key, x->data);
|
||||
idx = ((unsigned)hash) % x->size;
|
||||
for (e = x->buckets[idx]; e; e = e->next) {
|
||||
if (e->hash == hash && x->equalf(key, e->key, x->data))
|
||||
break;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xh_resize_(xhash *x, size_t newsize)
|
||||
{
|
||||
xhash y;
|
||||
xh_iter it;
|
||||
size_t idx;
|
||||
|
||||
xh_init_(&y, x->kwidth, x->vwidth, x->hashf, x->equalf, x->data);
|
||||
xh_bucket_realloc(&y, newsize);
|
||||
|
||||
xh_begin(&it, x);
|
||||
while (xh_next(&it)) {
|
||||
idx = ((unsigned)it.e->hash) % y.size;
|
||||
/* reuse entry object */
|
||||
it.e->next = y.buckets[idx];
|
||||
y.buckets[idx] = it.e;
|
||||
y.count++;
|
||||
}
|
||||
|
||||
free(x->buckets);
|
||||
|
||||
/* copy all members from y to x */
|
||||
memcpy(x, &y, sizeof(xhash));
|
||||
}
|
||||
|
||||
static inline xh_entry *
|
||||
xh_put_(xhash *x, const void *key, void *val)
|
||||
{
|
||||
int hash;
|
||||
size_t idx;
|
||||
xh_entry *e;
|
||||
|
||||
if ((e = xh_get_(x, key))) {
|
||||
memcpy(e->val, val, x->vwidth);
|
||||
return e;
|
||||
}
|
||||
|
||||
if (x->count + 1 > x->size * XHASH_RESIZE_RATIO) {
|
||||
xh_resize_(x, x->size * 2 + 1);
|
||||
}
|
||||
|
||||
hash = x->hashf(key, x->data);
|
||||
idx = ((unsigned)hash) % x->size;
|
||||
e = (xh_entry *)malloc(offsetof(xh_entry, val) + XHASH_ALIGN(x->vwidth) + x->kwidth);
|
||||
e->next = x->buckets[idx];
|
||||
e->hash = hash;
|
||||
e->key = e->val + XHASH_ALIGN(x->vwidth);
|
||||
memcpy((void *)e->key, key, x->kwidth);
|
||||
memcpy(e->val, val, x->vwidth);
|
||||
|
||||
x->count++;
|
||||
|
||||
return x->buckets[idx] = e;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xh_del_(xhash *x, const void *key)
|
||||
{
|
||||
int hash;
|
||||
size_t idx;
|
||||
xh_entry *e, *d;
|
||||
|
||||
hash = x->hashf(key, x->data);
|
||||
idx = ((unsigned)hash) % x->size;
|
||||
if (x->buckets[idx]->hash == hash && x->equalf(key, x->buckets[idx]->key, x->data)) {
|
||||
e = x->buckets[idx]->next;
|
||||
free(x->buckets[idx]);
|
||||
x->buckets[idx] = e;
|
||||
}
|
||||
else {
|
||||
for (e = x->buckets[idx]; ; e = e->next) {
|
||||
if (e->next->hash == hash && x->equalf(key, e->next->key, x->data))
|
||||
break;
|
||||
}
|
||||
d = e->next->next;
|
||||
free(e->next);
|
||||
e->next = d;
|
||||
}
|
||||
|
||||
x->count--;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xh_clear(xhash *x)
|
||||
{
|
||||
size_t i;
|
||||
xh_entry *e, *d;
|
||||
|
||||
for (i = 0; i < x->size; ++i) {
|
||||
e = x->buckets[i];
|
||||
while (e) {
|
||||
d = e->next;
|
||||
free(e);
|
||||
e = d;
|
||||
}
|
||||
x->buckets[i] = NULL;
|
||||
}
|
||||
|
||||
x->count = 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xh_destroy(xhash *x)
|
||||
{
|
||||
xh_clear(x);
|
||||
free(x->buckets);
|
||||
}
|
||||
|
||||
/* string map */
|
||||
|
||||
static inline int
|
||||
xh_str_hash(const void *key, void *data)
|
||||
{
|
||||
const char *str = *(const char **)key;
|
||||
int hash = 0;
|
||||
|
||||
(void)data;
|
||||
|
||||
while (*str) {
|
||||
hash = hash * 31 + *str++;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
static inline int
|
||||
xh_str_equal(const void *key1, const void *key2, void *data)
|
||||
{
|
||||
(void)data;
|
||||
|
||||
return strcmp(*(const char **)key1, *(const char **)key2) == 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xh_init_str(xhash *x, size_t width)
|
||||
{
|
||||
xh_init_(x, sizeof(const char *), width, xh_str_hash, xh_str_equal, NULL);
|
||||
}
|
||||
|
||||
static inline xh_entry *
|
||||
xh_get_str(xhash *x, const char *key)
|
||||
{
|
||||
return xh_get_(x, &key);
|
||||
}
|
||||
|
||||
static inline xh_entry *
|
||||
xh_put_str(xhash *x, const char *key, void *val)
|
||||
{
|
||||
return xh_put_(x, &key, val);
|
||||
}
|
||||
|
||||
static inline void
|
||||
xh_del_str(xhash *x, const char *key)
|
||||
{
|
||||
xh_del_(x, &key);
|
||||
}
|
||||
|
||||
/* object map */
|
||||
|
||||
static inline int
|
||||
xh_ptr_hash(const void *key, void *data)
|
||||
{
|
||||
(void)data;
|
||||
|
||||
return (size_t)*(const void **)key;
|
||||
}
|
||||
|
||||
static inline int
|
||||
xh_ptr_equal(const void *key1, const void *key2, void *data)
|
||||
{
|
||||
(void) data;
|
||||
|
||||
return *(const void **)key1 == *(const void **)key2;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xh_init_ptr(xhash *x, size_t width)
|
||||
{
|
||||
xh_init_(x, sizeof(const void *), width, xh_ptr_hash, xh_ptr_equal, NULL);
|
||||
}
|
||||
|
||||
static inline xh_entry *
|
||||
xh_get_ptr(xhash *x, const void *key)
|
||||
{
|
||||
return xh_get_(x, &key);
|
||||
}
|
||||
|
||||
static inline xh_entry *
|
||||
xh_put_ptr(xhash *x, const void *key, void *val)
|
||||
{
|
||||
return xh_put_(x, &key, val);
|
||||
}
|
||||
|
||||
static inline void
|
||||
xh_del_ptr(xhash *x, const void *key)
|
||||
{
|
||||
xh_del_(x, &key);
|
||||
}
|
||||
|
||||
/* int map */
|
||||
|
||||
static inline int
|
||||
xh_int_hash(const void *key, void *data)
|
||||
{
|
||||
(void)data;
|
||||
|
||||
return *(int *)key;
|
||||
}
|
||||
|
||||
static inline int
|
||||
xh_int_equal(const void *key1, const void *key2, void *data)
|
||||
{
|
||||
(void)data;
|
||||
|
||||
return *(int *)key1 == *(int *)key2;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xh_init_int(xhash *x, size_t width)
|
||||
{
|
||||
xh_init_(x, sizeof(int), width, xh_int_hash, xh_int_equal, NULL);
|
||||
}
|
||||
|
||||
static inline xh_entry *
|
||||
xh_get_int(xhash *x, int key)
|
||||
{
|
||||
return xh_get_(x, &key);
|
||||
}
|
||||
|
||||
static inline xh_entry *
|
||||
xh_put_int(xhash *x, int key, void *val)
|
||||
{
|
||||
return xh_put_(x, &key, val);
|
||||
}
|
||||
|
||||
static inline void
|
||||
xh_del_int(xhash *x, int key)
|
||||
{
|
||||
xh_del_(x, &key);
|
||||
}
|
||||
|
||||
/** iteration */
|
||||
|
||||
static inline void
|
||||
xh_begin(xh_iter *it, xhash *x)
|
||||
{
|
||||
size_t bidx;
|
||||
|
||||
it->x = x;
|
||||
|
||||
for (bidx = 0; bidx < x->size; ++bidx) {
|
||||
if (x->buckets[bidx])
|
||||
break;
|
||||
}
|
||||
it->e = NULL;
|
||||
it->next = x->buckets[bidx];
|
||||
it->bidx = bidx;
|
||||
}
|
||||
|
||||
static inline int
|
||||
xh_next(xh_iter *it)
|
||||
{
|
||||
size_t bidx;
|
||||
|
||||
if (! it->next) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
it->e = it->next;
|
||||
if (it->next->next) {
|
||||
it->next = it->next->next;
|
||||
return 1;
|
||||
}
|
||||
for (bidx = it->bidx + 1; bidx < it->x->size; ++bidx) {
|
||||
if (it->x->buckets[bidx])
|
||||
break;
|
||||
}
|
||||
it->next = it->x->buckets[bidx];
|
||||
it->bidx = bidx;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,329 @@
|
|||
#ifndef XROPE_H__
|
||||
#define XROPE_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* public APIs */
|
||||
|
||||
typedef struct xrope xrope;
|
||||
|
||||
/**
|
||||
* | name | frees buffer? | end with NULL? | complexity | misc
|
||||
* | ---- | ---- | ---- | ---- | ---
|
||||
* | xr_new_cstr | no | yes | O(1) | xr_new(_lit)
|
||||
* | xr_new_imbed | no | no | O(1) |
|
||||
* | xr_new_move | yes | yes | O(1) |
|
||||
* | xr_new_copy | yes | no | O(n) |
|
||||
*/
|
||||
|
||||
#define xr_new(cstr) xr_new_cstr(cstr, strlen(cstr))
|
||||
#define xr_new_lit(cstr) xr_new_cstr(cstr, sizeof(cstr) - 1)
|
||||
static inline xrope *xr_new_cstr(const char *, size_t);
|
||||
static inline xrope *xr_new_imbed(const char *, size_t);
|
||||
static inline xrope *xr_new_move(const char *, size_t);
|
||||
static inline xrope *xr_new_copy(const char *, size_t);
|
||||
|
||||
static inline void XROPE_INCREF(xrope *);
|
||||
static inline void XROPE_DECREF(xrope *);
|
||||
|
||||
static inline size_t xr_len(xrope *);
|
||||
static inline char xr_at(xrope *, size_t);
|
||||
static inline xrope *xr_cat(xrope *, xrope *);
|
||||
static inline xrope *xr_sub(xrope *, size_t, size_t);
|
||||
static inline const char *xr_cstr(xrope *); /* returns NULL-terminated string */
|
||||
|
||||
|
||||
/* impl */
|
||||
|
||||
typedef struct {
|
||||
char *str;
|
||||
int refcnt;
|
||||
size_t len;
|
||||
char autofree, zeroterm;
|
||||
} xr_chunk;
|
||||
|
||||
#define XR_CHUNK_INCREF(c) do { \
|
||||
(c)->refcnt++; \
|
||||
} while (0)
|
||||
|
||||
#define XR_CHUNK_DECREF(c) do { \
|
||||
xr_chunk *c__ = (c); \
|
||||
if (! --c__->refcnt) { \
|
||||
if (c__->autofree) \
|
||||
free(c__->str); \
|
||||
free(c__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
struct xrope {
|
||||
int refcnt;
|
||||
size_t weight;
|
||||
xr_chunk *chunk;
|
||||
size_t offset;
|
||||
struct xrope *left, *right;
|
||||
};
|
||||
|
||||
static inline void
|
||||
XROPE_INCREF(xrope *x) {
|
||||
x->refcnt++;
|
||||
}
|
||||
|
||||
static inline void
|
||||
XROPE_DECREF(xrope *x) {
|
||||
if (! --x->refcnt) {
|
||||
if (x->chunk) {
|
||||
XR_CHUNK_DECREF(x->chunk);
|
||||
free(x);
|
||||
return;
|
||||
}
|
||||
XROPE_DECREF(x->left);
|
||||
XROPE_DECREF(x->right);
|
||||
free(x);
|
||||
}
|
||||
}
|
||||
|
||||
static inline xrope *
|
||||
xr_new_cstr(const char *cstr, size_t len)
|
||||
{
|
||||
xr_chunk *c;
|
||||
xrope *x;
|
||||
|
||||
c = (xr_chunk *)malloc(sizeof(xr_chunk));
|
||||
c->refcnt = 1;
|
||||
c->str = (char *)cstr;
|
||||
c->len = len;
|
||||
c->autofree = 0;
|
||||
c->zeroterm = 1;
|
||||
|
||||
x = (xrope *)malloc(sizeof(xrope));
|
||||
x->refcnt = 1;
|
||||
x->left = NULL;
|
||||
x->right = NULL;
|
||||
x->weight = c->len;
|
||||
x->offset = 0;
|
||||
x->chunk = c;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline xrope *
|
||||
xr_new_imbed(const char *str, size_t len)
|
||||
{
|
||||
xr_chunk *c;
|
||||
xrope *x;
|
||||
|
||||
c = (xr_chunk *)malloc(sizeof(xr_chunk));
|
||||
c->refcnt = 1;
|
||||
c->str = (char *)str;
|
||||
c->len = len;
|
||||
c->autofree = 0;
|
||||
c->zeroterm = 0;
|
||||
|
||||
x = (xrope *)malloc(sizeof(xrope));
|
||||
x->refcnt = 1;
|
||||
x->left = NULL;
|
||||
x->right = NULL;
|
||||
x->weight = c->len;
|
||||
x->offset = 0;
|
||||
x->chunk = c;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline xrope *
|
||||
xr_new_move(const char *cstr, size_t len)
|
||||
{
|
||||
xr_chunk *c;
|
||||
xrope *x;
|
||||
|
||||
c = (xr_chunk *)malloc(sizeof(xr_chunk));
|
||||
c->refcnt = 1;
|
||||
c->str = (char *)cstr;
|
||||
c->len = len;
|
||||
c->autofree = 1;
|
||||
c->zeroterm = 1;
|
||||
|
||||
x = (xrope *)malloc(sizeof(xrope));
|
||||
x->refcnt = 1;
|
||||
x->left = NULL;
|
||||
x->right = NULL;
|
||||
x->weight = c->len;
|
||||
x->offset = 0;
|
||||
x->chunk = c;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline xrope *
|
||||
xr_new_copy(const char *str, size_t len)
|
||||
{
|
||||
char *buf;
|
||||
xr_chunk *c;
|
||||
xrope *x;
|
||||
|
||||
buf = (char *)malloc(len + 1);
|
||||
buf[len] = '\0';
|
||||
memcpy(buf, str, len);
|
||||
|
||||
c = (xr_chunk *)malloc(sizeof(xr_chunk));
|
||||
c->refcnt = 1;
|
||||
c->str = buf;
|
||||
c->len = len;
|
||||
c->autofree = 1;
|
||||
c->zeroterm = 1;
|
||||
|
||||
x = (xrope *)malloc(sizeof(xrope));
|
||||
x->refcnt = 1;
|
||||
x->left = NULL;
|
||||
x->right = NULL;
|
||||
x->weight = c->len;
|
||||
x->offset = 0;
|
||||
x->chunk = c;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
xr_len(xrope *x)
|
||||
{
|
||||
return x->weight;
|
||||
}
|
||||
|
||||
static inline char
|
||||
xr_at(xrope *x, size_t i)
|
||||
{
|
||||
if (x->weight <= i) {
|
||||
return -1;
|
||||
}
|
||||
if (x->chunk) {
|
||||
return x->chunk->str[x->offset + i];
|
||||
}
|
||||
return (i < x->left->weight)
|
||||
? xr_at(x->left, i)
|
||||
: xr_at(x->right, i - x->left->weight);
|
||||
}
|
||||
|
||||
static inline xrope *
|
||||
xr_cat(xrope *x, xrope *y)
|
||||
{
|
||||
xrope *z;
|
||||
|
||||
z = (xrope *)malloc(sizeof(xrope));
|
||||
z->refcnt = 1;
|
||||
z->left = x;
|
||||
z->right = y;
|
||||
z->weight = x->weight + y->weight;
|
||||
z->offset = 0;
|
||||
z->chunk = NULL;
|
||||
|
||||
XROPE_INCREF(x);
|
||||
XROPE_INCREF(y);
|
||||
|
||||
return z;
|
||||
}
|
||||
|
||||
static inline struct xrope *
|
||||
xr_sub(xrope *x, size_t i, size_t j)
|
||||
{
|
||||
assert(i <= j);
|
||||
assert(j <= x->weight);
|
||||
|
||||
if (i == 0 && x->weight == j) {
|
||||
XROPE_INCREF(x);
|
||||
return x;
|
||||
}
|
||||
|
||||
if (x->chunk) {
|
||||
xrope *y;
|
||||
|
||||
y = (xrope *)malloc(sizeof(xrope));
|
||||
y->refcnt = 1;
|
||||
y->left = NULL;
|
||||
y->right = NULL;
|
||||
y->weight = j - i;
|
||||
y->offset = x->offset + i;
|
||||
y->chunk = x->chunk;
|
||||
|
||||
XR_CHUNK_INCREF(x->chunk);
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
if (j <= x->left->weight) {
|
||||
return xr_sub(x->left, i, j);
|
||||
}
|
||||
else if (x->left->weight <= i) {
|
||||
return xr_sub(x->right, i - x->left->weight, j - x->left->weight);
|
||||
}
|
||||
else {
|
||||
xrope *r, *l;
|
||||
|
||||
l = xr_sub(x->left, i, x->left->weight);
|
||||
r = xr_sub(x->right, 0, j - x->left->weight);
|
||||
x = xr_cat(l, r);
|
||||
|
||||
XROPE_DECREF(l);
|
||||
XROPE_DECREF(r);
|
||||
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
xr_fold(xrope *x, xr_chunk *c, size_t offset)
|
||||
{
|
||||
if (x->chunk) {
|
||||
memcpy(c->str + offset, x->chunk->str + x->offset, x->weight);
|
||||
XR_CHUNK_DECREF(x->chunk);
|
||||
|
||||
x->chunk = c;
|
||||
x->offset = offset;
|
||||
XR_CHUNK_INCREF(c);
|
||||
return;
|
||||
}
|
||||
xr_fold(x->left, c, offset);
|
||||
xr_fold(x->right, c, offset + x->left->weight);
|
||||
|
||||
XROPE_DECREF(x->left);
|
||||
XROPE_DECREF(x->right);
|
||||
x->left = x->right = NULL;
|
||||
x->chunk = c;
|
||||
x->offset = offset;
|
||||
XR_CHUNK_INCREF(c);
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
xr_cstr(xrope *x)
|
||||
{
|
||||
xr_chunk *c;
|
||||
|
||||
if (x->chunk && x->offset == 0 && x->weight == x->chunk->len && x->chunk->zeroterm) {
|
||||
return x->chunk->str; /* reuse cached chunk */
|
||||
}
|
||||
|
||||
c = (xr_chunk *)malloc(sizeof(xr_chunk));
|
||||
c->refcnt = 1;
|
||||
c->len = x->weight;
|
||||
c->autofree = 1;
|
||||
c->zeroterm = 1;
|
||||
c->str = (char *)malloc(c->len + 1);
|
||||
c->str[c->len] = '\0';
|
||||
|
||||
xr_fold(x, c, 0);
|
||||
|
||||
XR_CHUNK_DECREF(c);
|
||||
return c->str;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,185 @@
|
|||
#ifndef XVECT_H__
|
||||
#define XVECT_H__
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014 by Yuichi Nishiwaki <yuichi@idylls.jp>
|
||||
*/
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct xvect {
|
||||
char *data;
|
||||
size_t size, mask, head, tail, width;
|
||||
} xvect;
|
||||
|
||||
static inline void xv_init(xvect *, size_t);
|
||||
static inline void xv_destroy(xvect *);
|
||||
|
||||
static inline size_t xv_size(xvect *);
|
||||
|
||||
static inline void xv_reserve(xvect *, size_t);
|
||||
static inline void xv_shrink(xvect *, size_t);
|
||||
|
||||
static inline void *xv_get(xvect *, size_t);
|
||||
static inline void xv_set(xvect *, size_t, void *);
|
||||
|
||||
static inline void xv_push(xvect *, void *);
|
||||
static inline void *xv_pop(xvect *);
|
||||
|
||||
static inline void *xv_shift(xvect *);
|
||||
static inline void xv_unshift(xvect *, void *);
|
||||
|
||||
static inline void xv_splice(xvect *, size_t, ptrdiff_t);
|
||||
static inline void xv_insert(xvect *, size_t, void *);
|
||||
|
||||
static inline void
|
||||
xv_init(xvect *x, size_t width)
|
||||
{
|
||||
x->data = NULL;
|
||||
x->width = width;
|
||||
x->size = 0;
|
||||
x->mask = -1;
|
||||
x->head = 0;
|
||||
x->tail = 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xv_destroy(xvect *x)
|
||||
{
|
||||
free(x->data);
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
xv_size(xvect *x)
|
||||
{
|
||||
return x->tail < x->head
|
||||
? x->tail + x->size - x->head
|
||||
: x->tail - x->head;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
xv_round2(size_t x)
|
||||
{
|
||||
x -= 1;
|
||||
x |= (x >> 1);
|
||||
x |= (x >> 2);
|
||||
x |= (x >> 4);
|
||||
x |= (x >> 8);
|
||||
x |= (x >> 16);
|
||||
x |= (x >> 32);
|
||||
x++;
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xv_rotate(xvect *x)
|
||||
{
|
||||
if (x->tail < x->head) {
|
||||
char buf[x->size * x->width];
|
||||
|
||||
/* perform rotation */
|
||||
memcpy(buf, x->data, sizeof buf);
|
||||
memcpy(x->data, buf + x->head * x->width, (x->size - x->head) * x->width);
|
||||
memcpy(x->data + (x->size - x->head) * x->width, buf, x->tail * x->width);
|
||||
x->tail = x->size - x->head + x->tail;
|
||||
x->head = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
xv_adjust(xvect *x, size_t size)
|
||||
{
|
||||
size = xv_round2(size);
|
||||
if (size != x->size) {
|
||||
xv_rotate(x);
|
||||
x->data = realloc(x->data, size * x->width);
|
||||
x->size = size;
|
||||
x->mask = size - 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
xv_reserve(xvect *x, size_t mincapa)
|
||||
{
|
||||
if (x->size < mincapa + 1) {
|
||||
xv_adjust(x, mincapa + 1); /* capa == size - 1 */
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
xv_shrink(xvect *x, size_t maxcapa)
|
||||
{
|
||||
if (x->size > maxcapa + 1) {
|
||||
xv_adjust(x, maxcapa + 1); /* capa == size - 1 */
|
||||
}
|
||||
}
|
||||
|
||||
static inline void *
|
||||
xv_get(xvect *x, size_t i)
|
||||
{
|
||||
return x->data + ((x->head + x->size + i) & x->mask) * x->width;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xv_set(xvect *x, size_t i, void *src)
|
||||
{
|
||||
memcpy(xv_get(x, i), src, x->width);
|
||||
}
|
||||
|
||||
static inline void
|
||||
xv_push(xvect *x, void *src)
|
||||
{
|
||||
xv_reserve(x, xv_size(x) + 1);
|
||||
xv_set(x, xv_size(x), src);
|
||||
x->tail = (x->tail + 1) & x->mask;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
xv_pop(xvect *x)
|
||||
{
|
||||
x->tail = (x->tail + x->size - 1) & x->mask;
|
||||
return xv_get(x, xv_size(x));
|
||||
}
|
||||
|
||||
static inline void *
|
||||
xv_shift(xvect *x)
|
||||
{
|
||||
x->head = (x->head + 1) & x->mask;
|
||||
return xv_get(x, -1);
|
||||
}
|
||||
|
||||
static inline void
|
||||
xv_unshift(xvect *x, void *src)
|
||||
{
|
||||
xv_reserve(x, xv_size(x) + 1);
|
||||
xv_set(x, -1, src);
|
||||
x->head = (x->head + x->size - 1) & x->mask;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xv_splice(xvect *x, size_t i, ptrdiff_t c)
|
||||
{
|
||||
xv_reserve(x, xv_size(x) - c);
|
||||
xv_rotate(x);
|
||||
memmove(xv_get(x, i), xv_get(x, i + c), (xv_size(x) - i - c) * x->width);
|
||||
x->tail -= c;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xv_insert(xvect *x, size_t i, void *src)
|
||||
{
|
||||
xv_splice(x, i, -1);
|
||||
xv_set(x, i, src);
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,445 @@
|
|||
#include "xfile.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define min(a,b) (((a)>(b))?(b):(a))
|
||||
#define max(a,b) (((a)<(b))?(b):(a))
|
||||
|
||||
#define XF_EOF 1
|
||||
#define XF_ERR 2
|
||||
|
||||
xFILE *
|
||||
xfunopen(void *cookie, int (*read)(void *, char *, int), int (*write)(void *, const char *, int), long (*seek)(void *, long, int), int (*flush)(void *), int (*close)(void *))
|
||||
{
|
||||
xFILE *file;
|
||||
|
||||
file = (xFILE *)malloc(sizeof(xFILE));
|
||||
if (! file) {
|
||||
return NULL;
|
||||
}
|
||||
file->ungot = -1;
|
||||
file->flags = 0;
|
||||
/* set vtable */
|
||||
file->vtable.cookie = cookie;
|
||||
file->vtable.read = read;
|
||||
file->vtable.write = write;
|
||||
file->vtable.seek = seek;
|
||||
file->vtable.flush = flush;
|
||||
file->vtable.close = close;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
xFILE *
|
||||
xfopen(const char *filename, const char *mode)
|
||||
{
|
||||
FILE *fp;
|
||||
xFILE *file;
|
||||
|
||||
fp = fopen(filename, mode);
|
||||
if (! fp) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
file = xfpopen(fp);
|
||||
if (! file) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
int
|
||||
xfclose(xFILE *file)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = file->vtable.close(file->vtable.cookie);
|
||||
if (r == EOF) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
xfflush(xFILE *file)
|
||||
{
|
||||
return file->vtable.flush(file->vtable.cookie);
|
||||
}
|
||||
|
||||
size_t
|
||||
xfread(void *ptr, size_t block, size_t nitems, xFILE *file)
|
||||
{
|
||||
char *dst = (char *)ptr;
|
||||
char buf[block];
|
||||
size_t i, offset;
|
||||
int n;
|
||||
|
||||
for (i = 0; i < nitems; ++i) {
|
||||
offset = 0;
|
||||
if (file->ungot != -1 && block > 0) {
|
||||
buf[0] = file->ungot;
|
||||
offset += 1;
|
||||
file->ungot = -1;
|
||||
}
|
||||
while (offset < block) {
|
||||
n = file->vtable.read(file->vtable.cookie, buf + offset, block - offset);
|
||||
if (n < 0) {
|
||||
file->flags |= XF_ERR;
|
||||
goto exit;
|
||||
}
|
||||
if (n == 0) {
|
||||
file->flags |= XF_EOF;
|
||||
goto exit;
|
||||
}
|
||||
offset += n;
|
||||
}
|
||||
memcpy(dst, buf, block);
|
||||
dst += block;
|
||||
}
|
||||
|
||||
exit:
|
||||
return i;
|
||||
}
|
||||
|
||||
size_t
|
||||
xfwrite(const void *ptr, size_t block, size_t nitems, xFILE *file)
|
||||
{
|
||||
char *dst = (char *)ptr;
|
||||
size_t i, offset;
|
||||
int n;
|
||||
|
||||
for (i = 0; i < nitems; ++i) {
|
||||
offset = 0;
|
||||
while (offset < block) {
|
||||
n = file->vtable.write(file->vtable.cookie, dst + offset, block - offset);
|
||||
if (n < 0) {
|
||||
file->flags |= XF_ERR;
|
||||
goto exit;
|
||||
}
|
||||
offset += n;
|
||||
}
|
||||
dst += block;
|
||||
}
|
||||
|
||||
exit:
|
||||
return i;
|
||||
}
|
||||
|
||||
long
|
||||
xfseek(xFILE *file, long offset, int whence)
|
||||
{
|
||||
file->ungot = -1;
|
||||
return file->vtable.seek(file->vtable.cookie, offset, whence);
|
||||
}
|
||||
|
||||
long
|
||||
xftell(xFILE *file)
|
||||
{
|
||||
return xfseek(file, 0, SEEK_CUR);
|
||||
}
|
||||
|
||||
void
|
||||
xrewind(xFILE *file)
|
||||
{
|
||||
xfseek(file, 0, SEEK_SET);
|
||||
}
|
||||
|
||||
void
|
||||
xclearerr(xFILE *file)
|
||||
{
|
||||
file->flags = 0;
|
||||
}
|
||||
|
||||
int
|
||||
xfeof(xFILE *file)
|
||||
{
|
||||
return file->flags & XF_EOF;
|
||||
}
|
||||
|
||||
int
|
||||
xferror(xFILE *file)
|
||||
{
|
||||
return file->flags & XF_ERR;
|
||||
}
|
||||
|
||||
int
|
||||
xfgetc(xFILE *file)
|
||||
{
|
||||
char buf[1];
|
||||
|
||||
xfread(buf, 1, 1, file);
|
||||
|
||||
if (xfeof(file)) {
|
||||
return EOF;
|
||||
}
|
||||
|
||||
return buf[0];
|
||||
}
|
||||
|
||||
int
|
||||
xungetc(int c, xFILE *file)
|
||||
{
|
||||
file->ungot = c;
|
||||
if (c != EOF) {
|
||||
file->flags &= ~XF_EOF;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int
|
||||
xgetchar(void)
|
||||
{
|
||||
return xfgetc(xstdin);
|
||||
}
|
||||
|
||||
int
|
||||
xfputc(int c, xFILE *file)
|
||||
{
|
||||
char buf[1];
|
||||
|
||||
buf[0] = c;
|
||||
xfwrite(buf, 1, 1, file);
|
||||
|
||||
return buf[0];
|
||||
}
|
||||
|
||||
int
|
||||
xputchar(int c)
|
||||
{
|
||||
return xfputc(c, xstdout);
|
||||
}
|
||||
|
||||
int
|
||||
xfputs(const char *str, xFILE *file)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = strlen(str);
|
||||
xfwrite(str, len, 1, file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
xprintf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int n;
|
||||
|
||||
va_start(ap, fmt);
|
||||
n = xvfprintf(xstdout, fmt, ap);
|
||||
va_end(ap);
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
xfprintf(xFILE *stream, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int n;
|
||||
|
||||
va_start(ap, fmt);
|
||||
n = xvfprintf(stream, fmt, ap);
|
||||
va_end(ap);
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
xvfprintf(xFILE *stream, const char *fmt, va_list ap)
|
||||
{
|
||||
va_list ap2;
|
||||
|
||||
va_copy(ap2, ap);
|
||||
{
|
||||
char buf[vsnprintf(NULL, 0, fmt, ap2)];
|
||||
|
||||
vsnprintf(buf, sizeof buf + 1, fmt, ap);
|
||||
|
||||
if (xfwrite(buf, sizeof buf, 1, stream) < 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
va_end(ap2);
|
||||
return sizeof buf;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Derieved xFILE Classes
|
||||
*/
|
||||
|
||||
static FILE *
|
||||
unpack(void *cookie)
|
||||
{
|
||||
switch ((long)cookie) {
|
||||
default: return cookie;
|
||||
case 0: return stdin;
|
||||
case 1: return stdout;
|
||||
case -1: return stderr;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
file_read(void *cookie, char *ptr, int size)
|
||||
{
|
||||
FILE *file = unpack(cookie);
|
||||
int r;
|
||||
|
||||
r = fread(ptr, 1, size, file);
|
||||
if (r < size && ferror(file)) {
|
||||
return -1;
|
||||
}
|
||||
if (r == 0 && feof(file)) {
|
||||
clearerr(file);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
file_write(void *cookie, const char *ptr, int size)
|
||||
{
|
||||
FILE *file = unpack(cookie);
|
||||
int r;
|
||||
|
||||
r = fwrite(ptr, 1, size, file);
|
||||
if (r < size) {
|
||||
return -1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static long
|
||||
file_seek(void *cookie, long pos, int whence)
|
||||
{
|
||||
return fseek(unpack(cookie), pos, whence);
|
||||
}
|
||||
|
||||
static int
|
||||
file_flush(void *cookie)
|
||||
{
|
||||
return fflush(unpack(cookie));
|
||||
}
|
||||
|
||||
static int
|
||||
file_close(void *cookie)
|
||||
{
|
||||
return fclose(unpack(cookie));
|
||||
}
|
||||
|
||||
xFILE *
|
||||
xfpopen(FILE *fp)
|
||||
{
|
||||
xFILE *file;
|
||||
|
||||
file = xfunopen(fp, file_read, file_write, file_seek, file_flush, file_close);
|
||||
if (! file) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
#define FILE_VTABLE file_read, file_write, file_seek, file_flush, file_close
|
||||
|
||||
static xFILE xfile_stdin = { -1, 0, { (void *)0, FILE_VTABLE } };
|
||||
static xFILE xfile_stdout = { -1, 0, { (void *)1, FILE_VTABLE } };
|
||||
static xFILE xfile_stderr = { -1, 0, { (void *)-1, FILE_VTABLE } };
|
||||
|
||||
xFILE *xstdin = &xfile_stdin;
|
||||
xFILE *xstdout = &xfile_stdout;
|
||||
xFILE *xstderr = &xfile_stderr;
|
||||
|
||||
struct membuf {
|
||||
char *buf;
|
||||
long pos, end, capa;
|
||||
};
|
||||
|
||||
static int
|
||||
mem_read(void *cookie, char *ptr, int size)
|
||||
{
|
||||
struct membuf *mem;
|
||||
|
||||
mem = (struct membuf *)cookie;
|
||||
|
||||
size = min(size, mem->end - mem->pos);
|
||||
memcpy(ptr, mem->buf + mem->pos, size);
|
||||
mem->pos += size;
|
||||
return size;
|
||||
}
|
||||
|
||||
static int
|
||||
mem_write(void *cookie, const char *ptr, int size)
|
||||
{
|
||||
struct membuf *mem;
|
||||
|
||||
mem = (struct membuf *)cookie;
|
||||
|
||||
if (mem->pos + size >= mem->capa) {
|
||||
mem->capa = (mem->pos + size) * 2;
|
||||
mem->buf = realloc(mem->buf, mem->capa);
|
||||
}
|
||||
memcpy(mem->buf + mem->pos, ptr, size);
|
||||
mem->pos += size;
|
||||
mem->end = max(mem->pos, mem->end);
|
||||
return size;
|
||||
}
|
||||
|
||||
static long
|
||||
mem_seek(void *cookie, long pos, int whence)
|
||||
{
|
||||
struct membuf *mem;
|
||||
|
||||
mem = (struct membuf *)cookie;
|
||||
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
mem->pos = pos;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
mem->pos += pos;
|
||||
break;
|
||||
case SEEK_END:
|
||||
mem->pos = mem->end + pos;
|
||||
break;
|
||||
}
|
||||
|
||||
return mem->pos;
|
||||
}
|
||||
|
||||
static int
|
||||
mem_flush(void *cookie)
|
||||
{
|
||||
(void)cookie;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mem_close(void *cookie)
|
||||
{
|
||||
struct membuf *mem;
|
||||
|
||||
mem = (struct membuf *)cookie;
|
||||
free(mem->buf);
|
||||
free(mem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
xFILE *
|
||||
xmopen()
|
||||
{
|
||||
struct membuf *mem;
|
||||
|
||||
mem = (struct membuf *)malloc(sizeof(struct membuf));
|
||||
mem->buf = (char *)malloc(BUFSIZ);
|
||||
mem->pos = 0;
|
||||
mem->end = 0;
|
||||
mem->capa = BUFSIZ;
|
||||
|
||||
return xfunopen(mem, mem_read, mem_write, mem_seek, mem_flush, mem_close);
|
||||
}
|
Loading…
Reference in New Issue