import of llt library source
This commit is contained in:
commit
1f81d56b89
|
@ -0,0 +1,44 @@
|
||||||
|
CC = gcc
|
||||||
|
|
||||||
|
SRCS = bitvector.c hashing.c socket.c timefuncs.c utils.c dblprint.c ptrhash.c \
|
||||||
|
utf8.c ios.c operators.c cplxprint.c dirpath.c
|
||||||
|
OBJS = $(SRCS:%.c=%.o)
|
||||||
|
DOBJS = $(SRCS:%.c=%.do)
|
||||||
|
TARGET = libllt.a
|
||||||
|
TESTSRC = unittest.c
|
||||||
|
TESTER = llttest
|
||||||
|
|
||||||
|
FLAGS = -Wall -Wextra -Wno-strict-aliasing $(CFLAGS)
|
||||||
|
LIBS =
|
||||||
|
|
||||||
|
DEBUGFLAGS = -g -DDEBUG $(FLAGS)
|
||||||
|
SHIPFLAGS = -O2 -DNDEBUG $(FLAGS)
|
||||||
|
|
||||||
|
default: release
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(SHIPFLAGS) -c $< -o $@
|
||||||
|
%.do: %.c
|
||||||
|
$(CC) $(DEBUGFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
debug: $(DOBJS)
|
||||||
|
rm -rf $(TARGET)
|
||||||
|
ar rs $(TARGET) $(DOBJS)
|
||||||
|
|
||||||
|
release: $(OBJS)
|
||||||
|
rm -rf $(TARGET)
|
||||||
|
ar rs $(TARGET) $(OBJS)
|
||||||
|
|
||||||
|
test:
|
||||||
|
make clean
|
||||||
|
make release CFLAGS=-DENABLE_LLT_TEST
|
||||||
|
gcc $(TESTSRC) $(TARGET) -o $(TESTER) -lm
|
||||||
|
./$(TESTER)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o
|
||||||
|
rm -f *.do
|
||||||
|
rm -f *~
|
||||||
|
rm -f core*
|
||||||
|
rm -f $(TARGET)
|
||||||
|
rm -f $(TESTER)
|
|
@ -0,0 +1,396 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <io.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#define fileno _fileno
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "dtypes.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "utf8.h"
|
||||||
|
#include "ios.h"
|
||||||
|
#include "socket.h"
|
||||||
|
|
||||||
|
/* OS-level primitive wrappers */
|
||||||
|
|
||||||
|
// return error code, #bytes read in *nread
|
||||||
|
static int _os_read(long fd, void *buf, size_t n, size_t *nread)
|
||||||
|
{
|
||||||
|
ssize_t r = read((int)fd, buf, n);
|
||||||
|
if (r == -1) {
|
||||||
|
*nread = 0;
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
*nread = (size_t)r;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _os_write(long fd, void *buf, size_t n, size_t *nwritten)
|
||||||
|
{
|
||||||
|
ssize_t r = write((int)fd, buf, n);
|
||||||
|
if (r == -1) {
|
||||||
|
*nwritten = 0;
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
*nread = (size_t)r;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _fd_available(long fd)
|
||||||
|
{
|
||||||
|
#ifndef WIN32
|
||||||
|
fd_set set;
|
||||||
|
struct timeval tv = {0, 0};
|
||||||
|
|
||||||
|
FD_ZERO(&set);
|
||||||
|
FD_SET(fd, &set);
|
||||||
|
return (select(fd+1, &set, NULL, NULL, &tv)!=0);
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* internal utility functions */
|
||||||
|
|
||||||
|
static char *_buf_realloc(ios_t *s, size_t sz)
|
||||||
|
{
|
||||||
|
char *temp;
|
||||||
|
|
||||||
|
if (sz <= s->maxsize)
|
||||||
|
return s->buf;
|
||||||
|
|
||||||
|
if ((s->buf==NULL || s->buf==&s->local[0]) && (sz <= IOS_INLSIZE)) {
|
||||||
|
/* TODO: if we want to allow shrinking, see if the buffer shrank
|
||||||
|
down to this size, in which case we need to copy. */
|
||||||
|
s->buf = &s->local[0];
|
||||||
|
s->maxsize = IOS_INLSIZE;
|
||||||
|
s->ownbuf = 1;
|
||||||
|
return s->buf;
|
||||||
|
}
|
||||||
|
else if (s->ownbuf && s->buf != &s->local[0]) {
|
||||||
|
// if we own the buffer we're free to resize it
|
||||||
|
// always allocate 1 bigger in case user wants to add a NUL
|
||||||
|
// terminator after taking over the buffer
|
||||||
|
temp = realloc(s->buf, sz+1);
|
||||||
|
if (temp == NULL)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
temp = malloc(sz+1);
|
||||||
|
s->ownbuf = 1;
|
||||||
|
if (temp == NULL)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->buf != temp && s->size > 0)
|
||||||
|
memcpy(temp, s->buf, s->size);
|
||||||
|
s->buf = temp;
|
||||||
|
s->maxsize = sz;
|
||||||
|
return s->buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write a block of data into the buffer at the current position, resizing
|
||||||
|
// if necessary. returns # written.
|
||||||
|
static size_t _writebuf_force(ios_t *s, char *data, size_t n)
|
||||||
|
{
|
||||||
|
size_t amt;
|
||||||
|
size_t newsize;
|
||||||
|
|
||||||
|
if (n == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (s->bpos + n > s->size) {
|
||||||
|
if (s->bpos + n > s->maxsize) {
|
||||||
|
/* TO DO: here you might want to add a mechanism for limiting
|
||||||
|
the growth of the stream. */
|
||||||
|
newsize = s->maxsize * 2;
|
||||||
|
while (s->bpos + n > newsize)
|
||||||
|
newsize *= 2;
|
||||||
|
if (_buf_realloc(s, newsize) == NULL) {
|
||||||
|
/* no more space; write as much as we can */
|
||||||
|
amt = s->maxsize - s->bpos;
|
||||||
|
if (amt > 0) {
|
||||||
|
memcpy(&s->buf[s->bpos], data, amt);
|
||||||
|
}
|
||||||
|
s->bpos += amt;
|
||||||
|
s->size = s->maxsize;
|
||||||
|
return amt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s->size = s->bpos + n;
|
||||||
|
}
|
||||||
|
memcpy(&s->buf[s->bpos], data, n);
|
||||||
|
s->bpos += n;
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* interface functions, low level */
|
||||||
|
|
||||||
|
size_t ios_read(ios_t *s, char *dest, size_t n)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ios_write(ios_t *s, char *data, size_t n)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t ios_seek(ios_t *s, off_t pos)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t ios_seek_end(ios_t *s)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t ios_skip(ios_t *s, off_t offs)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t ios_pos(ios_t *s)
|
||||||
|
{
|
||||||
|
if (s->bm == bm_mem)
|
||||||
|
return (off_t)s->bpos;
|
||||||
|
|
||||||
|
off_t fdpos = lseek(s->fd, 0, SEEK_CUR);
|
||||||
|
if (fdpos == (off_t)-1)
|
||||||
|
return fdpos;
|
||||||
|
|
||||||
|
if (s->state == iost_wr)
|
||||||
|
fdpos += s->bpos;
|
||||||
|
else if (s->state == iost_rd)
|
||||||
|
fdpos -= (s->size - s->bpos);
|
||||||
|
return fdpos;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ios_trunc(ios_t *s, size_t size)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int ios_eof(ios_t *s)
|
||||||
|
{
|
||||||
|
if (s->bm == bm_mem)
|
||||||
|
return (s->bpos >= s->size);
|
||||||
|
if (s->fd == -1)
|
||||||
|
return 1;
|
||||||
|
// todo
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _discard_partial_buffer(ios_t *s)
|
||||||
|
{
|
||||||
|
// this function preserves the invariant that data to write
|
||||||
|
// begins at the beginning of the buffer, and s->size refers
|
||||||
|
// to how much valid file data is stored in the buffer.
|
||||||
|
|
||||||
|
// this needs to be called when normal operation is interrupted in
|
||||||
|
// the middle of the buffer. "normal operation" is reading or
|
||||||
|
// writing to the end of the buffer. this happens e.g. when flushing.
|
||||||
|
if (s->bpos && s->size > s->bpos) {
|
||||||
|
memmove(s->buf, s->buf + s->bpos, s->size - s->bpos);
|
||||||
|
}
|
||||||
|
s->size -= s->bpos;
|
||||||
|
s->bpos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ios_flush(ios_t *s)
|
||||||
|
{
|
||||||
|
if (ndirty == 0 || s->bm == bm_mem || s->buf == NULL)
|
||||||
|
return 0;
|
||||||
|
if (s->fd == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int partialb=0;
|
||||||
|
if (s->bitpos > 0 && s->ndirty==s->bpos+1) {
|
||||||
|
// flushing partial byte
|
||||||
|
partialb=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t nw, ntowrite=s->ndirty;
|
||||||
|
int err = _os_write(s->fd, s->buf, ntowrite, &nw);
|
||||||
|
// todo: try recovering from some kinds of errors (e.g. retry)
|
||||||
|
if (partialb) {
|
||||||
|
// skip back 1, since we might have to write this byte again
|
||||||
|
// if more bits in it are changed
|
||||||
|
if (lseek(s->fd, -1, SEEK_CUR) == (off_t)-1) {
|
||||||
|
// uhoh. can't write the "rest" of this byte. move to next
|
||||||
|
// byte instead.
|
||||||
|
s->bpos++;
|
||||||
|
s->bitpos = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_discard_partial_buffer(s);
|
||||||
|
s->ndirty = 0;
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
if (nw < ntowrite)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ios_close(ios_t *s)
|
||||||
|
{
|
||||||
|
ios_flush(s);
|
||||||
|
if (s->fd != -1 && s->ownfd)
|
||||||
|
close(s->fd);
|
||||||
|
s->fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *ios_takebuf(ios_t *s, size_t *psize)
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
ios_flush(s);
|
||||||
|
|
||||||
|
if (s->buf == &s->local[0]) {
|
||||||
|
buf = malloc(s->size+1);
|
||||||
|
if (buf == NULL)
|
||||||
|
return NULL;
|
||||||
|
if (s->size)
|
||||||
|
memcpy(buf, s->buf, s->size);
|
||||||
|
buf[s->size] = '\0';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
buf = s->buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
*psize = s->size+1; // buffer is actually 1 bigger for terminating NUL
|
||||||
|
|
||||||
|
/* empty stream and reinitialize */
|
||||||
|
if (s->bm == bm_mem || s->bm == bm_none) {
|
||||||
|
s->buf = &s->local[0];
|
||||||
|
s->maxsize = IOS_INLSIZE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s->buf = NULL;
|
||||||
|
_buf_realloc(s, IOS_BUFSIZE);
|
||||||
|
}
|
||||||
|
s->size = s->bpos = 0;
|
||||||
|
s->bitpos = 0;
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ios_setbuf(ios_t *s, char *buf, size_t size, int own)
|
||||||
|
{
|
||||||
|
ios_flush(s);
|
||||||
|
size_t nvalid=0;
|
||||||
|
|
||||||
|
nvalid = s->size;
|
||||||
|
if (s->size == s->bpos && s->bitpos>0)
|
||||||
|
nvalid++;
|
||||||
|
if (size < nvalid)
|
||||||
|
nvalid = size;
|
||||||
|
memcpy(buf, s->buf, nvalid);
|
||||||
|
if (s->bpos > nvalid) {
|
||||||
|
// truncated
|
||||||
|
s->bpos = nvalid;
|
||||||
|
s->bitpos = 0;
|
||||||
|
}
|
||||||
|
s->size = nvalid;
|
||||||
|
|
||||||
|
if (s->buf!=NULL && s->ownbuf && s->buf!=&s->local[0])
|
||||||
|
free(s->buf);
|
||||||
|
s->buf = buf;
|
||||||
|
s->maxsize = size;
|
||||||
|
s->ownbuf = own;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ios_bufmode(ios_t *s, bufmode_t mode)
|
||||||
|
{
|
||||||
|
// no fd; can only do mem-only buffering
|
||||||
|
if (s->fd == -1 && mode != bm_mem)
|
||||||
|
return -1;
|
||||||
|
s->bm = mode;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ios_bswap(ios_t *s, int bswap)
|
||||||
|
{
|
||||||
|
s->byteswap = !!bswap;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ios_copy(ios_t *to, ios_t *from, size_t nbytes, bool_t all)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* stream object initializers. we do no allocation. */
|
||||||
|
|
||||||
|
ios_t *ios_file(ios_t *s, char *fname, int create, int rewrite)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ios_t *ios_mem(ios_t *s, size_t initsize)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ios_t *ios_fd(ios_t *s, long fd)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* higher level interface */
|
||||||
|
|
||||||
|
int ios_putbit(ios_t *s, int bit)
|
||||||
|
{
|
||||||
|
byte_t mask = 1<<s->bitpos;
|
||||||
|
|
||||||
|
if (_ios_setstate(s, iost_wr))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!s->dirty) {
|
||||||
|
// haven't written any bits yet
|
||||||
|
// if stenciling is turned on, the buffer is already full and
|
||||||
|
// we don't need to do anything
|
||||||
|
if (s->rereadable && !s->stenciled) {
|
||||||
|
// fill buffer if we can
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bit)
|
||||||
|
s->buf[s->bpos] |= mask;
|
||||||
|
else
|
||||||
|
s->buf[s->bpos] &= ~mask;
|
||||||
|
s->dirty = 1;
|
||||||
|
|
||||||
|
s->bitpos++;
|
||||||
|
if (s->bitpos > 7) {
|
||||||
|
s->bitpos = 0;
|
||||||
|
s->bpos++;
|
||||||
|
s->tally++;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ios_getbit(ios_t *s, int *pbit)
|
||||||
|
{
|
||||||
|
byte_t mask = 1<<s->bitpos;
|
||||||
|
|
||||||
|
if (_ios_setstate(s, iost_rd))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*pbit = (s->buf[s->bpos] & mask) ? 1 : 0;
|
||||||
|
s->bitpos++;
|
||||||
|
if (s->bitpos > 7) {
|
||||||
|
s->bitpos = 0;
|
||||||
|
s->bpos++;
|
||||||
|
s->tally++;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
|
@ -0,0 +1,198 @@
|
||||||
|
#ifndef __IOS_H_
|
||||||
|
#define __IOS_H_
|
||||||
|
|
||||||
|
// this flag controls when data actually moves out to the underlying I/O
|
||||||
|
// channel. memory streams are a special case of this where the data
|
||||||
|
// never moves out.
|
||||||
|
typedef enum { bm_none, bm_line, bm_block, bm_mem } bufmode_t;
|
||||||
|
|
||||||
|
typedef enum { iost_none, iost_rd, iost_wr } iostate_t;
|
||||||
|
|
||||||
|
#define IOS_INLSIZE 54
|
||||||
|
#define IOS_BUFSIZE 4095
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bufmode_t bm;
|
||||||
|
|
||||||
|
// the state only indicates where the underlying file position is relative
|
||||||
|
// to the buffer. reading: at the end. writing: at the beginning.
|
||||||
|
// in general, you can do any operation in any state.
|
||||||
|
iostate_t state;
|
||||||
|
|
||||||
|
char *buf; // start of buffer
|
||||||
|
size_t maxsize; // space allocated to buffer
|
||||||
|
size_t size; // length of valid data in buf, >=ndirty
|
||||||
|
size_t bpos; // current position in buffer
|
||||||
|
size_t ndirty; // # bytes at &buf[0] that need to be written
|
||||||
|
|
||||||
|
// this is a public field that keeps a running count of bytes
|
||||||
|
// read or written. you can freely use and change it. this is
|
||||||
|
// intended for keeping track of relative positions in streams
|
||||||
|
// that don't have absolute positions (like sockets).
|
||||||
|
size_t tally;
|
||||||
|
|
||||||
|
// pointer-size integer to support platforms where it might have
|
||||||
|
// to be a pointer
|
||||||
|
long fd;
|
||||||
|
|
||||||
|
byte_t bitpos;
|
||||||
|
//unsigned char bitdirty:1; // bit buffer needs to be written
|
||||||
|
unsigned char byteswap:1;
|
||||||
|
//unsigned char readonly:1;
|
||||||
|
unsigned char ownbuf:1;
|
||||||
|
unsigned char ownfd:1;
|
||||||
|
|
||||||
|
// this means you can read, seek back, then read the same data
|
||||||
|
// again any number of times. usually only true for files and strings.
|
||||||
|
unsigned char rereadable:1;
|
||||||
|
|
||||||
|
// this enables "stenciled writes". you can alternately write and
|
||||||
|
// seek without flushing in between. this performs read-before-write
|
||||||
|
// to populate the buffer, so "rereadable" capability is required.
|
||||||
|
// this is off by default, except for bit I/O if rereadable is true.
|
||||||
|
unsigned char stenciled:1;
|
||||||
|
|
||||||
|
// request durable writes (fsync)
|
||||||
|
// unsigned char durable:1;
|
||||||
|
|
||||||
|
// todo: mutex
|
||||||
|
char local[IOS_INLSIZE];
|
||||||
|
} ios_t;
|
||||||
|
|
||||||
|
/* low-level interface functions */
|
||||||
|
size_t ios_read(ios_t *s, char *dest, size_t n);
|
||||||
|
size_t ios_write(ios_t *s, char *data, size_t n);
|
||||||
|
off_t ios_seek(ios_t *s, off_t pos); // absolute seek
|
||||||
|
off_t ios_seek_end(ios_t *s);
|
||||||
|
off_t ios_skip(ios_t *s, off_t offs); // relative seek
|
||||||
|
off_t ios_pos(ios_t *s); // get current position
|
||||||
|
size_t ios_trunc(ios_t *s, size_t size);
|
||||||
|
int ios_eof(ios_t *s);
|
||||||
|
int ios_flush(ios_t *s);
|
||||||
|
void ios_close(ios_t *s);
|
||||||
|
char *ios_takebuf(ios_t *s, size_t *psize); // release buffer to caller
|
||||||
|
// set buffer space to use
|
||||||
|
int ios_setbuf(ios_t *s, char *buf, size_t size, int own);
|
||||||
|
int ios_bufmode(ios_t *s, bufmode_t mode);
|
||||||
|
void ios_bswap(ios_t *s, int bswap);
|
||||||
|
int ios_copy(ios_t *to, ios_t *from, size_t nbytes, bool_t all);
|
||||||
|
//void ios_lock(ios_t *s);
|
||||||
|
//int ios_trylock(ios_t *s);
|
||||||
|
//int ios_unlock(ios_t *s);
|
||||||
|
|
||||||
|
/* stream creation */
|
||||||
|
ios_t *ios_file(ios_t *s, char *fname, int create, int rewrite);
|
||||||
|
ios_t *ios_mem(ios_t *s, size_t initsize);
|
||||||
|
ios_t *ios_fd(ios_t *s, long fd);
|
||||||
|
// todo: ios_socket
|
||||||
|
|
||||||
|
/* high-level functions - output */
|
||||||
|
int ios_putnum(ios_t *s, char *data, uint32_t type);
|
||||||
|
int ios_putint(ios_t *s, int n);
|
||||||
|
int ios_pututf8(ios_t *s, uint32_t wc);
|
||||||
|
int ios_putstringz(ios_t *s, char *str, bool_t do_write_nulterm);
|
||||||
|
/* single-bit I/O - even works for mixed reads and writes.
|
||||||
|
mixing bit-level I/O with normal byte stream I/O has undefined effects and
|
||||||
|
will almost certainly destroy your file. */
|
||||||
|
int ios_putbit(ios_t *s, int bit);
|
||||||
|
int ios_printf(ios_t *s, char *format, ...);
|
||||||
|
|
||||||
|
/* high-level stream functions - input */
|
||||||
|
int ios_getnum(ios_t *s, char *data, uint32_t type);
|
||||||
|
int ios_getutf8(ios_t *s, uint32_t *pwc);
|
||||||
|
int ios_ungetutf8(ios_t *s, uint32_t wc);
|
||||||
|
int ios_getstringz(ios_t *dest, ios_t *src);
|
||||||
|
int ios_getstringn(ios_t *dest, ios_t *src, size_t nchars);
|
||||||
|
int ios_readline(ios_t *dest, ios_t *s, char delim);
|
||||||
|
int ios_getline(ios_t *s, char **pbuf, size_t *psz);
|
||||||
|
int ios_getbit(ios_t *s, int *pbit); // returns # of bits read (0 or 1)
|
||||||
|
|
||||||
|
// seek by utf8 sequence increments
|
||||||
|
int ios_nextutf8(ios_t *s);
|
||||||
|
int ios_prevutf8(ios_t *s);
|
||||||
|
|
||||||
|
/* stdio-style functions */
|
||||||
|
#define IOS_EOF (-1)
|
||||||
|
int ios_putc(ios_t *s, int c);
|
||||||
|
wint_t ios_putwc(ios_t *s, wchar_t wc);
|
||||||
|
int ios_getc(ios_t *s);
|
||||||
|
wint_t ios_getwc(ios_t *s);
|
||||||
|
int ios_ungetc(ios_t *s, int c);
|
||||||
|
wint_t ios_ungetwc(ios_t *s, wint_t wc);
|
||||||
|
#define ios_puts(s, str) ios_write(s, str, strlen(str))
|
||||||
|
|
||||||
|
/*
|
||||||
|
With memory streams, mixed reads and writes are equivalent to performing
|
||||||
|
sequences of *p++, as either an lvalue or rvalue. File streams behave
|
||||||
|
similarly, but other streams might not support this. Using unbuffered
|
||||||
|
mode makes this more predictable.
|
||||||
|
|
||||||
|
Note on "unget" functions:
|
||||||
|
There are two kinds of functions here: those that operate on sized
|
||||||
|
blocks of bytes and those that operate on logical units like "character"
|
||||||
|
or "integer". The "unget" functions only work on logical units. There
|
||||||
|
is no "unget n bytes". You can only do an unget after a matching get.
|
||||||
|
However, data pushed back by an unget is available to all read operations.
|
||||||
|
The reason for this is that unget is defined in terms of its effect on
|
||||||
|
the underlying buffer (namely, it rebuffers data as if it had been
|
||||||
|
buffered but not read yet). IOS reserves the right to perform large block
|
||||||
|
operations directly, bypassing the buffer. In such a case data was
|
||||||
|
never buffered, so "rebuffering" has no meaning (i.e. there is no
|
||||||
|
correspondence between the buffer and the physical stream).
|
||||||
|
|
||||||
|
Single-bit I/O is able to write partial bytes ONLY IF the stream supports
|
||||||
|
seeking. Also, line buffering is not well-defined in the context of
|
||||||
|
single-bit I/O, so it might not do what you expect.
|
||||||
|
|
||||||
|
implementation notes:
|
||||||
|
in order to know where we are in a file, we must ensure the buffer
|
||||||
|
is only populated from the underlying stream starting with p==buf.
|
||||||
|
|
||||||
|
to switch from writing to reading: flush, set p=buf, cnt=0
|
||||||
|
to switch from reading to writing: seek backwards cnt bytes, p=buf, cnt=0
|
||||||
|
|
||||||
|
when writing: buf starts at curr. physical stream pos, p - buf is how
|
||||||
|
many bytes we've written logically. cnt==0
|
||||||
|
|
||||||
|
dirty == (bitpos>0 && state==iost_wr), EXCEPT right after switching from
|
||||||
|
reading to writing, where we might be in the middle of a byte without
|
||||||
|
having changed it.
|
||||||
|
|
||||||
|
to write a bit: if !dirty, read up to maxsize-(p-buf) into buffer, then
|
||||||
|
seek back by the same amount (undo it). write onto those bits. now set
|
||||||
|
the dirty bit. in this state, we can bit-read up to the end of the byte,
|
||||||
|
then formally switch to the read state using flush.
|
||||||
|
|
||||||
|
design points:
|
||||||
|
- data-source independence, including memory streams
|
||||||
|
- support 64-bit and large files
|
||||||
|
- efficient, low-latency buffering
|
||||||
|
- unget
|
||||||
|
- expose buffer to user, allow user-owned buffers
|
||||||
|
- allow direct I/O, don't always go through buffer
|
||||||
|
- buffer-internal seeking. makes seeking back 1-2 bytes very fast,
|
||||||
|
and makes it possible for sockets where it otherwise wouldn't be
|
||||||
|
- special support for utf8
|
||||||
|
- single-bit I/O
|
||||||
|
- tries to allow switching between reading and writing
|
||||||
|
- type-aware functions with byte-order swapping service
|
||||||
|
- position counter for meaningful data offsets with sockets
|
||||||
|
|
||||||
|
note:
|
||||||
|
the current code needs to be mostly rewritten. the design should be
|
||||||
|
as follows:
|
||||||
|
|
||||||
|
the buffer is a view of part of a file/stream. you can seek, read, and
|
||||||
|
write around in it as much as you like, as if it were just a string.
|
||||||
|
|
||||||
|
we keep track of the part of the buffer that's invalid (written to).
|
||||||
|
we remember whether the position of the underlying stream is aligned
|
||||||
|
with the end of the buffer (reading mode) or the beginning (writing mode).
|
||||||
|
|
||||||
|
based on this info, we might have to seek back before doing a flush.
|
||||||
|
|
||||||
|
as optimizations, we do no writing if the buffer isn't "dirty", and we
|
||||||
|
do no reading if the data will only be overwritten.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,213 @@
|
||||||
|
#ifndef __STREAMS_H_
|
||||||
|
#define __STREAMS_H_
|
||||||
|
|
||||||
|
struct _stream;
|
||||||
|
|
||||||
|
// numeric type codes
|
||||||
|
#define T_BOOL 0x000
|
||||||
|
#define T_BYTE 0x001
|
||||||
|
#define T_SHORT 0x002
|
||||||
|
#define T_INT 0x003
|
||||||
|
#define T_FLOAT 0x004
|
||||||
|
#define T_DOUBLE 0x005
|
||||||
|
#define T_INT64 0x006
|
||||||
|
//#define T_LDOUBLE 0x007
|
||||||
|
#define T_UNSIGNED 0x008
|
||||||
|
#define T_CPLX 0x010
|
||||||
|
|
||||||
|
#define T_TYPEMASK 0x1f /* bits related to numeric type */
|
||||||
|
#define T_TYPESIZE 0x07 /* bits related to type size */
|
||||||
|
|
||||||
|
#define is_type(a, t) (((a) & T_TYPESIZE) == (t))
|
||||||
|
// type_bitseq tells whether 2 types are bit-representation compatible
|
||||||
|
#define type_bitseq(a, b) (((a) & ~T_UNSIGNED) == ((b) & ~T_UNSIGNED))
|
||||||
|
|
||||||
|
extern unsigned int type_sizes[];
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void (*free_func)(struct _stream *s);
|
||||||
|
/* these return -1 on error, or new position if successful */
|
||||||
|
/* set absolute position */
|
||||||
|
off_t (*seek)(struct _stream *s, off_t where);
|
||||||
|
/* seek to end (past last byte) */
|
||||||
|
off_t (*seek_end)(struct _stream *s);
|
||||||
|
/* move relative to current position */
|
||||||
|
off_t (*skip)(struct _stream *s, off_t offs);
|
||||||
|
|
||||||
|
/* these return # of bytes read/written, 0 on error */
|
||||||
|
size_t (*read)(struct _stream *s, char *dest, size_t size);
|
||||||
|
size_t (*write)(struct _stream *s, char *data, size_t size);
|
||||||
|
|
||||||
|
/* truncate a stream to the given length */
|
||||||
|
size_t (*trunc)(struct _stream *s, size_t size);
|
||||||
|
|
||||||
|
/* no data left? */
|
||||||
|
bool_t (*eof)(struct _stream *s);
|
||||||
|
|
||||||
|
/* sync bit buffer, and sync to hardware if applicable */
|
||||||
|
void (*flush)(struct _stream *s);
|
||||||
|
/* could add fsync() call for durable writes */
|
||||||
|
} stream_interface_t;
|
||||||
|
|
||||||
|
extern stream_interface_t fs_funcs;
|
||||||
|
extern stream_interface_t ms_funcs;
|
||||||
|
extern stream_interface_t ps_funcs;
|
||||||
|
|
||||||
|
#define is_memstream(s) (((stream_t*)s)->funcs==&ms_funcs)
|
||||||
|
#define is_filestream(s) (((stream_t*)s)->funcs==&fs_funcs)
|
||||||
|
#define is_pipestream(s) (((stream_t*)s)->funcs==&ps_funcs)
|
||||||
|
|
||||||
|
/* general i/o chunk size */
|
||||||
|
#define CHUNK_SIZE 4096
|
||||||
|
|
||||||
|
/* this should be a multiple of 4; otherwise the struct gets padded to
|
||||||
|
the next multiple of 4 anyway, wasting space */
|
||||||
|
#define N_STREAM_LOCAL 40
|
||||||
|
|
||||||
|
typedef struct _stream {
|
||||||
|
/* unfortunately, it seems that pos needs to be a signed type to be
|
||||||
|
compatible with OS functions. */
|
||||||
|
off_t pos;
|
||||||
|
byte_t bitpos; /* offset within a byte, for writing individual bits */
|
||||||
|
byte_t bitbuf; /* a copy of the byte at the current stream position */
|
||||||
|
char ungotc;
|
||||||
|
struct {
|
||||||
|
/* does bit buffer need to be written? */
|
||||||
|
unsigned char dirty:1;
|
||||||
|
unsigned char byteswap:1;
|
||||||
|
unsigned char readonly:1;
|
||||||
|
unsigned char ungot:1;
|
||||||
|
};
|
||||||
|
|
||||||
|
stream_interface_t *funcs;
|
||||||
|
|
||||||
|
/* stream-specific data */
|
||||||
|
union {
|
||||||
|
char *name;
|
||||||
|
size_t maxsize;
|
||||||
|
int rd; // pipe read descriptor
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
FILE *fptr;
|
||||||
|
char *data;
|
||||||
|
char *s;
|
||||||
|
int wd; // pipe write descriptor
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
/* this is always a size in BYTES */
|
||||||
|
size_t size;
|
||||||
|
size_t len;
|
||||||
|
};
|
||||||
|
char local[N_STREAM_LOCAL];
|
||||||
|
} stream_t;
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
stream_t *filestream_new(stream_t *s, char *fName,
|
||||||
|
bool_t create, bool_t rewrite);
|
||||||
|
stream_t *memstream_new(stream_t *s, size_t initsize);
|
||||||
|
stream_t *pipestream_new(stream_t *s, int flags);
|
||||||
|
stream_t *stream_fromfile(stream_t *s, FILE *f, char *name);
|
||||||
|
//string_t *string_new(int len);
|
||||||
|
//string_t *string_fromc(char *s);
|
||||||
|
stream_t *memstream_copy(stream_t *s);
|
||||||
|
void stream_free(stream_t *s);
|
||||||
|
void stream_flush(stream_t *s);
|
||||||
|
|
||||||
|
|
||||||
|
/* high level stream functions */
|
||||||
|
|
||||||
|
/* 'all' means copy to end of stream */
|
||||||
|
int stream_copy(stream_t *to, stream_t *from, size_t nbytes, bool_t all);
|
||||||
|
|
||||||
|
int stream_put_num(stream_t *s, char *data, u_int32_t type);
|
||||||
|
int stream_put_int(stream_t *s, int n);
|
||||||
|
int stream_put_char(stream_t *s, u_int32_t wc);
|
||||||
|
int stream_put_stringz(stream_t *s, char *str, bool_t nulterm);
|
||||||
|
|
||||||
|
/* single-bit I/O - even works for mixed reads and writes.
|
||||||
|
mixing bit-level I/O with normal byte stream I/O has undefined effects and
|
||||||
|
will almost certainly destroy your file. however, it is safe to switch
|
||||||
|
between bit and byte I/O if you call stream_flush in between. */
|
||||||
|
void stream_put_bit(stream_t *s, int bit);
|
||||||
|
|
||||||
|
/* warning: this uses a fixed-size buffer. it is intended only for printing
|
||||||
|
normal things like "a= %d". if you might be printing a large buffer, you
|
||||||
|
should use stream i/o functions directly. */
|
||||||
|
int stream_printf(stream_t *s, char *format, ...);
|
||||||
|
|
||||||
|
|
||||||
|
/* high level stream functions - input */
|
||||||
|
|
||||||
|
int stream_get_num(stream_t *s, char *data, u_int32_t type);
|
||||||
|
int stream_get_char(stream_t *s, u_int32_t *pwc);
|
||||||
|
int stream_get_stringz(stream_t *dest, stream_t *src);
|
||||||
|
int stream_get_stringn(stream_t *dest, stream_t *src, size_t c);
|
||||||
|
int stream_readline(stream_t *dest, stream_t *s, char delim);
|
||||||
|
int stream_getline(stream_t *s, char **pbuf, size_t *psz);
|
||||||
|
/* returns # of bits read (0 or 1) */
|
||||||
|
int stream_get_bit(stream_t *s, int *pbit);
|
||||||
|
|
||||||
|
int stream_nextchar(stream_t *s);
|
||||||
|
int stream_prevchar(stream_t *s);
|
||||||
|
|
||||||
|
void stream_close(stream_t *s);
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
// stream_fgetc
|
||||||
|
// stream_ungetc
|
||||||
|
|
||||||
|
/* get underlying file descriptors, -1 if none */
|
||||||
|
int stream_readfd(stream_t *s);
|
||||||
|
int stream_writefd(stream_t *s);
|
||||||
|
|
||||||
|
/*
|
||||||
|
low level stream functions
|
||||||
|
|
||||||
|
Streams are intended to provide a uniform function interface to various
|
||||||
|
kinds of byte streams.
|
||||||
|
|
||||||
|
The eight low-level stream functions (below) are intended to be light weight.
|
||||||
|
It must be easy to implement reasonably efficient higher-level stream
|
||||||
|
functions, therefore any complexity required to make (for example) single
|
||||||
|
byte reads and writes efficient must be implemented by the stream.
|
||||||
|
|
||||||
|
Note that you can implement file streams using fread(), fwrite(), etc.
|
||||||
|
because buffering is already implemented in every standard C library. These
|
||||||
|
calls do not make system calls in general, and are perfectly fine to use.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define stream_seek(s, w) (s)->funcs->seek(s, w)
|
||||||
|
#define stream_seek_end(s) (s)->funcs->seek_end(s)
|
||||||
|
#define stream_skip(s, o) (s)->funcs->skip(s, o)
|
||||||
|
#define stream_read(s, d, sz) (s)->funcs->read(s, (char*)d, sz)
|
||||||
|
#define stream_write(s, d, sz) (s)->funcs->write(s, (char*)d, sz)
|
||||||
|
#define stream_trunc(s, sz) (s)->funcs->trunc(s, sz)
|
||||||
|
#define stream_eof(s) (s)->funcs->eof(s)
|
||||||
|
|
||||||
|
|
||||||
|
STATIC_INLINE size_t stream_put_byte(stream_t *s, byte_t b)
|
||||||
|
{
|
||||||
|
return stream_write(s, (char*)&b, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC_INLINE size_t stream_get_byte(stream_t *s, byte_t *pb)
|
||||||
|
{
|
||||||
|
return stream_read(s, (char*)pb, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define stream_puts(s, str) stream_write(s, str, strlen(str))
|
||||||
|
|
||||||
|
/*
|
||||||
|
stream_take_buffer
|
||||||
|
|
||||||
|
This lets you get the data of a stream without having to copy it. In order
|
||||||
|
not to either lose the buffer or free it twice, this operation effectively
|
||||||
|
empties the stream. In other words, size goes to 0, data becomes NULL.
|
||||||
|
Whoever called the function takes full responsibility for the buffer.
|
||||||
|
You must free it eventually.
|
||||||
|
"size" gets set to the size of the data in the buffer.
|
||||||
|
*/
|
||||||
|
char *stream_take_buffer(stream_t *s, size_t *size);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,68 @@
|
||||||
|
/* moving data in small power-of-2 sized units */
|
||||||
|
void copy_el(char *dest, char *src, size_t sz)
|
||||||
|
{
|
||||||
|
switch (sz) {
|
||||||
|
case 16:
|
||||||
|
*(int64_t*)&dest[0] = *(int64_t*)&src[0];
|
||||||
|
*(int64_t*)&dest[8] = *(int64_t*)&src[8];
|
||||||
|
break;
|
||||||
|
case 8: *(int64_t*)dest = *(int64_t*)src; break;
|
||||||
|
case 4: *(int32_t*)dest = *(int32_t*)src; break;
|
||||||
|
case 2: *(int16_t*)dest = *(int16_t*)src; break;
|
||||||
|
case 1: *dest = *src; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap_el(char *a, char *b, size_t sz)
|
||||||
|
{
|
||||||
|
int64_t i64;
|
||||||
|
int32_t i32;
|
||||||
|
int16_t i16;
|
||||||
|
int8_t i8;
|
||||||
|
switch (sz) {
|
||||||
|
case 16:
|
||||||
|
i64 = *(int64_t*)&a[0];
|
||||||
|
*(int64_t*)&a[0] = *(int64_t*)&b[0];
|
||||||
|
*(int64_t*)&b[0] = i64;
|
||||||
|
i64 = *(int64_t*)&a[8];
|
||||||
|
*(int64_t*)&a[8] = *(int64_t*)&b[8];
|
||||||
|
*(int64_t*)&b[8] = i64;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
i64 = *(int64_t*)a;
|
||||||
|
*(int64_t*)a = *(int64_t*)b;
|
||||||
|
*(int64_t*)b = i64;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
i32 = *(int32_t*)a;
|
||||||
|
*(int32_t*)a = *(int32_t*)b;
|
||||||
|
*(int32_t*)b = i32;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
i16 = *(int16_t*)a;
|
||||||
|
*(int16_t*)a = *(int16_t*)b;
|
||||||
|
*(int16_t*)b = i16;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
i8 = *a;
|
||||||
|
*a = *b;
|
||||||
|
*b = i8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void neg_any(void *dest, void *a, numerictype_t tag)
|
||||||
|
{
|
||||||
|
switch (tag) {
|
||||||
|
case T_INT8: *(int8_t *)dest = -*(int8_t *)a; break;
|
||||||
|
case T_UINT8: *(uint8_t *)dest = -*(uint8_t *)a; break;
|
||||||
|
case T_INT16: *(int16_t *)dest = -*(int16_t *)a; break;
|
||||||
|
case T_UINT16: *(uint16_t*)dest = -*(uint16_t*)a; break;
|
||||||
|
case T_INT32: *(int32_t *)dest = -*(int32_t *)a; break;
|
||||||
|
case T_UINT32: *(uint32_t*)dest = -*(uint32_t*)a; break;
|
||||||
|
case T_INT64: *(int64_t *)dest = -*(int64_t *)a; break;
|
||||||
|
case T_UINT64: *(uint64_t*)dest = -*(uint64_t*)a; break;
|
||||||
|
case T_FLOAT: *(float *)dest = -*(float *)a; break;
|
||||||
|
case T_DOUBLE: *(double *)dest = -*(double *)a; break;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,544 @@
|
||||||
|
/*
|
||||||
|
bit vector primitives
|
||||||
|
|
||||||
|
todo:
|
||||||
|
* reverse
|
||||||
|
* nreverse
|
||||||
|
(- rotate left/right)
|
||||||
|
* shl_to
|
||||||
|
* not
|
||||||
|
- shr_row, shl_row
|
||||||
|
|
||||||
|
These routines are the back end supporting bit matrices. Many operations
|
||||||
|
on bit matrices are slow (such as accessing or setting a single element!)
|
||||||
|
but certain operations are privileged and lend themselves to extremely
|
||||||
|
efficient implementation due to the bit-vector nature of machine integers.
|
||||||
|
These are:
|
||||||
|
done:
|
||||||
|
& | $ ~ copy reverse fill sum prod
|
||||||
|
todo:
|
||||||
|
shift trans rowswap
|
||||||
|
would be nice:
|
||||||
|
channel interleave
|
||||||
|
|
||||||
|
Important note:
|
||||||
|
Out-of-place functions always assume dest and source have the same amount
|
||||||
|
of space available.
|
||||||
|
|
||||||
|
shr_to, shl_to, not_to, and reverse_to assume source and dest don't overlap
|
||||||
|
and_to, or_to, and xor_to allow overlap.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "dtypes.h"
|
||||||
|
#include "bitvector.h"
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <malloc.h>
|
||||||
|
#define alloca _alloca
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// greater than this # of words we use malloc instead of alloca
|
||||||
|
#define MALLOC_CUTOFF 2000
|
||||||
|
|
||||||
|
u_int32_t *bitvector_resize(u_int32_t *b, size_t n, int initzero)
|
||||||
|
{
|
||||||
|
u_int32_t *p;
|
||||||
|
size_t sz = ((n+31)>>5) * 4;
|
||||||
|
p = realloc(b, sz);
|
||||||
|
if (p == NULL) return NULL;
|
||||||
|
if (initzero) memset(p, 0, sz);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
u_int32_t *bitvector_new(size_t n, int initzero)
|
||||||
|
{
|
||||||
|
return bitvector_resize(NULL, n, initzero);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitvector_set(u_int32_t *b, u_int32_t n, u_int32_t c)
|
||||||
|
{
|
||||||
|
if (c)
|
||||||
|
b[n>>5] |= (1<<(n&31));
|
||||||
|
else
|
||||||
|
b[n>>5] &= ~(1<<(n&31));
|
||||||
|
}
|
||||||
|
|
||||||
|
u_int32_t bitvector_get(u_int32_t *b, u_int32_t n)
|
||||||
|
{
|
||||||
|
return b[n>>5] & (1<<(n&31));
|
||||||
|
}
|
||||||
|
|
||||||
|
u_int32_t bitreverse(u_int32_t x)
|
||||||
|
{
|
||||||
|
u_int32_t m;
|
||||||
|
|
||||||
|
#ifdef __INTEL_COMPILER
|
||||||
|
x = _bswap(x);
|
||||||
|
#else
|
||||||
|
x = (x >> 16) | (x << 16); m = 0xff00ff00;
|
||||||
|
x = ((x & m) >> 8) | ((x & ~m) << 8);
|
||||||
|
#endif
|
||||||
|
m = 0xf0f0f0f0;
|
||||||
|
x = ((x & m) >> 4) | ((x & ~m) << 4); m = 0xcccccccc;
|
||||||
|
x = ((x & m) >> 2) | ((x & ~m) << 2); m = 0xaaaaaaaa;
|
||||||
|
x = ((x & m) >> 1) | ((x & ~m) << 1);
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// shift all bits in a long bit vector
|
||||||
|
// n is # of int32s to consider, s is shift distance
|
||||||
|
// lowest bit-index is bit 0 of word 0
|
||||||
|
// TODO: handle boundary case of shift distance >= data size?
|
||||||
|
void bitvector_shr(u_int32_t *b, size_t n, u_int32_t s)
|
||||||
|
{
|
||||||
|
u_int32_t i;
|
||||||
|
if (s == 0 || n == 0) return;
|
||||||
|
i = (s>>5);
|
||||||
|
if (i) {
|
||||||
|
n -= i;
|
||||||
|
memmove(b, &b[i], n*4);
|
||||||
|
memset(&b[n], 0, i*4);
|
||||||
|
s &= 31;
|
||||||
|
}
|
||||||
|
for(i=0; i < n-1; i++) {
|
||||||
|
b[i] = (b[i]>>s) | (b[i+1]<<(32-s));
|
||||||
|
}
|
||||||
|
b[i]>>=s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// out-of-place version, good for re-aligning a strided submatrix to
|
||||||
|
// linear representation when a copy is needed
|
||||||
|
// assumes that dest has the same amount of space as source, even if it
|
||||||
|
// wouldn't have been necessary to hold the shifted bits
|
||||||
|
void bitvector_shr_to(u_int32_t *dest, u_int32_t *b, size_t n, u_int32_t s)
|
||||||
|
{
|
||||||
|
u_int32_t i, j;
|
||||||
|
if (n == 0) return;
|
||||||
|
if (s == 0) {
|
||||||
|
memcpy(dest, b, n*4);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
j = (s>>5);
|
||||||
|
if (j) {
|
||||||
|
n -= j;
|
||||||
|
memset(&dest[n], 0, j*4);
|
||||||
|
s &= 31;
|
||||||
|
b = &b[j];
|
||||||
|
}
|
||||||
|
for(i=0; i < n-1; i++) {
|
||||||
|
dest[i] = (b[i]>>s) | (b[i+1]<<(32-s));
|
||||||
|
}
|
||||||
|
dest[i] = b[i]>>s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitvector_shl(u_int32_t *b, size_t n, u_int32_t s)
|
||||||
|
{
|
||||||
|
u_int32_t i, scrap=0, temp;
|
||||||
|
if (s == 0 || n == 0) return;
|
||||||
|
i = (s>>5);
|
||||||
|
if (i) {
|
||||||
|
n -= i;
|
||||||
|
memmove(&b[i], b, n*4);
|
||||||
|
memset(b, 0, i*4);
|
||||||
|
s &= 31;
|
||||||
|
b = &b[i];
|
||||||
|
}
|
||||||
|
for(i=0; i < n; i++) {
|
||||||
|
temp = (b[i]<<s) | scrap;
|
||||||
|
scrap = b[i]>>(32-s);
|
||||||
|
b[i] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if dest has more space than source, set scrap to true to keep the
|
||||||
|
// top bits that would otherwise be shifted out
|
||||||
|
void bitvector_shl_to(u_int32_t *dest, u_int32_t *b, size_t n, u_int32_t s,
|
||||||
|
bool_t scrap)
|
||||||
|
{
|
||||||
|
u_int32_t i, j, sc=0;
|
||||||
|
if (n == 0) return;
|
||||||
|
if (s == 0) {
|
||||||
|
memcpy(dest, b, n*4);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
j = (s>>5);
|
||||||
|
if (j) {
|
||||||
|
n -= j;
|
||||||
|
memset(dest, 0, j*4);
|
||||||
|
s &= 31;
|
||||||
|
dest = &dest[j];
|
||||||
|
}
|
||||||
|
for(i=0; i < n; i++) {
|
||||||
|
dest[i] = (b[i]<<s) | sc;
|
||||||
|
sc = b[i]>>(32-s);
|
||||||
|
}
|
||||||
|
if (scrap)
|
||||||
|
dest[i] = sc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set nbits to c, starting at given bit offset
|
||||||
|
// assumes offs < 32
|
||||||
|
void bitvector_fill(u_int32_t *b, u_int32_t offs, u_int32_t c, u_int32_t nbits)
|
||||||
|
{
|
||||||
|
index_t i;
|
||||||
|
u_int32_t nw, tail;
|
||||||
|
u_int32_t mask;
|
||||||
|
|
||||||
|
if (nbits == 0) return;
|
||||||
|
nw = (offs+nbits+31)>>5;
|
||||||
|
|
||||||
|
if (nw == 1) {
|
||||||
|
mask = (lomask(nbits)<<offs);
|
||||||
|
if (c) b[0]|=mask; else b[0]&=(~mask);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mask = lomask(offs);
|
||||||
|
if (c) b[0]|=(~mask); else b[0]&=mask;
|
||||||
|
|
||||||
|
if (c) mask=ONES32; else mask = 0;
|
||||||
|
for(i=1; i < nw-1; i++)
|
||||||
|
b[i] = mask;
|
||||||
|
|
||||||
|
tail = (offs+nbits)&31;
|
||||||
|
if (tail==0) {
|
||||||
|
b[i] = mask;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mask = lomask(tail);
|
||||||
|
if (c) b[i]|=mask; else b[i]&=(~mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitvector_not(u_int32_t *b, u_int32_t offs, u_int32_t nbits)
|
||||||
|
{
|
||||||
|
index_t i;
|
||||||
|
u_int32_t nw, tail;
|
||||||
|
u_int32_t mask;
|
||||||
|
|
||||||
|
if (nbits == 0) return;
|
||||||
|
nw = (offs+nbits+31)>>5;
|
||||||
|
|
||||||
|
if (nw == 1) {
|
||||||
|
mask = (lomask(nbits)<<offs);
|
||||||
|
b[0] ^= mask;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mask = ~lomask(offs);
|
||||||
|
b[0]^=mask;
|
||||||
|
|
||||||
|
for(i=1; i < nw-1; i++)
|
||||||
|
b[i] = ~b[i];
|
||||||
|
|
||||||
|
tail = (offs+nbits)&31;
|
||||||
|
if (tail==0) {
|
||||||
|
b[i] = ~b[i];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mask = lomask(tail);
|
||||||
|
b[i]^=mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// constant-space bit vector copy in a single pass, with arbitrary
|
||||||
|
// offsets and lengths. to get this right, there are 16 cases to handle!
|
||||||
|
#define BITVECTOR_COPY_OP(name, OP) \
|
||||||
|
void bitvector_##name(u_int32_t *dest, u_int32_t doffs, \
|
||||||
|
u_int32_t *src, u_int32_t soffs, u_int32_t nbits) \
|
||||||
|
{ \
|
||||||
|
index_t i; \
|
||||||
|
u_int32_t s, nw, tail, snw; \
|
||||||
|
u_int32_t mask, scrap; \
|
||||||
|
\
|
||||||
|
if (nbits == 0) return; \
|
||||||
|
nw = (doffs+nbits+31)>>5; \
|
||||||
|
\
|
||||||
|
if (soffs == doffs) { \
|
||||||
|
if (nw == 1) { \
|
||||||
|
mask = (lomask(nbits)<<doffs); \
|
||||||
|
dest[0] = (dest[0] & ~mask) | (OP(src[0]) & mask); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
mask = ~lomask(doffs); \
|
||||||
|
dest[0] = (dest[0] & ~mask) | (OP(src[0]) & mask); \
|
||||||
|
for(i=1; i < nw-1; i++) \
|
||||||
|
dest[i] = OP(src[i]); \
|
||||||
|
tail = (doffs+nbits)&31; \
|
||||||
|
if (tail==0) { dest[i]=src[i]; } else { \
|
||||||
|
mask = lomask(tail); \
|
||||||
|
dest[i] = (dest[i] & ~mask) | (OP(src[i]) & mask); } \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
snw = (soffs+nbits+31)>>5; \
|
||||||
|
if (soffs < doffs) { \
|
||||||
|
s = doffs-soffs; \
|
||||||
|
if (nw == 1) { \
|
||||||
|
mask = (lomask(nbits)<<doffs); \
|
||||||
|
dest[0] = (dest[0] & ~mask) | ((OP(src[0])<<s) & mask); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
mask = ~lomask(doffs); \
|
||||||
|
dest[0] = (dest[0] & ~mask) | ((OP(src[0])<<s) & mask); \
|
||||||
|
scrap = OP(src[0])>>(32-s); \
|
||||||
|
for(i=1; i < snw-1; i++) { \
|
||||||
|
dest[i] = (OP(src[i])<<s) | scrap; \
|
||||||
|
scrap = OP(src[i])>>(32-s); \
|
||||||
|
} \
|
||||||
|
tail = (doffs+nbits)&31; \
|
||||||
|
if (tail==0) { mask=ONES32; } else { mask = lomask(tail); } \
|
||||||
|
if (snw == nw) { \
|
||||||
|
dest[i] = (dest[i] & ~mask) | (((OP(src[i])<<s)|scrap) & mask); \
|
||||||
|
} \
|
||||||
|
else /* snw < nw */ { \
|
||||||
|
if (snw == 1) { \
|
||||||
|
dest[i] = (dest[i] & ~mask) | \
|
||||||
|
(((OP(src[i])<<s) | scrap) & mask); \
|
||||||
|
} \
|
||||||
|
else { \
|
||||||
|
dest[i] = (OP(src[i])<<s) | scrap; \
|
||||||
|
scrap = OP(src[i])>>(32-s); \
|
||||||
|
i++; \
|
||||||
|
dest[i] = (dest[i] & ~mask) | (scrap & mask); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
else { \
|
||||||
|
s = soffs-doffs; \
|
||||||
|
if (snw == 1) { \
|
||||||
|
mask = (lomask(nbits)<<doffs); \
|
||||||
|
dest[0] = (dest[0] & ~mask) | ((OP(src[0])>>s) & mask); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
if (nw == 1) { \
|
||||||
|
mask = (lomask(nbits)<<doffs); \
|
||||||
|
dest[0] = (dest[0] & ~mask) | \
|
||||||
|
(((OP(src[0])>>s)|(OP(src[1])<<(32-s))) & mask); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
mask = ~lomask(doffs); \
|
||||||
|
dest[0] = (dest[0] & ~mask) | \
|
||||||
|
(((OP(src[0])>>s)|(OP(src[1])<<(32-s))) & mask); \
|
||||||
|
for(i=1; i < nw-1; i++) { \
|
||||||
|
dest[i] = (OP(src[i])>>s) | (OP(src[i+1])<<(32-s)); \
|
||||||
|
} \
|
||||||
|
tail = (doffs+nbits)&31; \
|
||||||
|
if (tail==0) { mask=ONES32; } else { mask = lomask(tail); } \
|
||||||
|
if (snw == nw) { \
|
||||||
|
dest[i] = (dest[i] & ~mask) | ((OP(src[i])>>s) & mask); \
|
||||||
|
} \
|
||||||
|
else /* snw > nw */ { \
|
||||||
|
dest[i] = (dest[i] & ~mask) | \
|
||||||
|
(((OP(src[i])>>s)|(OP(src[i+1])<<(32-s))) & mask); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BV_COPY(a) (a)
|
||||||
|
#define BV_NOT(a) (~(a))
|
||||||
|
BITVECTOR_COPY_OP(copy, BV_COPY)
|
||||||
|
BITVECTOR_COPY_OP(not_to, BV_NOT)
|
||||||
|
|
||||||
|
// right-shift the bits in one logical "row" of a long 2d bit vector
|
||||||
|
/*
|
||||||
|
void bitvector_shr_row(u_int32_t *b, u_int32_t offs, size_t nbits, u_int32_t s)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// copy from source to dest while reversing bit-order
|
||||||
|
// assumes dest offset == 0
|
||||||
|
// assumes source and dest don't overlap
|
||||||
|
// assumes offset < 32
|
||||||
|
void bitvector_reverse_to(u_int32_t *dest, u_int32_t *src, u_int32_t soffs,
|
||||||
|
u_int32_t nbits)
|
||||||
|
{
|
||||||
|
index_t i;
|
||||||
|
u_int32_t nw, tail;
|
||||||
|
|
||||||
|
if (nbits == 0) return;
|
||||||
|
|
||||||
|
nw = (soffs+nbits+31)>>5;
|
||||||
|
// first, reverse the words while reversing bit order within each word
|
||||||
|
for(i=0; i < nw/2; i++) {
|
||||||
|
dest[i] = bitreverse(src[nw-i-1]);
|
||||||
|
dest[nw-i-1] = bitreverse(src[i]);
|
||||||
|
}
|
||||||
|
if (nw&0x1)
|
||||||
|
dest[i] = bitreverse(src[i]);
|
||||||
|
|
||||||
|
tail = (soffs+nbits)&31;
|
||||||
|
if (tail)
|
||||||
|
bitvector_shr(dest, nw, 32-tail);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitvector_reverse(u_int32_t *b, u_int32_t offs, u_int32_t nbits)
|
||||||
|
{
|
||||||
|
index_t i;
|
||||||
|
u_int32_t nw, tail;
|
||||||
|
u_int32_t *temp;
|
||||||
|
|
||||||
|
if (nbits == 0) return;
|
||||||
|
|
||||||
|
nw = (offs+nbits+31)>>5;
|
||||||
|
temp = (nw > MALLOC_CUTOFF) ? malloc(nw*4) : alloca(nw*4);
|
||||||
|
for(i=0; i < nw/2; i++) {
|
||||||
|
temp[i] = bitreverse(b[nw-i-1]);
|
||||||
|
temp[nw-i-1] = bitreverse(b[i]);
|
||||||
|
}
|
||||||
|
if (nw&0x1)
|
||||||
|
temp[i] = bitreverse(b[i]);
|
||||||
|
|
||||||
|
tail = (offs+nbits)&31;
|
||||||
|
bitvector_copy(b, offs, temp, (32-tail)&31, nbits);
|
||||||
|
if (nw > MALLOC_CUTOFF) free(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
u_int32_t bitvector_count(u_int32_t *b, u_int32_t offs, u_int32_t nbits)
|
||||||
|
{
|
||||||
|
index_t i;
|
||||||
|
u_int32_t nw, tail;
|
||||||
|
u_int32_t ans;
|
||||||
|
|
||||||
|
if (nbits == 0) return 0;
|
||||||
|
nw = (offs+nbits+31)>>5;
|
||||||
|
|
||||||
|
if (nw == 1) {
|
||||||
|
return count_bits(b[0] & (lomask(nbits)<<offs));
|
||||||
|
}
|
||||||
|
|
||||||
|
ans = count_bits(b[0]>>offs); // first end cap
|
||||||
|
|
||||||
|
for(i=1; i < nw-1; i++) {
|
||||||
|
/* popcnt can be computed branch-free, so these special cases
|
||||||
|
probably don't help much */
|
||||||
|
/*
|
||||||
|
v = b[i];
|
||||||
|
if (v == 0)
|
||||||
|
continue;
|
||||||
|
if (v == ONES32)
|
||||||
|
ans += 32;
|
||||||
|
else
|
||||||
|
*/
|
||||||
|
ans += count_bits(b[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
tail = (offs+nbits)&31;
|
||||||
|
ans += count_bits(b[i]&(tail>0?lomask(tail):ONES32)); // last end cap
|
||||||
|
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
u_int32_t bitvector_any0(u_int32_t *b, u_int32_t offs, u_int32_t nbits)
|
||||||
|
{
|
||||||
|
index_t i;
|
||||||
|
u_int32_t nw, tail;
|
||||||
|
u_int32_t mask;
|
||||||
|
|
||||||
|
if (nbits == 0) return 0;
|
||||||
|
nw = (offs+nbits+31)>>5;
|
||||||
|
|
||||||
|
if (nw == 1) {
|
||||||
|
mask = (lomask(nbits)<<offs);
|
||||||
|
if ((b[0] & mask) != mask) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mask = ~lomask(offs);
|
||||||
|
if ((b[0] & mask) != mask) return 1;
|
||||||
|
|
||||||
|
for(i=1; i < nw-1; i++) {
|
||||||
|
if (b[i] != ONES32) return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tail = (offs+nbits)&31;
|
||||||
|
if (tail==0) {
|
||||||
|
if (b[i] != ONES32) return 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mask = lomask(tail);
|
||||||
|
if ((b[i] & mask) != mask) return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u_int32_t bitvector_any1(u_int32_t *b, u_int32_t offs, u_int32_t nbits)
|
||||||
|
{
|
||||||
|
index_t i;
|
||||||
|
u_int32_t nw, tail;
|
||||||
|
u_int32_t mask;
|
||||||
|
|
||||||
|
if (nbits == 0) return 0;
|
||||||
|
nw = (offs+nbits+31)>>5;
|
||||||
|
|
||||||
|
if (nw == 1) {
|
||||||
|
mask = (lomask(nbits)<<offs);
|
||||||
|
if ((b[0] & mask) != 0) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mask = ~lomask(offs);
|
||||||
|
if ((b[0] & mask) != 0) return 1;
|
||||||
|
|
||||||
|
for(i=1; i < nw-1; i++) {
|
||||||
|
if (b[i] != 0) return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tail = (offs+nbits)&31;
|
||||||
|
if (tail==0) {
|
||||||
|
if (b[i] != 0) return 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mask = lomask(tail);
|
||||||
|
if ((b[i] & mask) != 0) return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void adjust_offset_to(u_int32_t *dest, u_int32_t *src, u_int32_t nw,
|
||||||
|
u_int32_t soffs, u_int32_t newoffs)
|
||||||
|
{
|
||||||
|
if (newoffs > soffs)
|
||||||
|
bitvector_shl_to(dest, src, nw, newoffs-soffs, true);
|
||||||
|
else
|
||||||
|
bitvector_shr_to(dest, src, nw, soffs-newoffs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BITVECTOR_BINARY_OP_TO(opname, OP) \
|
||||||
|
void bitvector_##opname##_to(u_int32_t *dest, u_int32_t doffs, \
|
||||||
|
u_int32_t *a, u_int32_t aoffs, \
|
||||||
|
u_int32_t *b, u_int32_t boffs, u_int32_t nbits) \
|
||||||
|
{ \
|
||||||
|
u_int32_t nw = (doffs+nbits+31)>>5; \
|
||||||
|
u_int32_t *temp = nw>MALLOC_CUTOFF ? malloc((nw+1)*4) : alloca((nw+1)*4);\
|
||||||
|
u_int32_t i, anw, bnw; \
|
||||||
|
if (aoffs == boffs) { \
|
||||||
|
anw = (aoffs+nbits+31)>>5; \
|
||||||
|
} \
|
||||||
|
else if (aoffs == doffs) { \
|
||||||
|
bnw = (boffs+nbits+31)>>5; \
|
||||||
|
adjust_offset_to(temp, b, bnw, boffs, aoffs); \
|
||||||
|
b = temp; anw = nw; \
|
||||||
|
} \
|
||||||
|
else { \
|
||||||
|
anw = (aoffs+nbits+31)>>5; \
|
||||||
|
bnw = (boffs+nbits+31)>>5; \
|
||||||
|
adjust_offset_to(temp, a, anw, aoffs, boffs); \
|
||||||
|
a = temp; aoffs = boffs; anw = bnw; \
|
||||||
|
} \
|
||||||
|
for(i=0; i < anw; i++) temp[i] = OP(a[i], b[i]); \
|
||||||
|
bitvector_copy(dest, doffs, temp, aoffs, nbits); \
|
||||||
|
if (nw>MALLOC_CUTOFF) free(temp); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BV_AND(a,b) ((a)&(b))
|
||||||
|
#define BV_OR(a,b) ((a)|(b))
|
||||||
|
#define BV_XOR(a,b) ((a)^(b))
|
||||||
|
BITVECTOR_BINARY_OP_TO(and, BV_AND)
|
||||||
|
BITVECTOR_BINARY_OP_TO(or, BV_OR)
|
||||||
|
BITVECTOR_BINARY_OP_TO(xor, BV_XOR)
|
|
@ -0,0 +1,66 @@
|
||||||
|
#ifndef __BITVECTOR_H_
|
||||||
|
#define __BITVECTOR_H_
|
||||||
|
|
||||||
|
// a mask with n set lo or hi bits
|
||||||
|
#define lomask(n) (u_int32_t)((((u_int32_t)1)<<(n))-1)
|
||||||
|
#define himask(n) (~lomask(32-n))
|
||||||
|
#define ONES32 ((u_int32_t)0xffffffff)
|
||||||
|
|
||||||
|
#ifdef __INTEL_COMPILER
|
||||||
|
#define count_bits(b) _popcnt32(b)
|
||||||
|
#else
|
||||||
|
static inline u_int32_t count_bits(u_int32_t b)
|
||||||
|
{
|
||||||
|
b = b - ((b>>1)&0x55555555);
|
||||||
|
b = ((b>>2)&0x33333333) + (b&0x33333333);
|
||||||
|
b = ((b>>4)+b)&0x0f0f0f0f;
|
||||||
|
b += (b>>8);
|
||||||
|
b += (b>>16);
|
||||||
|
return b & 0x3f;
|
||||||
|
// here is the non-optimized version, for clarity:
|
||||||
|
/*
|
||||||
|
b = ((b>> 1)&0x55555555) + (b&0x55555555);
|
||||||
|
b = ((b>> 2)&0x33333333) + (b&0x33333333);
|
||||||
|
b = ((b>> 4)&0x0f0f0f0f) + (b&0x0f0f0f0f);
|
||||||
|
b = ((b>> 8)&0x00ff00ff) + (b&0x00ff00ff);
|
||||||
|
b = ((b>>16)&0x0000ffff) + (b&0x0000ffff);
|
||||||
|
return b & 0x3f;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
u_int32_t bitreverse(u_int32_t x);
|
||||||
|
|
||||||
|
u_int32_t *bitvector_new(size_t n, int initzero);
|
||||||
|
u_int32_t *bitvector_resize(u_int32_t *b, size_t n, int initzero);
|
||||||
|
void bitvector_set(u_int32_t *b, u_int32_t n, u_int32_t c);
|
||||||
|
u_int32_t bitvector_get(u_int32_t *b, u_int32_t n);
|
||||||
|
|
||||||
|
void bitvector_shr(u_int32_t *b, size_t n, u_int32_t s);
|
||||||
|
void bitvector_shr_to(u_int32_t *dest, u_int32_t *b, size_t n, u_int32_t s);
|
||||||
|
void bitvector_shl(u_int32_t *b, size_t n, u_int32_t s);
|
||||||
|
void bitvector_shl_to(u_int32_t *dest, u_int32_t *b, size_t n, u_int32_t s,
|
||||||
|
bool_t scrap);
|
||||||
|
void bitvector_fill(u_int32_t *b,u_int32_t offs, u_int32_t c, u_int32_t nbits);
|
||||||
|
void bitvector_copy(u_int32_t *dest, u_int32_t doffs,
|
||||||
|
u_int32_t *a, u_int32_t aoffs, u_int32_t nbits);
|
||||||
|
void bitvector_not(u_int32_t *b, u_int32_t offs, u_int32_t nbits);
|
||||||
|
void bitvector_not_to(u_int32_t *dest, u_int32_t doffs,
|
||||||
|
u_int32_t *a, u_int32_t aoffs, u_int32_t nbits);
|
||||||
|
void bitvector_reverse(u_int32_t *b, u_int32_t offs, u_int32_t nbits);
|
||||||
|
void bitvector_reverse_to(u_int32_t *dest, u_int32_t *src, u_int32_t soffs,
|
||||||
|
u_int32_t nbits);
|
||||||
|
void bitvector_and_to(u_int32_t *dest, u_int32_t doffs,
|
||||||
|
u_int32_t *a, u_int32_t aoffs,
|
||||||
|
u_int32_t *b, u_int32_t boffs, u_int32_t nbits);
|
||||||
|
void bitvector_or_to(u_int32_t *dest, u_int32_t doffs,
|
||||||
|
u_int32_t *a, u_int32_t aoffs,
|
||||||
|
u_int32_t *b, u_int32_t boffs, u_int32_t nbits);
|
||||||
|
void bitvector_xor_to(u_int32_t *dest, u_int32_t doffs,
|
||||||
|
u_int32_t *a, u_int32_t aoffs,
|
||||||
|
u_int32_t *b, u_int32_t boffs, u_int32_t nbits);
|
||||||
|
u_int32_t bitvector_count(u_int32_t *b, u_int32_t offs, u_int32_t nbits);
|
||||||
|
u_int32_t bitvector_any0(u_int32_t *b, u_int32_t offs, u_int32_t nbits);
|
||||||
|
u_int32_t bitvector_any1(u_int32_t *b, u_int32_t offs, u_int32_t nbits);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef __CONFIG_H_
|
||||||
|
#define __CONFIG_H_
|
||||||
|
|
||||||
|
#define LINUX
|
||||||
|
#undef WIN32
|
||||||
|
|
||||||
|
#undef BITS64
|
||||||
|
|
||||||
|
#define ARCH_X86
|
||||||
|
#undef ARCH_X86_64
|
||||||
|
|
||||||
|
#define __CPU__ 586
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,67 @@
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "ieee754.h"
|
||||||
|
#include "dtypes.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
void snprint_cplx(char *s, size_t cnt, double re, double im,
|
||||||
|
// args to pass on to snprint_real
|
||||||
|
int width, int dec,
|
||||||
|
int max_digs_rt, int max_digs_lf,
|
||||||
|
// print spaces around sign in a+bi
|
||||||
|
int spflag)
|
||||||
|
{
|
||||||
|
int fzr = (re==0) || rel_zero(re,im);
|
||||||
|
int fzi = (im==0) || rel_zero(im,re);
|
||||||
|
size_t len, sl;
|
||||||
|
size_t space = cnt;
|
||||||
|
|
||||||
|
s[0] = '\0';
|
||||||
|
if (isnan(im) && fzr) {
|
||||||
|
if (space < 2) return;
|
||||||
|
snprint_real(s, space-2, im, width, dec, max_digs_rt, max_digs_lf);
|
||||||
|
strcat(s, "i");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!fzr || (fzr && fzi)) {
|
||||||
|
if (space < 4) return;
|
||||||
|
snprint_real(s, space-4, re, width, dec, max_digs_rt, max_digs_lf);
|
||||||
|
if ((im >= 0 || (isnan(im)&&!sign_bit(im))) && !fzi) {
|
||||||
|
if (spflag) {
|
||||||
|
strcat(s, " + ");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
strcat(s, "+");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!fzi) {
|
||||||
|
im = -im;
|
||||||
|
if (spflag)
|
||||||
|
strcat(s, " - ");
|
||||||
|
else
|
||||||
|
strcat(s, "-");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!fzi) {
|
||||||
|
len = sl = strlen(s);
|
||||||
|
if (dbl_equals(im, -1)) {
|
||||||
|
while (len-sl < (size_t)width-2 && len < (space-3))
|
||||||
|
s[len++] = ' ';
|
||||||
|
s[len] = '-';
|
||||||
|
s[len+1] = 'i';
|
||||||
|
s[len+2] = '\0';
|
||||||
|
}
|
||||||
|
else if (dbl_equals(im, 1)) {
|
||||||
|
while (len-sl < (size_t)width-1 && len < (space-2))
|
||||||
|
s[len++] = ' ';
|
||||||
|
s[len] = 'i';
|
||||||
|
s[len+1] = '\0';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
snprint_real(s+len, space-len-2, im, width, dec,
|
||||||
|
max_digs_rt, max_digs_lf);
|
||||||
|
strcat(s, "i");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,202 @@
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "ieee754.h"
|
||||||
|
#include "dtypes.h"
|
||||||
|
|
||||||
|
static uint64_t max_ulps;
|
||||||
|
static uint32_t flt_max_ulps;
|
||||||
|
|
||||||
|
static uint64_t nexti64pow2(uint64_t i)
|
||||||
|
{
|
||||||
|
if (i==0) return 1;
|
||||||
|
if ((i&(i-1))==0) return i;
|
||||||
|
if (i&BIT63) return BIT63;
|
||||||
|
// repeatedly clear bottom bit
|
||||||
|
while (i&(i-1))
|
||||||
|
i = i&(i-1);
|
||||||
|
return i<<1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t nexti32pow2(uint32_t i)
|
||||||
|
{
|
||||||
|
if (i==0) return 1;
|
||||||
|
if ((i&(i-1))==0) return i;
|
||||||
|
if (i&BIT31) return BIT31;
|
||||||
|
// repeatedly clear bottom bit
|
||||||
|
while (i&(i-1))
|
||||||
|
i = i&(i-1);
|
||||||
|
return i<<1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dbl_tolerance(double tol)
|
||||||
|
{
|
||||||
|
max_ulps = nexti64pow2((uint64_t)(tol/DBL_EPSILON));
|
||||||
|
}
|
||||||
|
|
||||||
|
void flt_tolerance(float tol)
|
||||||
|
{
|
||||||
|
flt_max_ulps = nexti32pow2((uint32_t)(tol/FLT_EPSILON));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __INTEL_COMPILER
|
||||||
|
static inline int64_t llabs(int64_t j)
|
||||||
|
{
|
||||||
|
return NBABS(j, 64);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
extern int64_t llabs(int64_t j);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int dbl_equals(double a, double b)
|
||||||
|
{
|
||||||
|
int64_t aint, bint;
|
||||||
|
|
||||||
|
if (a == b)
|
||||||
|
return 1;
|
||||||
|
aint = *(int64_t*)&a;
|
||||||
|
bint = *(int64_t*)&b;
|
||||||
|
if (aint < 0)
|
||||||
|
aint = BIT63 - aint;
|
||||||
|
if (bint < 0)
|
||||||
|
bint = BIT63 - bint;
|
||||||
|
/* you'd think it makes no difference whether the result of llabs is
|
||||||
|
signed or unsigned, but if it's signed then the case of
|
||||||
|
0x8000000000000000 blows up, making 4 == -1 :) */
|
||||||
|
if ((uint64_t)llabs(aint-bint) <= max_ulps)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int flt_equals(float a, float b)
|
||||||
|
{
|
||||||
|
int32_t aint, bint;
|
||||||
|
|
||||||
|
if (a == b)
|
||||||
|
return 1;
|
||||||
|
aint = *(int32_t*)&a;
|
||||||
|
bint = *(int32_t*)&b;
|
||||||
|
if (aint < 0)
|
||||||
|
aint = BIT31 - aint;
|
||||||
|
if (bint < 0)
|
||||||
|
bint = BIT31 - bint;
|
||||||
|
if ((uint32_t)abs(aint-bint) <= flt_max_ulps)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int double_exponent(double d)
|
||||||
|
{
|
||||||
|
union ieee754_double dl;
|
||||||
|
|
||||||
|
dl.d = d;
|
||||||
|
return dl.ieee.exponent - IEEE754_DOUBLE_BIAS;
|
||||||
|
}
|
||||||
|
|
||||||
|
double double_mantissa(double d)
|
||||||
|
{
|
||||||
|
union ieee754_double dl;
|
||||||
|
|
||||||
|
dl.d = d;
|
||||||
|
dl.ieee.exponent = IEEE754_DOUBLE_BIAS;
|
||||||
|
dl.ieee.negative = 0;
|
||||||
|
return dl.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
int float_exponent(float f)
|
||||||
|
{
|
||||||
|
union ieee754_float fl;
|
||||||
|
|
||||||
|
fl.f = f;
|
||||||
|
return fl.ieee.exponent - IEEE754_FLOAT_BIAS;
|
||||||
|
}
|
||||||
|
|
||||||
|
float float_mantissa(float f)
|
||||||
|
{
|
||||||
|
union ieee754_float fl;
|
||||||
|
|
||||||
|
fl.f = f;
|
||||||
|
fl.ieee.exponent = IEEE754_FLOAT_BIAS;
|
||||||
|
fl.ieee.negative = 0;
|
||||||
|
return fl.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void snprint_real(char *s, size_t cnt, double r,
|
||||||
|
int width, // printf field width, or 0
|
||||||
|
int dec, // # decimal digits desired, recommend 16
|
||||||
|
// # of zeros in .00...0x before using scientific notation
|
||||||
|
// recommend 3-4 or so
|
||||||
|
int max_digs_rt,
|
||||||
|
// # of digits left of decimal before scientific notation
|
||||||
|
// recommend 10
|
||||||
|
int max_digs_lf)
|
||||||
|
{
|
||||||
|
int mag;
|
||||||
|
double fpart, temp;
|
||||||
|
char format[8];
|
||||||
|
char num_format[3];
|
||||||
|
int sz, keepz=0;
|
||||||
|
|
||||||
|
s[0] = '\0';
|
||||||
|
if (width == -1) {
|
||||||
|
width = 0;
|
||||||
|
keepz=1;
|
||||||
|
}
|
||||||
|
if (isnan(r)) {
|
||||||
|
if (sign_bit(r))
|
||||||
|
strncpy(s, "-nan", cnt);
|
||||||
|
else
|
||||||
|
strncpy(s, "nan", cnt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (r == 0) {
|
||||||
|
strncpy(s, "0", cnt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
num_format[0] = 'l';
|
||||||
|
num_format[2] = '\0';
|
||||||
|
|
||||||
|
mag = double_exponent(r);
|
||||||
|
|
||||||
|
mag = (int)(((double)mag)/LOG2_10 + 0.5);
|
||||||
|
if (r == 0)
|
||||||
|
mag = 0;
|
||||||
|
if ((mag > max_digs_lf-1) || (mag < -max_digs_rt)) {
|
||||||
|
num_format[1] = 'e';
|
||||||
|
temp = r/pow(10, mag); /* see if number will have a decimal */
|
||||||
|
fpart = temp - floor(temp); /* when written in scientific notation */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
num_format[1] = 'f';
|
||||||
|
fpart = r - floor(r);
|
||||||
|
}
|
||||||
|
if (fpart == 0)
|
||||||
|
dec = 0;
|
||||||
|
if (width == 0) {
|
||||||
|
snprintf(format, 8, "%%.%d%s", dec, num_format);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
snprintf(format, 8, "%%%d.%d%s", width, dec, num_format);
|
||||||
|
}
|
||||||
|
sz = snprintf(s, cnt, format, r);
|
||||||
|
/* trim trailing zeros from fractions. not when using scientific
|
||||||
|
notation, since we might have e.g. 1.2000e+100. also not when we
|
||||||
|
need a specific output width */
|
||||||
|
if (width == 0 && !keepz) {
|
||||||
|
if (sz > 2 && fpart && num_format[1]!='e') {
|
||||||
|
while (s[sz-1] == '0') {
|
||||||
|
s[sz-1]='\0';
|
||||||
|
sz--;
|
||||||
|
}
|
||||||
|
// don't need trailing .
|
||||||
|
if (s[sz-1] == '.') {
|
||||||
|
s[sz-1] = '\0';
|
||||||
|
sz--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO. currently 1.1e20 prints as 1.1000000000000000e+20; be able to
|
||||||
|
// get rid of all those zeros.
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <sys/timeb.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#undef NO_ERROR
|
||||||
|
#undef MOD_SHIFT
|
||||||
|
#undef TRUE
|
||||||
|
#undef FALSE
|
||||||
|
#undef VOID
|
||||||
|
#else
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "dtypes.h"
|
||||||
|
|
||||||
|
void get_cwd(char *buf, size_t size)
|
||||||
|
{
|
||||||
|
#ifndef WIN32
|
||||||
|
getcwd(buf, size);
|
||||||
|
#else
|
||||||
|
GetCurrentDirectory(size, buf);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int set_cwd(char *buf)
|
||||||
|
{
|
||||||
|
#ifndef WIN32
|
||||||
|
if (chdir(buf) == -1)
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
|
if (SetCurrentDirectory(buf) == 0)
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LINUX
|
||||||
|
char *get_exename(char *buf, size_t size)
|
||||||
|
{
|
||||||
|
char linkname[64]; /* /proc/<pid>/exe */
|
||||||
|
pid_t pid;
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
/* Get our PID and build the name of the link in /proc */
|
||||||
|
pid = getpid();
|
||||||
|
|
||||||
|
if (snprintf(linkname, sizeof(linkname), "/proc/%i/exe", pid) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Now read the symbolic link */
|
||||||
|
ret = readlink(linkname, buf, size);
|
||||||
|
|
||||||
|
/* In case of an error, leave the handling up to the caller */
|
||||||
|
if (ret == -1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Report insufficient buffer size */
|
||||||
|
if ((size_t)ret >= size)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Ensure proper NUL termination */
|
||||||
|
buf[ret] = 0;
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
#elif defined(WIN32)
|
||||||
|
char *get_exename(char *buf, size_t size)
|
||||||
|
{
|
||||||
|
if (GetModuleFileName(NULL, buf, size) == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
#elif defined(MACOSX) || defined(MACINTEL)
|
||||||
|
#include "/Developer/Headers/FlatCarbon/Processes.h"
|
||||||
|
#include "/Developer/Headers/FlatCarbon/Files.h"
|
||||||
|
char *get_exename(char *buf, size_t size)
|
||||||
|
{
|
||||||
|
ProcessSerialNumber PSN;
|
||||||
|
FSRef ref;
|
||||||
|
|
||||||
|
if (GetCurrentProcess(&PSN) < 0 ||
|
||||||
|
GetProcessBundleLocation(&PSN, &ref) < 0 ||
|
||||||
|
FSRefMakePath(&ref, buf, size) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,23 @@
|
||||||
|
#ifndef __DIRPATH_H_
|
||||||
|
#define __DIRPATH_H_
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#define PATHSEP '\\'
|
||||||
|
#define PATHSEPSTRING "\\"
|
||||||
|
#define PATHLISTSEP ';'
|
||||||
|
#define PATHLISTSEPSTRING ";"
|
||||||
|
#define ISPATHSEP(c) ((c)=='/' || (c)=='\\')
|
||||||
|
#define MAXPATHLEN 1024
|
||||||
|
#else
|
||||||
|
#define PATHSEP '/'
|
||||||
|
#define PATHSEPSTRING "/"
|
||||||
|
#define PATHLISTSEP ':'
|
||||||
|
#define PATHLISTSEPSTRING ":"
|
||||||
|
#define ISPATHSEP(c) ((c)=='/')
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void get_cwd(char *buf, size_t size);
|
||||||
|
int set_cwd(char *buf);
|
||||||
|
char *get_exename(char *buf, size_t size);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,124 @@
|
||||||
|
#ifndef __DTYPES_H_
|
||||||
|
#define __DTYPES_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file defines sane integer types for our target platforms. This
|
||||||
|
library only runs on machines with the following characteristics:
|
||||||
|
|
||||||
|
- supports integer word sizes of 8, 16, 32, and 64 bits
|
||||||
|
- uses unsigned and signed 2's complement representations
|
||||||
|
- all pointer types are the same size
|
||||||
|
- there is an integer type with the same size as a pointer
|
||||||
|
|
||||||
|
Some features require:
|
||||||
|
- IEEE 754 single- and double-precision floating point
|
||||||
|
|
||||||
|
We assume the LP64 convention for 64-bit platforms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
typedef int bool_t;
|
||||||
|
/* unfortunately we can't make this an enum, since false is an invalid
|
||||||
|
enum label in C++ (since it's a keyword) */
|
||||||
|
#define false (0)
|
||||||
|
#define true (1)
|
||||||
|
|
||||||
|
#if defined(__INTEL_COMPILER) && defined(WIN32)
|
||||||
|
# define STATIC_INLINE static
|
||||||
|
# define INLINE
|
||||||
|
# ifdef BITS64
|
||||||
|
typedef unsigned long size_t;
|
||||||
|
# else
|
||||||
|
typedef unsigned int size_t;
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define STATIC_INLINE static inline
|
||||||
|
# define INLINE inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef unsigned char byte_t; /* 1 byte */
|
||||||
|
#if defined(WIN32)
|
||||||
|
typedef short int16_t;
|
||||||
|
typedef int int32_t;
|
||||||
|
typedef long long int64_t;
|
||||||
|
typedef unsigned char u_int8_t;
|
||||||
|
typedef unsigned short u_int16_t;
|
||||||
|
typedef unsigned int u_int32_t;
|
||||||
|
#ifdef BITS64
|
||||||
|
typedef unsigned long u_int64_t;
|
||||||
|
#else
|
||||||
|
typedef unsigned long long u_int64_t;
|
||||||
|
#endif
|
||||||
|
#ifdef __INTEL_COMPILER
|
||||||
|
typedef signed char int8_t;
|
||||||
|
typedef short int16_t;
|
||||||
|
typedef int int32_t;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#include <sys/types.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BITS64
|
||||||
|
#define TOP_BIT 0x8000000000000000
|
||||||
|
#define NBITS 64
|
||||||
|
typedef unsigned long uint_t; // preferred int type on platform
|
||||||
|
typedef long int_t;
|
||||||
|
typedef int64_t offset_t;
|
||||||
|
typedef u_int64_t index_t;
|
||||||
|
typedef int64_t ptrint_t; // pointer-size int
|
||||||
|
typedef u_int64_t u_ptrint_t
|
||||||
|
#else
|
||||||
|
#define TOP_BIT 0x80000000
|
||||||
|
#define NBITS 32
|
||||||
|
typedef unsigned long uint_t;
|
||||||
|
typedef long int_t;
|
||||||
|
typedef int32_t offset_t;
|
||||||
|
typedef u_int32_t index_t;
|
||||||
|
typedef int32_t ptrint_t;
|
||||||
|
typedef u_int32_t u_ptrint_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef u_int8_t uint8_t;
|
||||||
|
typedef u_int16_t uint16_t;
|
||||||
|
typedef u_int32_t uint32_t;
|
||||||
|
typedef u_int64_t uint64_t;
|
||||||
|
typedef u_ptrint_t uptrint_t;
|
||||||
|
|
||||||
|
#define ALIGN(x, sz) (((x) + (sz-1)) & (-sz))
|
||||||
|
|
||||||
|
#define DBL_MAXINT 9007199254740992LL
|
||||||
|
#define FLT_MAXINT 16777216
|
||||||
|
#define U64_MAX 18446744073709551615ULL
|
||||||
|
#define S64_MAX 9223372036854775807LL
|
||||||
|
#define S64_MIN (-S64_MAX - 1LL)
|
||||||
|
#define BIT63 0x8000000000000000LL
|
||||||
|
#define BIT31 0x80000000
|
||||||
|
|
||||||
|
#define DBL_EPSILON 2.2204460492503131e-16
|
||||||
|
#define FLT_EPSILON 1.1920928e-7
|
||||||
|
#define DBL_MAX 1.7976931348623157e+308
|
||||||
|
#define DBL_MIN 2.2250738585072014e-308
|
||||||
|
#define FLT_MAX 3.402823466e+38
|
||||||
|
#define FLT_MIN 1.175494351e-38
|
||||||
|
#define LOG2_10 3.3219280948873626
|
||||||
|
#define rel_zero(a, b) (fabs((a)/(b)) < DBL_EPSILON)
|
||||||
|
#define sign_bit(r) ((*(int64_t*)&(r)) & BIT63)
|
||||||
|
#define LABS(n) (((n)^((n)>>(NBITS-1))) - ((n)>>(NBITS-1)))
|
||||||
|
#define NBABS(n,nb) (((n)^((n)>>((nb)-1))) - ((n)>>((nb)-1)))
|
||||||
|
#define DFINITE(d) (((*(int64_t*)&(d))&0x7ff0000000000000LL)!=0x7ff0000000000000LL)
|
||||||
|
|
||||||
|
typedef enum { T_INT8, T_UINT8, T_INT16, T_UINT16, T_INT32, T_UINT32,
|
||||||
|
T_INT64, T_UINT64, T_FLOAT, T_DOUBLE } numerictype_t;
|
||||||
|
|
||||||
|
#define N_NUMTYPES ((int)T_DOUBLE+1)
|
||||||
|
|
||||||
|
#ifdef BITS64
|
||||||
|
# define T_LONG T_INT64
|
||||||
|
# define T_ULONG T_UINT64
|
||||||
|
#else
|
||||||
|
# define T_LONG T_INT32
|
||||||
|
# define T_ULONG T_UINT32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
Hashing and random numbers
|
||||||
|
*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "ieee754.h"
|
||||||
|
#include "dtypes.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "hashing.h"
|
||||||
|
#include "timefuncs.h"
|
||||||
|
|
||||||
|
uint_t nextipow2(uint_t i)
|
||||||
|
{
|
||||||
|
if (i==0) return 1;
|
||||||
|
if ((i&(i-1))==0) return i;
|
||||||
|
if (i&TOP_BIT) return TOP_BIT;
|
||||||
|
|
||||||
|
// repeatedly clear bottom bit
|
||||||
|
while (i&(i-1))
|
||||||
|
i = i&(i-1);
|
||||||
|
|
||||||
|
return i<<1;
|
||||||
|
}
|
||||||
|
|
||||||
|
u_int32_t int32hash(u_int32_t a)
|
||||||
|
{
|
||||||
|
a = (a+0x7ed55d16) + (a<<12);
|
||||||
|
a = (a^0xc761c23c) ^ (a>>19);
|
||||||
|
a = (a+0x165667b1) + (a<<5);
|
||||||
|
a = (a+0xd3a2646c) ^ (a<<9);
|
||||||
|
a = (a+0xfd7046c5) + (a<<3);
|
||||||
|
a = (a^0xb55a4f09) ^ (a>>16);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
u_int64_t int64hash(u_int64_t key)
|
||||||
|
{
|
||||||
|
key = (~key) + (key << 21); // key = (key << 21) - key - 1;
|
||||||
|
key = key ^ (key >> 24);
|
||||||
|
key = (key + (key << 3)) + (key << 8); // key * 265
|
||||||
|
key = key ^ (key >> 14);
|
||||||
|
key = (key + (key << 2)) + (key << 4); // key * 21
|
||||||
|
key = key ^ (key >> 28);
|
||||||
|
key = key + (key << 31);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
u_int32_t int64to32hash(u_int64_t key)
|
||||||
|
{
|
||||||
|
key = (~key) + (key << 18); // key = (key << 18) - key - 1;
|
||||||
|
key = key ^ (key >> 31);
|
||||||
|
key = key * 21; // key = (key + (key << 2)) + (key << 4);
|
||||||
|
key = key ^ (key >> 11);
|
||||||
|
key = key + (key << 6);
|
||||||
|
key = key ^ (key >> 22);
|
||||||
|
return (u_int32_t)key;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "lookup3.c"
|
||||||
|
|
||||||
|
u_int64_t memhash(char* buf, size_t n)
|
||||||
|
{
|
||||||
|
u_int32_t c=0xcafe8881, b=0x4d6a087c;
|
||||||
|
|
||||||
|
hashlittle2(buf, n, &c, &b);
|
||||||
|
return (u_int64_t)c | (((u_int64_t)b)<<32);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "mt19937ar.c"
|
||||||
|
|
||||||
|
double rand_double()
|
||||||
|
{
|
||||||
|
union ieee754_double d;
|
||||||
|
|
||||||
|
d.ieee.mantissa0 = random();
|
||||||
|
d.ieee.mantissa1 = random();
|
||||||
|
d.ieee.negative = 0;
|
||||||
|
d.ieee.exponent = IEEE754_DOUBLE_BIAS + 0; /* 2^0 */
|
||||||
|
return d.d - 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float rand_float()
|
||||||
|
{
|
||||||
|
union ieee754_float f;
|
||||||
|
|
||||||
|
f.ieee.mantissa = random();
|
||||||
|
f.ieee.negative = 0;
|
||||||
|
f.ieee.exponent = IEEE754_FLOAT_BIAS + 0; /* 2^0 */
|
||||||
|
return f.f - 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void randn(double *pre, double *pim)
|
||||||
|
{
|
||||||
|
double s, vre, vim, ure, uim;
|
||||||
|
|
||||||
|
do {
|
||||||
|
ure = rand_double();
|
||||||
|
uim = rand_double();
|
||||||
|
vre = 2*ure - 1;
|
||||||
|
vim = 2*uim - 1;
|
||||||
|
s = vre*vre + vim*vim;
|
||||||
|
} while (s >= 1);
|
||||||
|
s = sqrt(-2*log(s)/s);
|
||||||
|
*pre = s * vre;
|
||||||
|
*pim = s * vim;
|
||||||
|
}
|
||||||
|
|
||||||
|
void randomize()
|
||||||
|
{
|
||||||
|
u_int64_t tm = i64time();
|
||||||
|
init_by_array((unsigned long*)&tm, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void llt_init()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
I used this function to guess good values based on epsilon:
|
||||||
|
tol(eps) = exp(ln(eps)*-.2334012088721472)*eps
|
||||||
|
*/
|
||||||
|
dbl_tolerance(1e-12);
|
||||||
|
flt_tolerance(5e-6);
|
||||||
|
|
||||||
|
randomize();
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef __HASHING_H_
|
||||||
|
#define __HASHING_H_
|
||||||
|
|
||||||
|
uint_t nextipow2(uint_t i);
|
||||||
|
u_int32_t int32hash(u_int32_t a);
|
||||||
|
u_int64_t int64hash(u_int64_t key);
|
||||||
|
u_int32_t int64to32hash(u_int64_t key);
|
||||||
|
#ifdef BITS64
|
||||||
|
#define inthash int64hash
|
||||||
|
#else
|
||||||
|
#define inthash int32hash
|
||||||
|
#endif
|
||||||
|
u_int64_t memhash(char* buf, size_t n);
|
||||||
|
#define random() genrand_int32()
|
||||||
|
#define srandom(n) init_genrand(n)
|
||||||
|
double rand_double();
|
||||||
|
float rand_float();
|
||||||
|
void randn(double *pre, double *pim);
|
||||||
|
u_int64_t i64time();
|
||||||
|
void randomize();
|
||||||
|
unsigned long genrand_int32();
|
||||||
|
void init_genrand(unsigned long s);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,222 @@
|
||||||
|
/* Copyright (C) 1992, 1995, 1996, 1999 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, write to the Free
|
||||||
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
|
02111-1307 USA. */
|
||||||
|
|
||||||
|
#ifndef _IEEE754_H
|
||||||
|
|
||||||
|
#define _IEEE754_H 1
|
||||||
|
#ifdef LINUX
|
||||||
|
#include <features.h>
|
||||||
|
|
||||||
|
#include <endian.h>
|
||||||
|
|
||||||
|
__BEGIN_DECLS
|
||||||
|
#else
|
||||||
|
#define __LITTLE_ENDIAN 1234
|
||||||
|
#define __BIG_ENDIAN 4321
|
||||||
|
#define __PDP_ENDIAN 3412
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MACOSX
|
||||||
|
#define __BYTE_ORDER __BIG_ENDIAN
|
||||||
|
#define __FLOAT_WORD_ORDER __BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MACINTEL
|
||||||
|
#define __BYTE_ORDER __LITTLE_ENDIAN
|
||||||
|
#define __FLOAT_WORD_ORDER __LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#define __BYTE_ORDER __LITTLE_ENDIAN
|
||||||
|
#define __FLOAT_WORD_ORDER __LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
union ieee754_float
|
||||||
|
{
|
||||||
|
float f;
|
||||||
|
|
||||||
|
/* This is the IEEE 754 single-precision format. */
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||||
|
unsigned int negative:1;
|
||||||
|
unsigned int exponent:8;
|
||||||
|
unsigned int mantissa:23;
|
||||||
|
#endif /* Big endian. */
|
||||||
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
unsigned int mantissa:23;
|
||||||
|
unsigned int exponent:8;
|
||||||
|
unsigned int negative:1;
|
||||||
|
#endif /* Little endian. */
|
||||||
|
} ieee;
|
||||||
|
|
||||||
|
/* This format makes it easier to see if a NaN is a signalling NaN. */
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||||
|
unsigned int negative:1;
|
||||||
|
unsigned int exponent:8;
|
||||||
|
unsigned int quiet_nan:1;
|
||||||
|
unsigned int mantissa:22;
|
||||||
|
#endif /* Big endian. */
|
||||||
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
unsigned int mantissa:22;
|
||||||
|
unsigned int quiet_nan:1;
|
||||||
|
unsigned int exponent:8;
|
||||||
|
unsigned int negative:1;
|
||||||
|
#endif /* Little endian. */
|
||||||
|
} ieee_nan;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define IEEE754_FLOAT_BIAS 0x7f /* Added to exponent. */
|
||||||
|
|
||||||
|
|
||||||
|
union ieee754_double
|
||||||
|
{
|
||||||
|
double d;
|
||||||
|
|
||||||
|
/* This is the IEEE 754 double-precision format. */
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||||
|
unsigned int negative:1;
|
||||||
|
unsigned int exponent:11;
|
||||||
|
/* Together these comprise the mantissa. */
|
||||||
|
unsigned int mantissa0:20;
|
||||||
|
unsigned int mantissa1:32;
|
||||||
|
#endif /* Big endian. */
|
||||||
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
# if __FLOAT_WORD_ORDER == BIG_ENDIAN
|
||||||
|
unsigned int mantissa0:20;
|
||||||
|
unsigned int exponent:11;
|
||||||
|
unsigned int negative:1;
|
||||||
|
unsigned int mantissa1:32;
|
||||||
|
# else
|
||||||
|
/* Together these comprise the mantissa. */
|
||||||
|
unsigned int mantissa1:32;
|
||||||
|
unsigned int mantissa0:20;
|
||||||
|
unsigned int exponent:11;
|
||||||
|
unsigned int negative:1;
|
||||||
|
# endif
|
||||||
|
#endif /* Little endian. */
|
||||||
|
} ieee;
|
||||||
|
|
||||||
|
/* This format makes it easier to see if a NaN is a signalling NaN. */
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||||
|
unsigned int negative:1;
|
||||||
|
unsigned int exponent:11;
|
||||||
|
unsigned int quiet_nan:1;
|
||||||
|
/* Together these comprise the mantissa. */
|
||||||
|
unsigned int mantissa0:19;
|
||||||
|
unsigned int mantissa1:32;
|
||||||
|
#else
|
||||||
|
# if __FLOAT_WORD_ORDER == BIG_ENDIAN
|
||||||
|
unsigned int mantissa0:19;
|
||||||
|
unsigned int quiet_nan:1;
|
||||||
|
unsigned int exponent:11;
|
||||||
|
unsigned int negative:1;
|
||||||
|
unsigned int mantissa1:32;
|
||||||
|
# else
|
||||||
|
/* Together these comprise the mantissa. */
|
||||||
|
unsigned int mantissa1:32;
|
||||||
|
unsigned int mantissa0:19;
|
||||||
|
unsigned int quiet_nan:1;
|
||||||
|
unsigned int exponent:11;
|
||||||
|
unsigned int negative:1;
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
} ieee_nan;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define IEEE754_DOUBLE_BIAS 0x3ff /* Added to exponent. */
|
||||||
|
|
||||||
|
|
||||||
|
union ieee854_long_double
|
||||||
|
{
|
||||||
|
long double d;
|
||||||
|
|
||||||
|
/* This is the IEEE 854 double-extended-precision format. */
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||||
|
unsigned int negative:1;
|
||||||
|
unsigned int exponent:15;
|
||||||
|
unsigned int empty:16;
|
||||||
|
unsigned int mantissa0:32;
|
||||||
|
unsigned int mantissa1:32;
|
||||||
|
#endif
|
||||||
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
# if __FLOAT_WORD_ORDER == BIG_ENDIAN
|
||||||
|
unsigned int exponent:15;
|
||||||
|
unsigned int negative:1;
|
||||||
|
unsigned int empty:16;
|
||||||
|
unsigned int mantissa0:32;
|
||||||
|
unsigned int mantissa1:32;
|
||||||
|
# else
|
||||||
|
unsigned int mantissa1:32;
|
||||||
|
unsigned int mantissa0:32;
|
||||||
|
unsigned int exponent:15;
|
||||||
|
unsigned int negative:1;
|
||||||
|
unsigned int empty:16;
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
} ieee;
|
||||||
|
|
||||||
|
/* This is for NaNs in the IEEE 854 double-extended-precision format. */
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||||
|
unsigned int negative:1;
|
||||||
|
unsigned int exponent:15;
|
||||||
|
unsigned int empty:16;
|
||||||
|
unsigned int one:1;
|
||||||
|
unsigned int quiet_nan:1;
|
||||||
|
unsigned int mantissa0:30;
|
||||||
|
unsigned int mantissa1:32;
|
||||||
|
#endif
|
||||||
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
# if __FLOAT_WORD_ORDER == BIG_ENDIAN
|
||||||
|
unsigned int exponent:15;
|
||||||
|
unsigned int negative:1;
|
||||||
|
unsigned int empty:16;
|
||||||
|
unsigned int mantissa0:30;
|
||||||
|
unsigned int quiet_nan:1;
|
||||||
|
unsigned int one:1;
|
||||||
|
unsigned int mantissa1:32;
|
||||||
|
# else
|
||||||
|
unsigned int mantissa1:32;
|
||||||
|
unsigned int mantissa0:30;
|
||||||
|
unsigned int quiet_nan:1;
|
||||||
|
unsigned int one:1;
|
||||||
|
unsigned int exponent:15;
|
||||||
|
unsigned int negative:1;
|
||||||
|
unsigned int empty:16;
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
} ieee_nan;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define IEEE854_LONG_DOUBLE_BIAS 0x3fff
|
||||||
|
|
||||||
|
#ifdef LINUX
|
||||||
|
__END_DECLS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ieee754.h */
|
|
@ -0,0 +1,479 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <io.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#define fileno _fileno
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "dtypes.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "utf8.h"
|
||||||
|
#include "ios.h"
|
||||||
|
#include "socket.h"
|
||||||
|
#include "timefuncs.h"
|
||||||
|
|
||||||
|
/* OS-level primitive wrappers */
|
||||||
|
|
||||||
|
static int _fd_available(long fd)
|
||||||
|
{
|
||||||
|
#ifndef WIN32
|
||||||
|
fd_set set;
|
||||||
|
struct timeval tv = {0, 0};
|
||||||
|
|
||||||
|
FD_ZERO(&set);
|
||||||
|
FD_SET(fd, &set);
|
||||||
|
return (select(fd+1, &set, NULL, NULL, &tv)!=0);
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// poll for read, unless forwrite!=0
|
||||||
|
static void _fd_poll(long fd, int forwrite)
|
||||||
|
{
|
||||||
|
#ifndef WIN32
|
||||||
|
fd_set set;
|
||||||
|
|
||||||
|
FD_ZERO(&set);
|
||||||
|
FD_SET(fd, &set);
|
||||||
|
if (forwrite)
|
||||||
|
select(fd+1, NULL, &set, NULL, NULL);
|
||||||
|
else
|
||||||
|
select(fd+1, &set, NULL, NULL, NULL);
|
||||||
|
#else
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _enonfatal(int err)
|
||||||
|
{
|
||||||
|
return (err == EAGAIN || err == EINPROGRESS || err == EINTR ||
|
||||||
|
err == EWOULDBLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SLEEP_TIME 5//ms
|
||||||
|
|
||||||
|
// return error code, #bytes read in *nread
|
||||||
|
// these wrappers retry operations until success or a fatal error
|
||||||
|
static int _os_read(long fd, void *buf, size_t n, size_t *nread)
|
||||||
|
{
|
||||||
|
ssize_t r;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
r = read((int)fd, buf, n);
|
||||||
|
if (r > -1) {
|
||||||
|
*nread = (size_t)r;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!_enonfatal(errno)) {
|
||||||
|
*nread = 0;
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
sleep_ms(SLEEP_TIME);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _os_read_all(long fd, void *buf, size_t n, size_t *nread)
|
||||||
|
{
|
||||||
|
size_t got;
|
||||||
|
|
||||||
|
*nread = 0;
|
||||||
|
|
||||||
|
while (n>0) {
|
||||||
|
int err = _os_read(fd, buf, n, &got);
|
||||||
|
n -= got;
|
||||||
|
*nread += got;
|
||||||
|
buf += got;
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
if (got == 0)
|
||||||
|
_fd_poll(fd, 0);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _os_write(long fd, void *buf, size_t n, size_t *nwritten)
|
||||||
|
{
|
||||||
|
ssize_t r;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
r = write((int)fd, buf, n);
|
||||||
|
if (r > -1) {
|
||||||
|
*nwritten = (size_t)r;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!_enonfatal(errno)) {
|
||||||
|
*nwritten = 0;
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
sleep_ms(5);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _os_write_all(long fd, void *buf, size_t n, size_t *nwritten)
|
||||||
|
{
|
||||||
|
size_t wrote;
|
||||||
|
|
||||||
|
*nwritten = 0;
|
||||||
|
|
||||||
|
while (n>0) {
|
||||||
|
int err = _os_write(fd, buf, n, &wrote);
|
||||||
|
n -= wrote;
|
||||||
|
*nwritten += wrote;
|
||||||
|
buf += wrote;
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
if (wrote == 0)
|
||||||
|
_fd_poll(fd, 1);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* internal utility functions */
|
||||||
|
|
||||||
|
static char *_buf_realloc(ios_t *s, size_t sz)
|
||||||
|
{
|
||||||
|
char *temp;
|
||||||
|
|
||||||
|
if (sz <= s->maxsize)
|
||||||
|
return s->buf;
|
||||||
|
|
||||||
|
if ((s->buf==NULL || s->buf==&s->local[0]) && (sz <= IOS_INLSIZE)) {
|
||||||
|
/* TODO: if we want to allow shrinking, see if the buffer shrank
|
||||||
|
down to this size, in which case we need to copy. */
|
||||||
|
s->buf = &s->local[0];
|
||||||
|
s->maxsize = IOS_INLSIZE;
|
||||||
|
s->ownbuf = 1;
|
||||||
|
return s->buf;
|
||||||
|
}
|
||||||
|
else if (s->ownbuf && s->buf != &s->local[0]) {
|
||||||
|
// if we own the buffer we're free to resize it
|
||||||
|
// always allocate 1 bigger in case user wants to add a NUL
|
||||||
|
// terminator after taking over the buffer
|
||||||
|
temp = realloc(s->buf, sz+1);
|
||||||
|
if (temp == NULL)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
temp = malloc(sz+1);
|
||||||
|
if (temp == NULL)
|
||||||
|
return NULL;
|
||||||
|
s->ownbuf = 1;
|
||||||
|
if (s->size > 0)
|
||||||
|
memcpy(temp, s->buf, s->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
s->buf = temp;
|
||||||
|
s->maxsize = sz;
|
||||||
|
return s->buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write a block of data into the buffer at the current position, resizing
|
||||||
|
// if necessary. returns # written.
|
||||||
|
static size_t _writebuf_force(ios_t *s, char *data, size_t n)
|
||||||
|
{
|
||||||
|
size_t amt;
|
||||||
|
size_t newsize;
|
||||||
|
|
||||||
|
if (n == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (s->bpos + n > s->size) {
|
||||||
|
if (s->bpos + n > s->maxsize) {
|
||||||
|
/* TODO: here you might want to add a mechanism for limiting
|
||||||
|
the growth of the stream. */
|
||||||
|
newsize = s->maxsize * 2;
|
||||||
|
while (s->bpos + n > newsize)
|
||||||
|
newsize *= 2;
|
||||||
|
if (_buf_realloc(s, newsize) == NULL) {
|
||||||
|
/* no more space; write as much as we can */
|
||||||
|
amt = s->maxsize - s->bpos;
|
||||||
|
if (amt > 0) {
|
||||||
|
memcpy(&s->buf[s->bpos], data, amt);
|
||||||
|
}
|
||||||
|
s->bpos += amt;
|
||||||
|
s->size = s->maxsize;
|
||||||
|
return amt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s->size = s->bpos + n;
|
||||||
|
}
|
||||||
|
memcpy(&s->buf[s->bpos], data, n);
|
||||||
|
s->bpos += n;
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* interface functions, low level */
|
||||||
|
|
||||||
|
size_t ios_read(ios_t *s, char *dest, size_t n, int all)
|
||||||
|
{
|
||||||
|
size_t tot = 0;
|
||||||
|
size_t got, avail;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
while (n > 0) {
|
||||||
|
avail = s->size - s->bpos;
|
||||||
|
|
||||||
|
if (avail >= n) {
|
||||||
|
memcpy(dest, s->buf + s->bpos, n);
|
||||||
|
s->bpos += n;
|
||||||
|
return tot+n;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (avail > 0) {
|
||||||
|
memcpy(dest, s->buf + s->bpos, avail);
|
||||||
|
}
|
||||||
|
if (s->bm == bm_mem || s->fd == -1) {
|
||||||
|
// can't get any more data
|
||||||
|
s->bpos += avail;
|
||||||
|
return avail;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dest += avail;
|
||||||
|
n -= avail;
|
||||||
|
tot += avail;
|
||||||
|
|
||||||
|
ios_flush(s);
|
||||||
|
s->bpos = s->size = 0;
|
||||||
|
s->state = bst_rd;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n > (s->maxsize - (s->maxsize>>4))) {
|
||||||
|
// doesn't fit comfortably in buffer; go direct
|
||||||
|
if (all)
|
||||||
|
result = _os_read_all(s->fd, dest, n, &got);
|
||||||
|
else
|
||||||
|
result = _os_read(s->fd, dest, n, &got);
|
||||||
|
return tot+got;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// refill buffer
|
||||||
|
if (_os_read(s->fd, s->buf, s->maxsize, &got)) {
|
||||||
|
return tot;
|
||||||
|
}
|
||||||
|
if (got == 0) {
|
||||||
|
if (all)
|
||||||
|
_fd_poll(s->fd, 0);
|
||||||
|
else
|
||||||
|
return tot;
|
||||||
|
}
|
||||||
|
s->size = got;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tot;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ios_write(ios_t *s, char *data, size_t n)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t ios_seek(ios_t *s, off_t pos)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t ios_seek_end(ios_t *s)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t ios_skip(ios_t *s, off_t offs)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t ios_pos(ios_t *s)
|
||||||
|
{
|
||||||
|
if (s->bm == bm_mem)
|
||||||
|
return (off_t)s->bpos;
|
||||||
|
|
||||||
|
off_t fdpos = lseek(s->fd, 0, SEEK_CUR);
|
||||||
|
if (fdpos == (off_t)-1)
|
||||||
|
return fdpos;
|
||||||
|
|
||||||
|
if (s->state == bst_wr)
|
||||||
|
fdpos += s->bpos;
|
||||||
|
else if (s->state == bst_rd)
|
||||||
|
fdpos -= (s->size - s->bpos);
|
||||||
|
return fdpos;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ios_trunc(ios_t *s, size_t size)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int ios_eof(ios_t *s)
|
||||||
|
{
|
||||||
|
if (s->bm == bm_mem)
|
||||||
|
return (s->bpos >= s->size);
|
||||||
|
if (s->fd == -1)
|
||||||
|
return 1;
|
||||||
|
// todo
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _discard_partial_buffer(ios_t *s)
|
||||||
|
{
|
||||||
|
// this function preserves the invariant that data to write
|
||||||
|
// begins at the beginning of the buffer, and s->size refers
|
||||||
|
// to how much valid file data is stored in the buffer.
|
||||||
|
|
||||||
|
// this needs to be called when normal operation is interrupted in
|
||||||
|
// the middle of the buffer. "normal operation" is reading or
|
||||||
|
// writing to the end of the buffer. this happens e.g. when flushing.
|
||||||
|
size_t delta = 0;
|
||||||
|
if (s->ndirty && s->size > s->ndirty) {
|
||||||
|
delta = s->size - s->ndirty;
|
||||||
|
memmove(s->buf, s->buf + s->ndirty, delta);
|
||||||
|
}
|
||||||
|
s->size -= s->ndirty;
|
||||||
|
s->bpos -= s->ndirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ios_flush(ios_t *s)
|
||||||
|
{
|
||||||
|
if (s->ndirty == 0 || s->bm == bm_mem || s->buf == NULL)
|
||||||
|
return 0;
|
||||||
|
if (s->fd == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (s->state == bst_rd) {
|
||||||
|
if (lseek(s->fd, -(off_t)s->size, SEEK_CUR) == (off_t)-1) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t nw, ntowrite=s->ndirty;
|
||||||
|
// todo: this should use sendall
|
||||||
|
int err = _os_write(s->fd, s->buf, ntowrite, &nw);
|
||||||
|
// todo: try recovering from some kinds of errors (e.g. retry)
|
||||||
|
|
||||||
|
if (s->state == bst_rd) {
|
||||||
|
if (lseek(s->fd, s->size - nw, SEEK_CUR) == (off_t)-1) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->ndirty <= s->bpos) {
|
||||||
|
// in this case assume we're done with the first part of the buffer
|
||||||
|
_discard_partial_buffer(s);
|
||||||
|
}
|
||||||
|
s->ndirty = 0;
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
if (nw < ntowrite)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ios_close(ios_t *s)
|
||||||
|
{
|
||||||
|
ios_flush(s);
|
||||||
|
if (s->fd != -1 && s->ownfd)
|
||||||
|
close(s->fd);
|
||||||
|
s->fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *ios_takebuf(ios_t *s, size_t *psize)
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
ios_flush(s);
|
||||||
|
|
||||||
|
if (s->buf == &s->local[0]) {
|
||||||
|
buf = malloc(s->size+1);
|
||||||
|
if (buf == NULL)
|
||||||
|
return NULL;
|
||||||
|
if (s->size)
|
||||||
|
memcpy(buf, s->buf, s->size);
|
||||||
|
buf[s->size] = '\0';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
buf = s->buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
*psize = s->size+1; // buffer is actually 1 bigger for terminating NUL
|
||||||
|
|
||||||
|
/* empty stream and reinitialize */
|
||||||
|
if (s->bm == bm_mem || s->bm == bm_none) {
|
||||||
|
s->buf = &s->local[0];
|
||||||
|
s->maxsize = IOS_INLSIZE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s->buf = NULL;
|
||||||
|
_buf_realloc(s, IOS_BUFSIZE);
|
||||||
|
}
|
||||||
|
s->size = s->bpos = 0;
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ios_setbuf(ios_t *s, char *buf, size_t size, int own)
|
||||||
|
{
|
||||||
|
ios_flush(s);
|
||||||
|
size_t nvalid=0;
|
||||||
|
|
||||||
|
nvalid = (size < s->size) ? size : s->size;
|
||||||
|
memcpy(buf, s->buf, nvalid);
|
||||||
|
if (s->bpos > nvalid) {
|
||||||
|
// truncated
|
||||||
|
s->bpos = nvalid;
|
||||||
|
}
|
||||||
|
s->size = nvalid;
|
||||||
|
|
||||||
|
if (s->buf!=NULL && s->ownbuf && s->buf!=&s->local[0])
|
||||||
|
free(s->buf);
|
||||||
|
s->buf = buf;
|
||||||
|
s->maxsize = size;
|
||||||
|
s->ownbuf = own;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ios_bufmode(ios_t *s, bufmode_t mode)
|
||||||
|
{
|
||||||
|
// no fd; can only do mem-only buffering
|
||||||
|
if (s->fd == -1 && mode != bm_mem)
|
||||||
|
return -1;
|
||||||
|
s->bm = mode;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ios_bswap(ios_t *s, int bswap)
|
||||||
|
{
|
||||||
|
s->byteswap = !!bswap;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ios_copy(ios_t *to, ios_t *from, size_t nbytes, bool_t all)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* stream object initializers. we do no allocation. */
|
||||||
|
|
||||||
|
ios_t *ios_file(ios_t *s, char *fname, int create, int rewrite)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ios_t *ios_mem(ios_t *s, size_t initsize)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ios_t *ios_fd(ios_t *s, long fd)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* higher level interface */
|
||||||
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
#ifndef __IOS_H_
|
||||||
|
#define __IOS_H_
|
||||||
|
|
||||||
|
// this flag controls when data actually moves out to the underlying I/O
|
||||||
|
// channel. memory streams are a special case of this where the data
|
||||||
|
// never moves out.
|
||||||
|
typedef enum { bm_none, bm_line, bm_block, bm_mem } bufmode_t;
|
||||||
|
|
||||||
|
typedef enum { bst_none, bst_rd, bst_wr } bufstate_t;
|
||||||
|
|
||||||
|
#define IOS_INLSIZE 54
|
||||||
|
#define IOS_BUFSIZE 4095
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bufmode_t bm;
|
||||||
|
|
||||||
|
// the state only indicates where the underlying file position is relative
|
||||||
|
// to the buffer. reading: at the end. writing: at the beginning.
|
||||||
|
// in general, you can do any operation in any state.
|
||||||
|
bufstate_t state;
|
||||||
|
|
||||||
|
int errcode;
|
||||||
|
|
||||||
|
char *buf; // start of buffer
|
||||||
|
size_t maxsize; // space allocated to buffer
|
||||||
|
size_t size; // length of valid data in buf, >=ndirty
|
||||||
|
size_t bpos; // current position in buffer
|
||||||
|
size_t ndirty; // # bytes at &buf[0] that need to be written
|
||||||
|
|
||||||
|
// this is a public field that keeps a running count of bytes
|
||||||
|
// read or written. you can freely use and change it. this is
|
||||||
|
// intended for keeping track of relative positions in streams
|
||||||
|
// that don't have absolute positions (like sockets).
|
||||||
|
size_t tally;
|
||||||
|
|
||||||
|
// pointer-size integer to support platforms where it might have
|
||||||
|
// to be a pointer
|
||||||
|
long fd;
|
||||||
|
|
||||||
|
unsigned char byteswap:1;
|
||||||
|
//unsigned char readonly:1;
|
||||||
|
unsigned char ownbuf:1;
|
||||||
|
unsigned char ownfd:1;
|
||||||
|
|
||||||
|
// this means you can read, seek back, then read the same data
|
||||||
|
// again any number of times. usually only true for files and strings.
|
||||||
|
unsigned char rereadable:1;
|
||||||
|
|
||||||
|
// this enables "stenciled writes". you can alternately write and
|
||||||
|
// seek without flushing in between. this performs read-before-write
|
||||||
|
// to populate the buffer, so "rereadable" capability is required.
|
||||||
|
// this is off by default.
|
||||||
|
unsigned char stenciled:1;
|
||||||
|
|
||||||
|
// request durable writes (fsync)
|
||||||
|
// unsigned char durable:1;
|
||||||
|
|
||||||
|
// todo: mutex
|
||||||
|
char local[IOS_INLSIZE];
|
||||||
|
} ios_t;
|
||||||
|
|
||||||
|
/* low-level interface functions */
|
||||||
|
size_t ios_read(ios_t *s, char *dest, size_t n, int all);
|
||||||
|
size_t ios_write(ios_t *s, char *data, size_t n);
|
||||||
|
off_t ios_seek(ios_t *s, off_t pos); // absolute seek
|
||||||
|
off_t ios_seek_end(ios_t *s);
|
||||||
|
off_t ios_skip(ios_t *s, off_t offs); // relative seek
|
||||||
|
off_t ios_pos(ios_t *s); // get current position
|
||||||
|
size_t ios_trunc(ios_t *s, size_t size);
|
||||||
|
int ios_eof(ios_t *s);
|
||||||
|
int ios_flush(ios_t *s);
|
||||||
|
void ios_close(ios_t *s);
|
||||||
|
char *ios_takebuf(ios_t *s, size_t *psize); // release buffer to caller
|
||||||
|
// set buffer space to use
|
||||||
|
int ios_setbuf(ios_t *s, char *buf, size_t size, int own);
|
||||||
|
int ios_bufmode(ios_t *s, bufmode_t mode);
|
||||||
|
void ios_bswap(ios_t *s, int bswap);
|
||||||
|
int ios_copy(ios_t *to, ios_t *from, size_t nbytes, bool_t all);
|
||||||
|
//void ios_lock(ios_t *s);
|
||||||
|
//int ios_trylock(ios_t *s);
|
||||||
|
//int ios_unlock(ios_t *s);
|
||||||
|
|
||||||
|
/* stream creation */
|
||||||
|
ios_t *ios_file(ios_t *s, char *fname, int create, int rewrite);
|
||||||
|
ios_t *ios_mem(ios_t *s, size_t initsize);
|
||||||
|
ios_t *ios_fd(ios_t *s, long fd);
|
||||||
|
// todo: ios_socket
|
||||||
|
|
||||||
|
/* high-level functions - output */
|
||||||
|
int ios_putnum(ios_t *s, char *data, uint32_t type);
|
||||||
|
int ios_putint(ios_t *s, int n);
|
||||||
|
int ios_pututf8(ios_t *s, uint32_t wc);
|
||||||
|
int ios_putstringz(ios_t *s, char *str, bool_t do_write_nulterm);
|
||||||
|
int ios_printf(ios_t *s, char *format, ...);
|
||||||
|
|
||||||
|
/* high-level stream functions - input */
|
||||||
|
int ios_getnum(ios_t *s, char *data, uint32_t type);
|
||||||
|
int ios_getutf8(ios_t *s, uint32_t *pwc);
|
||||||
|
int ios_ungetutf8(ios_t *s, uint32_t wc);
|
||||||
|
int ios_getstringz(ios_t *dest, ios_t *src);
|
||||||
|
int ios_getstringn(ios_t *dest, ios_t *src, size_t nchars);
|
||||||
|
int ios_readline(ios_t *dest, ios_t *s, char delim);
|
||||||
|
int ios_getline(ios_t *s, char **pbuf, size_t *psz);
|
||||||
|
|
||||||
|
// seek by utf8 sequence increments
|
||||||
|
int ios_nextutf8(ios_t *s);
|
||||||
|
int ios_prevutf8(ios_t *s);
|
||||||
|
|
||||||
|
/* stdio-style functions */
|
||||||
|
#define IOS_EOF (-1)
|
||||||
|
int ios_putc(ios_t *s, int c);
|
||||||
|
wint_t ios_putwc(ios_t *s, wchar_t wc);
|
||||||
|
int ios_getc(ios_t *s);
|
||||||
|
wint_t ios_getwc(ios_t *s);
|
||||||
|
int ios_ungetc(ios_t *s, int c);
|
||||||
|
wint_t ios_ungetwc(ios_t *s, wint_t wc);
|
||||||
|
#define ios_puts(s, str) ios_write(s, str, strlen(str))
|
||||||
|
|
||||||
|
/*
|
||||||
|
With memory streams, mixed reads and writes are equivalent to performing
|
||||||
|
sequences of *p++, as either an lvalue or rvalue. File streams behave
|
||||||
|
similarly, but other streams might not support this. Using unbuffered
|
||||||
|
mode makes this more predictable.
|
||||||
|
|
||||||
|
Note on "unget" functions:
|
||||||
|
There are two kinds of functions here: those that operate on sized
|
||||||
|
blocks of bytes and those that operate on logical units like "character"
|
||||||
|
or "integer". The "unget" functions only work on logical units. There
|
||||||
|
is no "unget n bytes". You can only do an unget after a matching get.
|
||||||
|
However, data pushed back by an unget is available to all read operations.
|
||||||
|
The reason for this is that unget is defined in terms of its effect on
|
||||||
|
the underlying buffer (namely, it rebuffers data as if it had been
|
||||||
|
buffered but not read yet). IOS reserves the right to perform large block
|
||||||
|
operations directly, bypassing the buffer. In such a case data was
|
||||||
|
never buffered, so "rebuffering" has no meaning (i.e. there is no
|
||||||
|
correspondence between the buffer and the physical stream).
|
||||||
|
|
||||||
|
Single-bit I/O is able to write partial bytes ONLY IF the stream supports
|
||||||
|
seeking. Also, line buffering is not well-defined in the context of
|
||||||
|
single-bit I/O, so it might not do what you expect.
|
||||||
|
|
||||||
|
implementation notes:
|
||||||
|
in order to know where we are in a file, we must ensure the buffer
|
||||||
|
is only populated from the underlying stream starting with p==buf.
|
||||||
|
|
||||||
|
to switch from writing to reading: flush, set p=buf, cnt=0
|
||||||
|
to switch from reading to writing: seek backwards cnt bytes, p=buf, cnt=0
|
||||||
|
|
||||||
|
when writing: buf starts at curr. physical stream pos, p - buf is how
|
||||||
|
many bytes we've written logically. cnt==0
|
||||||
|
|
||||||
|
dirty == (bitpos>0 && state==iost_wr), EXCEPT right after switching from
|
||||||
|
reading to writing, where we might be in the middle of a byte without
|
||||||
|
having changed it.
|
||||||
|
|
||||||
|
to write a bit: if !dirty, read up to maxsize-(p-buf) into buffer, then
|
||||||
|
seek back by the same amount (undo it). write onto those bits. now set
|
||||||
|
the dirty bit. in this state, we can bit-read up to the end of the byte,
|
||||||
|
then formally switch to the read state using flush.
|
||||||
|
|
||||||
|
design points:
|
||||||
|
- data-source independence, including memory streams
|
||||||
|
- support 64-bit and large files
|
||||||
|
- efficient, low-latency buffering
|
||||||
|
- unget
|
||||||
|
- expose buffer to user, allow user-owned buffers
|
||||||
|
- allow direct I/O, don't always go through buffer
|
||||||
|
- buffer-internal seeking. makes seeking back 1-2 bytes very fast,
|
||||||
|
and makes it possible for sockets where it otherwise wouldn't be
|
||||||
|
- special support for utf8
|
||||||
|
- tries to allow switching between reading and writing
|
||||||
|
- type-aware functions with byte-order swapping service
|
||||||
|
- position counter for meaningful data offsets with sockets
|
||||||
|
|
||||||
|
note:
|
||||||
|
the current code needs to be mostly rewritten. the design should be
|
||||||
|
as follows:
|
||||||
|
|
||||||
|
the buffer is a view of part of a file/stream. you can seek, read, and
|
||||||
|
write around in it as much as you like, as if it were just a string.
|
||||||
|
|
||||||
|
we keep track of the part of the buffer that's invalid (written to).
|
||||||
|
we remember whether the position of the underlying stream is aligned
|
||||||
|
with the end of the buffer (reading mode) or the beginning (writing mode).
|
||||||
|
|
||||||
|
based on this info, we might have to seek back before doing a flush.
|
||||||
|
|
||||||
|
as optimizations, we do no writing if the buffer isn't "dirty", and we
|
||||||
|
do no reading if the data will only be overwritten.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef __LLT_H_
|
||||||
|
#define __LLT_H_
|
||||||
|
|
||||||
|
#include "dtypes.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "utf8.h"
|
||||||
|
#include "ios.h"
|
||||||
|
#include "socket.h"
|
||||||
|
#include "timefuncs.h"
|
||||||
|
#include "hashing.h"
|
||||||
|
#include "ptrhash.h"
|
||||||
|
#include "bitvector.h"
|
||||||
|
#include "dirpath.h"
|
||||||
|
|
||||||
|
void llt_init();
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,984 @@
|
||||||
|
/*
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
lookup3.c, by Bob Jenkins, May 2006, Public Domain.
|
||||||
|
|
||||||
|
These are functions for producing 32-bit hashes for hash table lookup.
|
||||||
|
hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
|
||||||
|
are externally useful functions. Routines to test the hash are included
|
||||||
|
if SELF_TEST is defined. You can use this free for any purpose. It's in
|
||||||
|
the public domain. It has no warranty.
|
||||||
|
|
||||||
|
You probably want to use hashlittle(). hashlittle() and hashbig()
|
||||||
|
hash byte arrays. hashlittle() is is faster than hashbig() on
|
||||||
|
little-endian machines. Intel and AMD are little-endian machines.
|
||||||
|
On second thought, you probably want hashlittle2(), which is identical to
|
||||||
|
hashlittle() except it returns two 32-bit hashes for the price of one.
|
||||||
|
You could implement hashbig2() if you wanted but I haven't bothered here.
|
||||||
|
|
||||||
|
If you want to find a hash of, say, exactly 7 integers, do
|
||||||
|
a = i1; b = i2; c = i3;
|
||||||
|
mix(a,b,c);
|
||||||
|
a += i4; b += i5; c += i6;
|
||||||
|
mix(a,b,c);
|
||||||
|
a += i7;
|
||||||
|
final(a,b,c);
|
||||||
|
then use c as the hash value. If you have a variable length array of
|
||||||
|
4-byte integers to hash, use hashword(). If you have a byte array (like
|
||||||
|
a character string), use hashlittle(). If you have several byte arrays, or
|
||||||
|
a mix of things, see the comments above hashlittle().
|
||||||
|
|
||||||
|
Why is this so big? I read 12 bytes at a time into 3 4-byte integers,
|
||||||
|
then mix those integers. This is fast (you can do a lot more thorough
|
||||||
|
mixing with 12*3 instructions on 3 integers than you can with 3 instructions
|
||||||
|
on 1 byte), but shoehorning those bytes into integers efficiently is messy.
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
//#define SELF_TEST 1
|
||||||
|
|
||||||
|
#include <stdio.h> /* defines printf for tests */
|
||||||
|
#include <time.h> /* defines time_t for timings in the test */
|
||||||
|
#ifndef WIN32
|
||||||
|
#include <stdint.h> /* defines uint32_t etc */
|
||||||
|
#include <sys/param.h> /* attempt to define endianness */
|
||||||
|
#else
|
||||||
|
typedef unsigned int uint32_t;
|
||||||
|
typedef unsigned char uint8_t;
|
||||||
|
typedef unsigned short uint16_t;
|
||||||
|
#endif
|
||||||
|
#ifdef LINUX
|
||||||
|
# include <endian.h> /* attempt to define endianness */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* My best guess at if you are big-endian or little-endian. This may
|
||||||
|
* need adjustment.
|
||||||
|
*/
|
||||||
|
#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \
|
||||||
|
__BYTE_ORDER == __LITTLE_ENDIAN) || \
|
||||||
|
(defined(i386) || defined(__i386__) || defined(__i486__) || \
|
||||||
|
defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL))
|
||||||
|
# define HASH_LITTLE_ENDIAN 1
|
||||||
|
# define HASH_BIG_ENDIAN 0
|
||||||
|
#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \
|
||||||
|
__BYTE_ORDER == __BIG_ENDIAN) || \
|
||||||
|
(defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel))
|
||||||
|
# define HASH_LITTLE_ENDIAN 0
|
||||||
|
# define HASH_BIG_ENDIAN 1
|
||||||
|
#else
|
||||||
|
# define HASH_LITTLE_ENDIAN 0
|
||||||
|
# define HASH_BIG_ENDIAN 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define hashsize(n) ((uint32_t)1<<(n))
|
||||||
|
#define hashmask(n) (hashsize(n)-1)
|
||||||
|
#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
|
||||||
|
|
||||||
|
/*
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
mix -- mix 3 32-bit values reversibly.
|
||||||
|
|
||||||
|
This is reversible, so any information in (a,b,c) before mix() is
|
||||||
|
still in (a,b,c) after mix().
|
||||||
|
|
||||||
|
If four pairs of (a,b,c) inputs are run through mix(), or through
|
||||||
|
mix() in reverse, there are at least 32 bits of the output that
|
||||||
|
are sometimes the same for one pair and different for another pair.
|
||||||
|
This was tested for:
|
||||||
|
* pairs that differed by one bit, by two bits, in any combination
|
||||||
|
of top bits of (a,b,c), or in any combination of bottom bits of
|
||||||
|
(a,b,c).
|
||||||
|
* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
|
||||||
|
the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
|
||||||
|
is commonly produced by subtraction) look like a single 1-bit
|
||||||
|
difference.
|
||||||
|
* the base values were pseudorandom, all zero but one bit set, or
|
||||||
|
all zero plus a counter that starts at zero.
|
||||||
|
|
||||||
|
Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
|
||||||
|
satisfy this are
|
||||||
|
4 6 8 16 19 4
|
||||||
|
9 15 3 18 27 15
|
||||||
|
14 9 3 7 17 3
|
||||||
|
Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
|
||||||
|
for "differ" defined as + with a one-bit base and a two-bit delta. I
|
||||||
|
used http://burtleburtle.net/bob/hash/avalanche.html to choose
|
||||||
|
the operations, constants, and arrangements of the variables.
|
||||||
|
|
||||||
|
This does not achieve avalanche. There are input bits of (a,b,c)
|
||||||
|
that fail to affect some output bits of (a,b,c), especially of a. The
|
||||||
|
most thoroughly mixed value is c, but it doesn't really even achieve
|
||||||
|
avalanche in c.
|
||||||
|
|
||||||
|
This allows some parallelism. Read-after-writes are good at doubling
|
||||||
|
the number of bits affected, so the goal of mixing pulls in the opposite
|
||||||
|
direction as the goal of parallelism. I did what I could. Rotates
|
||||||
|
seem to cost as much as shifts on every machine I could lay my hands
|
||||||
|
on, and rotates are much kinder to the top and bottom bits, so I used
|
||||||
|
rotates.
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#define mix(a,b,c) \
|
||||||
|
{ \
|
||||||
|
a -= c; a ^= rot(c, 4); c += b; \
|
||||||
|
b -= a; b ^= rot(a, 6); a += c; \
|
||||||
|
c -= b; c ^= rot(b, 8); b += a; \
|
||||||
|
a -= c; a ^= rot(c,16); c += b; \
|
||||||
|
b -= a; b ^= rot(a,19); a += c; \
|
||||||
|
c -= b; c ^= rot(b, 4); b += a; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
final -- final mixing of 3 32-bit values (a,b,c) into c
|
||||||
|
|
||||||
|
Pairs of (a,b,c) values differing in only a few bits will usually
|
||||||
|
produce values of c that look totally different. This was tested for
|
||||||
|
* pairs that differed by one bit, by two bits, in any combination
|
||||||
|
of top bits of (a,b,c), or in any combination of bottom bits of
|
||||||
|
(a,b,c).
|
||||||
|
* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
|
||||||
|
the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
|
||||||
|
is commonly produced by subtraction) look like a single 1-bit
|
||||||
|
difference.
|
||||||
|
* the base values were pseudorandom, all zero but one bit set, or
|
||||||
|
all zero plus a counter that starts at zero.
|
||||||
|
|
||||||
|
These constants passed:
|
||||||
|
14 11 25 16 4 14 24
|
||||||
|
12 14 25 16 4 14 24
|
||||||
|
and these came close:
|
||||||
|
4 8 15 26 3 22 24
|
||||||
|
10 8 15 26 3 22 24
|
||||||
|
11 8 15 26 3 22 24
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#define final(a,b,c) \
|
||||||
|
{ \
|
||||||
|
c ^= b; c -= rot(b,14); \
|
||||||
|
a ^= c; a -= rot(c,11); \
|
||||||
|
b ^= a; b -= rot(a,25); \
|
||||||
|
c ^= b; c -= rot(b,16); \
|
||||||
|
a ^= c; a -= rot(c,4); \
|
||||||
|
b ^= a; b -= rot(a,14); \
|
||||||
|
c ^= b; c -= rot(b,24); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
This works on all machines. To be useful, it requires
|
||||||
|
-- that the key be an array of uint32_t's, and
|
||||||
|
-- that the length be the number of uint32_t's in the key
|
||||||
|
|
||||||
|
The function hashword() is identical to hashlittle() on little-endian
|
||||||
|
machines, and identical to hashbig() on big-endian machines,
|
||||||
|
except that the length has to be measured in uint32_ts rather than in
|
||||||
|
bytes. hashlittle() is more complicated than hashword() only because
|
||||||
|
hashlittle() has to dance around fitting the key bytes into registers.
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
uint32_t hashword(
|
||||||
|
const uint32_t *k, /* the key, an array of uint32_t values */
|
||||||
|
size_t length, /* the length of the key, in uint32_ts */
|
||||||
|
uint32_t initval) /* the previous hash, or an arbitrary value */
|
||||||
|
{
|
||||||
|
uint32_t a,b,c;
|
||||||
|
|
||||||
|
/* Set up the internal state */
|
||||||
|
a = b = c = 0xdeadbeef + (((uint32_t)length)<<2) + initval;
|
||||||
|
|
||||||
|
/*------------------------------------------------- handle most of the key */
|
||||||
|
while (length > 3)
|
||||||
|
{
|
||||||
|
a += k[0];
|
||||||
|
b += k[1];
|
||||||
|
c += k[2];
|
||||||
|
mix(a,b,c);
|
||||||
|
length -= 3;
|
||||||
|
k += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------- handle the last 3 uint32_t's */
|
||||||
|
switch(length) /* all the case statements fall through */
|
||||||
|
{
|
||||||
|
case 3 : c+=k[2];
|
||||||
|
case 2 : b+=k[1];
|
||||||
|
case 1 : a+=k[0];
|
||||||
|
final(a,b,c);
|
||||||
|
case 0: /* case 0: nothing left to add */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*------------------------------------------------------ report the result */
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
hashword2() -- same as hashword(), but take two seeds and return two
|
||||||
|
32-bit values. pc and pb must both be nonnull, and *pc and *pb must
|
||||||
|
both be initialized with seeds. If you pass in (*pb)==0, the output
|
||||||
|
(*pc) will be the same as the return value from hashword().
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
void hashword2 (
|
||||||
|
const uint32_t *k, /* the key, an array of uint32_t values */
|
||||||
|
size_t length, /* the length of the key, in uint32_ts */
|
||||||
|
uint32_t *pc, /* IN: seed OUT: primary hash value */
|
||||||
|
uint32_t *pb) /* IN: more seed OUT: secondary hash value */
|
||||||
|
{
|
||||||
|
uint32_t a,b,c;
|
||||||
|
|
||||||
|
/* Set up the internal state */
|
||||||
|
a = b = c = 0xdeadbeef + ((uint32_t)(length<<2)) + *pc;
|
||||||
|
c += *pb;
|
||||||
|
|
||||||
|
/*------------------------------------------------- handle most of the key */
|
||||||
|
while (length > 3)
|
||||||
|
{
|
||||||
|
a += k[0];
|
||||||
|
b += k[1];
|
||||||
|
c += k[2];
|
||||||
|
mix(a,b,c);
|
||||||
|
length -= 3;
|
||||||
|
k += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------- handle the last 3 uint32_t's */
|
||||||
|
switch(length) /* all the case statements fall through */
|
||||||
|
{
|
||||||
|
case 3 : c+=k[2];
|
||||||
|
case 2 : b+=k[1];
|
||||||
|
case 1 : a+=k[0];
|
||||||
|
final(a,b,c);
|
||||||
|
case 0: /* case 0: nothing left to add */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*------------------------------------------------------ report the result */
|
||||||
|
*pc=c; *pb=b;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/*
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
hashlittle() -- hash a variable-length key into a 32-bit value
|
||||||
|
k : the key (the unaligned variable-length array of bytes)
|
||||||
|
length : the length of the key, counting by bytes
|
||||||
|
initval : can be any 4-byte value
|
||||||
|
Returns a 32-bit value. Every bit of the key affects every bit of
|
||||||
|
the return value. Two keys differing by one or two bits will have
|
||||||
|
totally different hash values.
|
||||||
|
|
||||||
|
The best hash table sizes are powers of 2. There is no need to do
|
||||||
|
mod a prime (mod is sooo slow!). If you need less than 32 bits,
|
||||||
|
use a bitmask. For example, if you need only 10 bits, do
|
||||||
|
h = (h & hashmask(10));
|
||||||
|
In which case, the hash table should have hashsize(10) elements.
|
||||||
|
|
||||||
|
If you are hashing n strings (uint8_t **)k, do it like this:
|
||||||
|
for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);
|
||||||
|
|
||||||
|
By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this
|
||||||
|
code any way you wish, private, educational, or commercial. It's free.
|
||||||
|
|
||||||
|
Use for hash table lookup, or anything where one collision in 2^^32 is
|
||||||
|
acceptable. Do NOT use for cryptographic purposes.
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint32_t hashlittle( const void *key, size_t length, uint32_t initval)
|
||||||
|
{
|
||||||
|
uint32_t a,b,c; /* internal state */
|
||||||
|
union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
|
||||||
|
|
||||||
|
/* Set up the internal state */
|
||||||
|
a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
|
||||||
|
|
||||||
|
u.ptr = key;
|
||||||
|
if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
|
||||||
|
const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
|
||||||
|
const uint8_t *k8;
|
||||||
|
|
||||||
|
/*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
|
||||||
|
while (length > 12)
|
||||||
|
{
|
||||||
|
a += k[0];
|
||||||
|
b += k[1];
|
||||||
|
c += k[2];
|
||||||
|
mix(a,b,c);
|
||||||
|
length -= 12;
|
||||||
|
k += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------- handle the last (probably partial) block */
|
||||||
|
/*
|
||||||
|
* "k[2]&0xffffff" actually reads beyond the end of the string, but
|
||||||
|
* then masks off the part it's not allowed to read. Because the
|
||||||
|
* string is aligned, the masked-off tail is in the same word as the
|
||||||
|
* rest of the string. Every machine with memory protection I've seen
|
||||||
|
* does it on word boundaries, so is OK with this. But VALGRIND will
|
||||||
|
* still catch it and complain. The masking trick does make the hash
|
||||||
|
* noticably faster for short strings (like English words).
|
||||||
|
*/
|
||||||
|
#ifndef VALGRIND
|
||||||
|
|
||||||
|
switch(length)
|
||||||
|
{
|
||||||
|
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
|
||||||
|
case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
|
||||||
|
case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
|
||||||
|
case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
|
||||||
|
case 8 : b+=k[1]; a+=k[0]; break;
|
||||||
|
case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
|
||||||
|
case 6 : b+=k[1]&0xffff; a+=k[0]; break;
|
||||||
|
case 5 : b+=k[1]&0xff; a+=k[0]; break;
|
||||||
|
case 4 : a+=k[0]; break;
|
||||||
|
case 3 : a+=k[0]&0xffffff; break;
|
||||||
|
case 2 : a+=k[0]&0xffff; break;
|
||||||
|
case 1 : a+=k[0]&0xff; break;
|
||||||
|
case 0 : return c; /* zero length strings require no mixing */
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* make valgrind happy */
|
||||||
|
|
||||||
|
k8 = (const uint8_t *)k;
|
||||||
|
switch(length)
|
||||||
|
{
|
||||||
|
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
|
||||||
|
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
|
||||||
|
case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
|
||||||
|
case 9 : c+=k8[8]; /* fall through */
|
||||||
|
case 8 : b+=k[1]; a+=k[0]; break;
|
||||||
|
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
|
||||||
|
case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
|
||||||
|
case 5 : b+=k8[4]; /* fall through */
|
||||||
|
case 4 : a+=k[0]; break;
|
||||||
|
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
|
||||||
|
case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
|
||||||
|
case 1 : a+=k8[0]; break;
|
||||||
|
case 0 : return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !valgrind */
|
||||||
|
|
||||||
|
} else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
|
||||||
|
const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
|
||||||
|
const uint8_t *k8;
|
||||||
|
|
||||||
|
/*--------------- all but last block: aligned reads and different mixing */
|
||||||
|
while (length > 12)
|
||||||
|
{
|
||||||
|
a += k[0] + (((uint32_t)k[1])<<16);
|
||||||
|
b += k[2] + (((uint32_t)k[3])<<16);
|
||||||
|
c += k[4] + (((uint32_t)k[5])<<16);
|
||||||
|
mix(a,b,c);
|
||||||
|
length -= 12;
|
||||||
|
k += 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------- handle the last (probably partial) block */
|
||||||
|
k8 = (const uint8_t *)k;
|
||||||
|
switch(length)
|
||||||
|
{
|
||||||
|
case 12: c+=k[4]+(((uint32_t)k[5])<<16);
|
||||||
|
b+=k[2]+(((uint32_t)k[3])<<16);
|
||||||
|
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||||
|
break;
|
||||||
|
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
|
||||||
|
case 10: c+=k[4];
|
||||||
|
b+=k[2]+(((uint32_t)k[3])<<16);
|
||||||
|
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||||
|
break;
|
||||||
|
case 9 : c+=k8[8]; /* fall through */
|
||||||
|
case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
|
||||||
|
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||||
|
break;
|
||||||
|
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
|
||||||
|
case 6 : b+=k[2];
|
||||||
|
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||||
|
break;
|
||||||
|
case 5 : b+=k8[4]; /* fall through */
|
||||||
|
case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
|
||||||
|
break;
|
||||||
|
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
|
||||||
|
case 2 : a+=k[0];
|
||||||
|
break;
|
||||||
|
case 1 : a+=k8[0];
|
||||||
|
break;
|
||||||
|
case 0 : return c; /* zero length requires no mixing */
|
||||||
|
}
|
||||||
|
|
||||||
|
} else { /* need to read the key one byte at a time */
|
||||||
|
const uint8_t *k = (const uint8_t *)key;
|
||||||
|
|
||||||
|
/*--------------- all but the last block: affect some 32 bits of (a,b,c) */
|
||||||
|
while (length > 12)
|
||||||
|
{
|
||||||
|
a += k[0];
|
||||||
|
a += ((uint32_t)k[1])<<8;
|
||||||
|
a += ((uint32_t)k[2])<<16;
|
||||||
|
a += ((uint32_t)k[3])<<24;
|
||||||
|
b += k[4];
|
||||||
|
b += ((uint32_t)k[5])<<8;
|
||||||
|
b += ((uint32_t)k[6])<<16;
|
||||||
|
b += ((uint32_t)k[7])<<24;
|
||||||
|
c += k[8];
|
||||||
|
c += ((uint32_t)k[9])<<8;
|
||||||
|
c += ((uint32_t)k[10])<<16;
|
||||||
|
c += ((uint32_t)k[11])<<24;
|
||||||
|
mix(a,b,c);
|
||||||
|
length -= 12;
|
||||||
|
k += 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------- last block: affect all 32 bits of (c) */
|
||||||
|
switch(length) /* all the case statements fall through */
|
||||||
|
{
|
||||||
|
case 12: c+=((uint32_t)k[11])<<24;
|
||||||
|
case 11: c+=((uint32_t)k[10])<<16;
|
||||||
|
case 10: c+=((uint32_t)k[9])<<8;
|
||||||
|
case 9 : c+=k[8];
|
||||||
|
case 8 : b+=((uint32_t)k[7])<<24;
|
||||||
|
case 7 : b+=((uint32_t)k[6])<<16;
|
||||||
|
case 6 : b+=((uint32_t)k[5])<<8;
|
||||||
|
case 5 : b+=k[4];
|
||||||
|
case 4 : a+=((uint32_t)k[3])<<24;
|
||||||
|
case 3 : a+=((uint32_t)k[2])<<16;
|
||||||
|
case 2 : a+=((uint32_t)k[1])<<8;
|
||||||
|
case 1 : a+=k[0];
|
||||||
|
break;
|
||||||
|
case 0 : return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final(a,b,c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hashlittle2: return 2 32-bit hash values
|
||||||
|
*
|
||||||
|
* This is identical to hashlittle(), except it returns two 32-bit hash
|
||||||
|
* values instead of just one. This is good enough for hash table
|
||||||
|
* lookup with 2^^64 buckets, or if you want a second hash if you're not
|
||||||
|
* happy with the first, or if you want a probably-unique 64-bit ID for
|
||||||
|
* the key. *pc is better mixed than *pb, so use *pc first. If you want
|
||||||
|
* a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)".
|
||||||
|
*/
|
||||||
|
void hashlittle2(
|
||||||
|
const void *key, /* the key to hash */
|
||||||
|
size_t length, /* length of the key */
|
||||||
|
uint32_t *pc, /* IN: primary initval, OUT: primary hash */
|
||||||
|
uint32_t *pb) /* IN: secondary initval, OUT: secondary hash */
|
||||||
|
{
|
||||||
|
uint32_t a,b,c; /* internal state */
|
||||||
|
union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
|
||||||
|
|
||||||
|
/* Set up the internal state */
|
||||||
|
a = b = c = 0xdeadbeef + ((uint32_t)length) + *pc;
|
||||||
|
c += *pb;
|
||||||
|
|
||||||
|
u.ptr = key;
|
||||||
|
if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
|
||||||
|
const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
|
||||||
|
const uint8_t *k8;
|
||||||
|
|
||||||
|
/*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
|
||||||
|
while (length > 12)
|
||||||
|
{
|
||||||
|
a += k[0];
|
||||||
|
b += k[1];
|
||||||
|
c += k[2];
|
||||||
|
mix(a,b,c);
|
||||||
|
length -= 12;
|
||||||
|
k += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------- handle the last (probably partial) block */
|
||||||
|
/*
|
||||||
|
* "k[2]&0xffffff" actually reads beyond the end of the string, but
|
||||||
|
* then masks off the part it's not allowed to read. Because the
|
||||||
|
* string is aligned, the masked-off tail is in the same word as the
|
||||||
|
* rest of the string. Every machine with memory protection I've seen
|
||||||
|
* does it on word boundaries, so is OK with this. But VALGRIND will
|
||||||
|
* still catch it and complain. The masking trick does make the hash
|
||||||
|
* noticably faster for short strings (like English words).
|
||||||
|
*/
|
||||||
|
#ifndef VALGRIND
|
||||||
|
(void)k8;
|
||||||
|
switch(length)
|
||||||
|
{
|
||||||
|
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
|
||||||
|
case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
|
||||||
|
case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
|
||||||
|
case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
|
||||||
|
case 8 : b+=k[1]; a+=k[0]; break;
|
||||||
|
case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
|
||||||
|
case 6 : b+=k[1]&0xffff; a+=k[0]; break;
|
||||||
|
case 5 : b+=k[1]&0xff; a+=k[0]; break;
|
||||||
|
case 4 : a+=k[0]; break;
|
||||||
|
case 3 : a+=k[0]&0xffffff; break;
|
||||||
|
case 2 : a+=k[0]&0xffff; break;
|
||||||
|
case 1 : a+=k[0]&0xff; break;
|
||||||
|
case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* make valgrind happy */
|
||||||
|
|
||||||
|
k8 = (const uint8_t *)k;
|
||||||
|
switch(length)
|
||||||
|
{
|
||||||
|
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
|
||||||
|
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
|
||||||
|
case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
|
||||||
|
case 9 : c+=k8[8]; /* fall through */
|
||||||
|
case 8 : b+=k[1]; a+=k[0]; break;
|
||||||
|
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
|
||||||
|
case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
|
||||||
|
case 5 : b+=k8[4]; /* fall through */
|
||||||
|
case 4 : a+=k[0]; break;
|
||||||
|
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
|
||||||
|
case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
|
||||||
|
case 1 : a+=k8[0]; break;
|
||||||
|
case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !valgrind */
|
||||||
|
|
||||||
|
} else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
|
||||||
|
const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
|
||||||
|
const uint8_t *k8;
|
||||||
|
|
||||||
|
/*--------------- all but last block: aligned reads and different mixing */
|
||||||
|
while (length > 12)
|
||||||
|
{
|
||||||
|
a += k[0] + (((uint32_t)k[1])<<16);
|
||||||
|
b += k[2] + (((uint32_t)k[3])<<16);
|
||||||
|
c += k[4] + (((uint32_t)k[5])<<16);
|
||||||
|
mix(a,b,c);
|
||||||
|
length -= 12;
|
||||||
|
k += 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------- handle the last (probably partial) block */
|
||||||
|
k8 = (const uint8_t *)k;
|
||||||
|
switch(length)
|
||||||
|
{
|
||||||
|
case 12: c+=k[4]+(((uint32_t)k[5])<<16);
|
||||||
|
b+=k[2]+(((uint32_t)k[3])<<16);
|
||||||
|
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||||
|
break;
|
||||||
|
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
|
||||||
|
case 10: c+=k[4];
|
||||||
|
b+=k[2]+(((uint32_t)k[3])<<16);
|
||||||
|
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||||
|
break;
|
||||||
|
case 9 : c+=k8[8]; /* fall through */
|
||||||
|
case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
|
||||||
|
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||||
|
break;
|
||||||
|
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
|
||||||
|
case 6 : b+=k[2];
|
||||||
|
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||||
|
break;
|
||||||
|
case 5 : b+=k8[4]; /* fall through */
|
||||||
|
case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
|
||||||
|
break;
|
||||||
|
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
|
||||||
|
case 2 : a+=k[0];
|
||||||
|
break;
|
||||||
|
case 1 : a+=k8[0];
|
||||||
|
break;
|
||||||
|
case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
|
||||||
|
}
|
||||||
|
|
||||||
|
} else { /* need to read the key one byte at a time */
|
||||||
|
const uint8_t *k = (const uint8_t *)key;
|
||||||
|
|
||||||
|
/*--------------- all but the last block: affect some 32 bits of (a,b,c) */
|
||||||
|
while (length > 12)
|
||||||
|
{
|
||||||
|
a += k[0];
|
||||||
|
a += ((uint32_t)k[1])<<8;
|
||||||
|
a += ((uint32_t)k[2])<<16;
|
||||||
|
a += ((uint32_t)k[3])<<24;
|
||||||
|
b += k[4];
|
||||||
|
b += ((uint32_t)k[5])<<8;
|
||||||
|
b += ((uint32_t)k[6])<<16;
|
||||||
|
b += ((uint32_t)k[7])<<24;
|
||||||
|
c += k[8];
|
||||||
|
c += ((uint32_t)k[9])<<8;
|
||||||
|
c += ((uint32_t)k[10])<<16;
|
||||||
|
c += ((uint32_t)k[11])<<24;
|
||||||
|
mix(a,b,c);
|
||||||
|
length -= 12;
|
||||||
|
k += 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------- last block: affect all 32 bits of (c) */
|
||||||
|
switch(length) /* all the case statements fall through */
|
||||||
|
{
|
||||||
|
case 12: c+=((uint32_t)k[11])<<24;
|
||||||
|
case 11: c+=((uint32_t)k[10])<<16;
|
||||||
|
case 10: c+=((uint32_t)k[9])<<8;
|
||||||
|
case 9 : c+=k[8];
|
||||||
|
case 8 : b+=((uint32_t)k[7])<<24;
|
||||||
|
case 7 : b+=((uint32_t)k[6])<<16;
|
||||||
|
case 6 : b+=((uint32_t)k[5])<<8;
|
||||||
|
case 5 : b+=k[4];
|
||||||
|
case 4 : a+=((uint32_t)k[3])<<24;
|
||||||
|
case 3 : a+=((uint32_t)k[2])<<16;
|
||||||
|
case 2 : a+=((uint32_t)k[1])<<8;
|
||||||
|
case 1 : a+=k[0];
|
||||||
|
break;
|
||||||
|
case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final(a,b,c);
|
||||||
|
*pc=c; *pb=b;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/*
|
||||||
|
* hashbig():
|
||||||
|
* This is the same as hashword() on big-endian machines. It is different
|
||||||
|
* from hashlittle() on all machines. hashbig() takes advantage of
|
||||||
|
* big-endian byte ordering.
|
||||||
|
*/
|
||||||
|
uint32_t hashbig( const void *key, size_t length, uint32_t initval)
|
||||||
|
{
|
||||||
|
uint32_t a,b,c;
|
||||||
|
union { const void *ptr; size_t i; } u; /* to cast key to (size_t) happily */
|
||||||
|
|
||||||
|
/* Set up the internal state */
|
||||||
|
a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
|
||||||
|
|
||||||
|
u.ptr = key;
|
||||||
|
if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) {
|
||||||
|
const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
|
||||||
|
const uint8_t *k8;
|
||||||
|
|
||||||
|
/*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
|
||||||
|
while (length > 12)
|
||||||
|
{
|
||||||
|
a += k[0];
|
||||||
|
b += k[1];
|
||||||
|
c += k[2];
|
||||||
|
mix(a,b,c);
|
||||||
|
length -= 12;
|
||||||
|
k += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------- handle the last (probably partial) block */
|
||||||
|
/*
|
||||||
|
* "k[2]<<8" actually reads beyond the end of the string, but
|
||||||
|
* then shifts out the part it's not allowed to read. Because the
|
||||||
|
* string is aligned, the illegal read is in the same word as the
|
||||||
|
* rest of the string. Every machine with memory protection I've seen
|
||||||
|
* does it on word boundaries, so is OK with this. But VALGRIND will
|
||||||
|
* still catch it and complain. The masking trick does make the hash
|
||||||
|
* noticably faster for short strings (like English words).
|
||||||
|
*/
|
||||||
|
#ifndef VALGRIND
|
||||||
|
|
||||||
|
switch(length)
|
||||||
|
{
|
||||||
|
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
|
||||||
|
case 11: c+=k[2]&0xffffff00; b+=k[1]; a+=k[0]; break;
|
||||||
|
case 10: c+=k[2]&0xffff0000; b+=k[1]; a+=k[0]; break;
|
||||||
|
case 9 : c+=k[2]&0xff000000; b+=k[1]; a+=k[0]; break;
|
||||||
|
case 8 : b+=k[1]; a+=k[0]; break;
|
||||||
|
case 7 : b+=k[1]&0xffffff00; a+=k[0]; break;
|
||||||
|
case 6 : b+=k[1]&0xffff0000; a+=k[0]; break;
|
||||||
|
case 5 : b+=k[1]&0xff000000; a+=k[0]; break;
|
||||||
|
case 4 : a+=k[0]; break;
|
||||||
|
case 3 : a+=k[0]&0xffffff00; break;
|
||||||
|
case 2 : a+=k[0]&0xffff0000; break;
|
||||||
|
case 1 : a+=k[0]&0xff000000; break;
|
||||||
|
case 0 : return c; /* zero length strings require no mixing */
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* make valgrind happy */
|
||||||
|
|
||||||
|
k8 = (const uint8_t *)k;
|
||||||
|
switch(length) /* all the case statements fall through */
|
||||||
|
{
|
||||||
|
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
|
||||||
|
case 11: c+=((uint32_t)k8[10])<<8; /* fall through */
|
||||||
|
case 10: c+=((uint32_t)k8[9])<<16; /* fall through */
|
||||||
|
case 9 : c+=((uint32_t)k8[8])<<24; /* fall through */
|
||||||
|
case 8 : b+=k[1]; a+=k[0]; break;
|
||||||
|
case 7 : b+=((uint32_t)k8[6])<<8; /* fall through */
|
||||||
|
case 6 : b+=((uint32_t)k8[5])<<16; /* fall through */
|
||||||
|
case 5 : b+=((uint32_t)k8[4])<<24; /* fall through */
|
||||||
|
case 4 : a+=k[0]; break;
|
||||||
|
case 3 : a+=((uint32_t)k8[2])<<8; /* fall through */
|
||||||
|
case 2 : a+=((uint32_t)k8[1])<<16; /* fall through */
|
||||||
|
case 1 : a+=((uint32_t)k8[0])<<24; break;
|
||||||
|
case 0 : return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !VALGRIND */
|
||||||
|
|
||||||
|
} else { /* need to read the key one byte at a time */
|
||||||
|
const uint8_t *k = (const uint8_t *)key;
|
||||||
|
|
||||||
|
/*--------------- all but the last block: affect some 32 bits of (a,b,c) */
|
||||||
|
while (length > 12)
|
||||||
|
{
|
||||||
|
a += ((uint32_t)k[0])<<24;
|
||||||
|
a += ((uint32_t)k[1])<<16;
|
||||||
|
a += ((uint32_t)k[2])<<8;
|
||||||
|
a += ((uint32_t)k[3]);
|
||||||
|
b += ((uint32_t)k[4])<<24;
|
||||||
|
b += ((uint32_t)k[5])<<16;
|
||||||
|
b += ((uint32_t)k[6])<<8;
|
||||||
|
b += ((uint32_t)k[7]);
|
||||||
|
c += ((uint32_t)k[8])<<24;
|
||||||
|
c += ((uint32_t)k[9])<<16;
|
||||||
|
c += ((uint32_t)k[10])<<8;
|
||||||
|
c += ((uint32_t)k[11]);
|
||||||
|
mix(a,b,c);
|
||||||
|
length -= 12;
|
||||||
|
k += 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------- last block: affect all 32 bits of (c) */
|
||||||
|
switch(length) /* all the case statements fall through */
|
||||||
|
{
|
||||||
|
case 12: c+=k[11];
|
||||||
|
case 11: c+=((uint32_t)k[10])<<8;
|
||||||
|
case 10: c+=((uint32_t)k[9])<<16;
|
||||||
|
case 9 : c+=((uint32_t)k[8])<<24;
|
||||||
|
case 8 : b+=k[7];
|
||||||
|
case 7 : b+=((uint32_t)k[6])<<8;
|
||||||
|
case 6 : b+=((uint32_t)k[5])<<16;
|
||||||
|
case 5 : b+=((uint32_t)k[4])<<24;
|
||||||
|
case 4 : a+=k[3];
|
||||||
|
case 3 : a+=((uint32_t)k[2])<<8;
|
||||||
|
case 2 : a+=((uint32_t)k[1])<<16;
|
||||||
|
case 1 : a+=((uint32_t)k[0])<<24;
|
||||||
|
break;
|
||||||
|
case 0 : return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final(a,b,c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SELF_TEST
|
||||||
|
|
||||||
|
/* used for timings */
|
||||||
|
void driver1()
|
||||||
|
{
|
||||||
|
uint8_t buf[256];
|
||||||
|
uint32_t i;
|
||||||
|
uint32_t h=0;
|
||||||
|
time_t a,z;
|
||||||
|
|
||||||
|
time(&a);
|
||||||
|
for (i=0; i<256; ++i) buf[i] = 'x';
|
||||||
|
for (i=0; i<1; ++i)
|
||||||
|
{
|
||||||
|
h = hashlittle(&buf[0],1,h);
|
||||||
|
}
|
||||||
|
time(&z);
|
||||||
|
if (z-a > 0) printf("time %d %.8x\n", z-a, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check that every input bit changes every output bit half the time */
|
||||||
|
#define HASHSTATE 1
|
||||||
|
#define HASHLEN 1
|
||||||
|
#define MAXPAIR 60
|
||||||
|
#define MAXLEN 70
|
||||||
|
void driver2()
|
||||||
|
{
|
||||||
|
uint8_t qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1];
|
||||||
|
uint32_t c[HASHSTATE], d[HASHSTATE], i=0, j=0, k, l, m=0, z;
|
||||||
|
uint32_t e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE];
|
||||||
|
uint32_t x[HASHSTATE],y[HASHSTATE];
|
||||||
|
uint32_t hlen;
|
||||||
|
|
||||||
|
printf("No more than %d trials should ever be needed \n",MAXPAIR/2);
|
||||||
|
for (hlen=0; hlen < MAXLEN; ++hlen)
|
||||||
|
{
|
||||||
|
z=0;
|
||||||
|
for (i=0; i<hlen; ++i) /*----------------------- for each input byte, */
|
||||||
|
{
|
||||||
|
for (j=0; j<8; ++j) /*------------------------ for each input bit, */
|
||||||
|
{
|
||||||
|
for (m=1; m<8; ++m) /*------------ for serveral possible initvals, */
|
||||||
|
{
|
||||||
|
for (l=0; l<HASHSTATE; ++l)
|
||||||
|
e[l]=f[l]=g[l]=h[l]=x[l]=y[l]=~((uint32_t)0);
|
||||||
|
|
||||||
|
/*---- check that every output bit is affected by that input bit */
|
||||||
|
for (k=0; k<MAXPAIR; k+=2)
|
||||||
|
{
|
||||||
|
uint32_t finished=1;
|
||||||
|
/* keys have one bit different */
|
||||||
|
for (l=0; l<hlen+1; ++l) {a[l] = b[l] = (uint8_t)0;}
|
||||||
|
/* have a and b be two keys differing in only one bit */
|
||||||
|
a[i] ^= (k<<j);
|
||||||
|
a[i] ^= (k>>(8-j));
|
||||||
|
c[0] = hashlittle(a, hlen, m);
|
||||||
|
b[i] ^= ((k+1)<<j);
|
||||||
|
b[i] ^= ((k+1)>>(8-j));
|
||||||
|
d[0] = hashlittle(b, hlen, m);
|
||||||
|
/* check every bit is 1, 0, set, and not set at least once */
|
||||||
|
for (l=0; l<HASHSTATE; ++l)
|
||||||
|
{
|
||||||
|
e[l] &= (c[l]^d[l]);
|
||||||
|
f[l] &= ~(c[l]^d[l]);
|
||||||
|
g[l] &= c[l];
|
||||||
|
h[l] &= ~c[l];
|
||||||
|
x[l] &= d[l];
|
||||||
|
y[l] &= ~d[l];
|
||||||
|
if (e[l]|f[l]|g[l]|h[l]|x[l]|y[l]) finished=0;
|
||||||
|
}
|
||||||
|
if (finished) break;
|
||||||
|
}
|
||||||
|
if (k>z) z=k;
|
||||||
|
if (k==MAXPAIR)
|
||||||
|
{
|
||||||
|
printf("Some bit didn't change: ");
|
||||||
|
printf("%.8x %.8x %.8x %.8x %.8x %.8x ",
|
||||||
|
e[0],f[0],g[0],h[0],x[0],y[0]);
|
||||||
|
printf("i %d j %d m %d len %d\n", i, j, m, hlen);
|
||||||
|
}
|
||||||
|
if (z==MAXPAIR) goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
if (z < MAXPAIR)
|
||||||
|
{
|
||||||
|
printf("Mix success %2d bytes %2d initvals ",i,m);
|
||||||
|
printf("required %d trials\n", z/2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for reading beyond the end of the buffer and alignment problems */
|
||||||
|
void driver3()
|
||||||
|
{
|
||||||
|
uint8_t buf[MAXLEN+20], *b;
|
||||||
|
uint32_t len;
|
||||||
|
uint8_t q[] = "This is the time for all good men to come to the aid of their country...";
|
||||||
|
uint32_t h;
|
||||||
|
uint8_t qq[] = "xThis is the time for all good men to come to the aid of their country...";
|
||||||
|
uint32_t i;
|
||||||
|
uint8_t qqq[] = "xxThis is the time for all good men to come to the aid of their country...";
|
||||||
|
uint32_t j;
|
||||||
|
uint8_t qqqq[] = "xxxThis is the time for all good men to come to the aid of their country...";
|
||||||
|
uint32_t ref,x,y;
|
||||||
|
uint8_t *p;
|
||||||
|
|
||||||
|
printf("Endianness. These lines should all be the same (for values filled in):\n");
|
||||||
|
printf("%.8x %.8x %.8x\n",
|
||||||
|
hashword((const uint32_t *)q, (sizeof(q)-1)/4, 13),
|
||||||
|
hashword((const uint32_t *)q, (sizeof(q)-5)/4, 13),
|
||||||
|
hashword((const uint32_t *)q, (sizeof(q)-9)/4, 13));
|
||||||
|
p = q;
|
||||||
|
printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
|
||||||
|
hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
|
||||||
|
hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
|
||||||
|
hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
|
||||||
|
hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
|
||||||
|
hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
|
||||||
|
hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
|
||||||
|
p = &qq[1];
|
||||||
|
printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
|
||||||
|
hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
|
||||||
|
hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
|
||||||
|
hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
|
||||||
|
hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
|
||||||
|
hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
|
||||||
|
hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
|
||||||
|
p = &qqq[2];
|
||||||
|
printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
|
||||||
|
hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
|
||||||
|
hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
|
||||||
|
hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
|
||||||
|
hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
|
||||||
|
hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
|
||||||
|
hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
|
||||||
|
p = &qqqq[3];
|
||||||
|
printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
|
||||||
|
hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
|
||||||
|
hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
|
||||||
|
hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
|
||||||
|
hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
|
||||||
|
hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
|
||||||
|
hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
/* check that hashlittle2 and hashlittle produce the same results */
|
||||||
|
i=47; j=0;
|
||||||
|
hashlittle2(q, sizeof(q), &i, &j);
|
||||||
|
if (hashlittle(q, sizeof(q), 47) != i)
|
||||||
|
printf("hashlittle2 and hashlittle mismatch\n");
|
||||||
|
|
||||||
|
/* check that hashword2 and hashword produce the same results */
|
||||||
|
len = 0xdeadbeef;
|
||||||
|
i=47, j=0;
|
||||||
|
hashword2(&len, 1, &i, &j);
|
||||||
|
if (hashword(&len, 1, 47) != i)
|
||||||
|
printf("hashword2 and hashword mismatch %x %x\n",
|
||||||
|
i, hashword(&len, 1, 47));
|
||||||
|
|
||||||
|
/* check hashlittle doesn't read before or after the ends of the string */
|
||||||
|
for (h=0, b=buf+1; h<8; ++h, ++b)
|
||||||
|
{
|
||||||
|
for (i=0; i<MAXLEN; ++i)
|
||||||
|
{
|
||||||
|
len = i;
|
||||||
|
for (j=0; j<i; ++j) *(b+j)=0;
|
||||||
|
|
||||||
|
/* these should all be equal */
|
||||||
|
ref = hashlittle(b, len, (uint32_t)1);
|
||||||
|
*(b+i)=(uint8_t)~0;
|
||||||
|
*(b-1)=(uint8_t)~0;
|
||||||
|
x = hashlittle(b, len, (uint32_t)1);
|
||||||
|
y = hashlittle(b, len, (uint32_t)1);
|
||||||
|
if ((ref != x) || (ref != y))
|
||||||
|
{
|
||||||
|
printf("alignment error: %.8x %.8x %.8x %d %d\n",ref,x,y,
|
||||||
|
h, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check for problems with nulls */
|
||||||
|
void driver4()
|
||||||
|
{
|
||||||
|
uint8_t buf[1];
|
||||||
|
uint32_t h,i,state[HASHSTATE];
|
||||||
|
|
||||||
|
|
||||||
|
buf[0] = ~0;
|
||||||
|
for (i=0; i<HASHSTATE; ++i) state[i] = 1;
|
||||||
|
printf("These should all be different\n");
|
||||||
|
for (i=0, h=0; i<8; ++i)
|
||||||
|
{
|
||||||
|
h = hashlittle(buf, 0, h);
|
||||||
|
printf("%2ld 0-byte strings, hash is %.8x\n", i, h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
driver1(); /* test that the key is hashed: used for timings */
|
||||||
|
driver2(); /* test that whole key is hashed thoroughly */
|
||||||
|
driver3(); /* test that nothing but the key is hashed */
|
||||||
|
driver4(); /* test hashing multiple buffers (all buffers are null) */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* SELF_TEST */
|
|
@ -0,0 +1,193 @@
|
||||||
|
/*
|
||||||
|
A C-program for MT19937, with initialization improved 2002/1/26.
|
||||||
|
Coded by Takuji Nishimura and Makoto Matsumoto.
|
||||||
|
|
||||||
|
Before using, initialize the state by using init_genrand(seed)
|
||||||
|
or init_by_array(init_key, key_length).
|
||||||
|
|
||||||
|
Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. The names of its contributors may not be used to endorse or promote
|
||||||
|
products derived from this software without specific prior written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
|
||||||
|
Any feedback is very welcome.
|
||||||
|
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
|
||||||
|
email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* Period parameters */
|
||||||
|
#define mtN 624
|
||||||
|
#define mtM 397
|
||||||
|
#define MATRIX_A 0x9908b0dfUL /* constant vector a */
|
||||||
|
#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
|
||||||
|
#define LOWER_MASK 0x7fffffffUL /* least significant r bits */
|
||||||
|
|
||||||
|
static unsigned long mt[mtN]; /* the array for the state vector */
|
||||||
|
static int mti=mtN+1; /* mti==mtN+1 means mt[mtN] is not initialized */
|
||||||
|
|
||||||
|
/* initializes mt[mtN] with a seed */
|
||||||
|
void init_genrand(unsigned long s)
|
||||||
|
{
|
||||||
|
mt[0]= s & 0xffffffffUL;
|
||||||
|
for (mti=1; mti<mtN; mti++) {
|
||||||
|
mt[mti] =
|
||||||
|
(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
|
||||||
|
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
|
||||||
|
/* In the previous versions, MSBs of the seed affect */
|
||||||
|
/* only MSBs of the array mt[]. */
|
||||||
|
/* 2002/01/09 modified by Makoto Matsumoto */
|
||||||
|
mt[mti] &= 0xffffffffUL;
|
||||||
|
/* for >32 bit machines */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialize by an array with array-length */
|
||||||
|
/* init_key is the array for initializing keys */
|
||||||
|
/* key_length is its length */
|
||||||
|
/* slight change for C++, 2004/2/26 */
|
||||||
|
void init_by_array(unsigned long init_key[], int key_length)
|
||||||
|
{
|
||||||
|
int i, j, k;
|
||||||
|
init_genrand(19650218UL);
|
||||||
|
i=1; j=0;
|
||||||
|
k = (mtN>key_length ? mtN : key_length);
|
||||||
|
for (; k; k--) {
|
||||||
|
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))
|
||||||
|
+ init_key[j] + j; /* non linear */
|
||||||
|
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
|
||||||
|
i++; j++;
|
||||||
|
if (i>=mtN) { mt[0] = mt[mtN-1]; i=1; }
|
||||||
|
if (j>=key_length) j=0;
|
||||||
|
}
|
||||||
|
for (k=mtN-1; k; k--) {
|
||||||
|
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))
|
||||||
|
- i; /* non linear */
|
||||||
|
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
|
||||||
|
i++;
|
||||||
|
if (i>=mtN) { mt[0] = mt[mtN-1]; i=1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* generates a random number on [0,0xffffffff]-interval */
|
||||||
|
unsigned long genrand_int32(void)
|
||||||
|
{
|
||||||
|
unsigned long y;
|
||||||
|
static unsigned long mag01[2]={0x0UL, MATRIX_A};
|
||||||
|
/* mag01[x] = x * MATRIX_A for x=0,1 */
|
||||||
|
|
||||||
|
if (mti >= mtN) { /* generate mtN words at one time */
|
||||||
|
int kk;
|
||||||
|
|
||||||
|
if (mti == mtN+1) /* if init_genrand() has not been called, */
|
||||||
|
init_genrand(5489UL); /* a default initial seed is used */
|
||||||
|
|
||||||
|
for (kk=0;kk<mtN-mtM;kk++) {
|
||||||
|
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
|
||||||
|
mt[kk] = mt[kk+mtM] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||||
|
}
|
||||||
|
for (;kk<mtN-1;kk++) {
|
||||||
|
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
|
||||||
|
mt[kk] = mt[kk+(mtM-mtN)] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||||
|
}
|
||||||
|
y = (mt[mtN-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
|
||||||
|
mt[mtN-1] = mt[mtM-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||||
|
|
||||||
|
mti = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
y = mt[mti++];
|
||||||
|
|
||||||
|
/* Tempering */
|
||||||
|
y ^= (y >> 11);
|
||||||
|
y ^= (y << 7) & 0x9d2c5680UL;
|
||||||
|
y ^= (y << 15) & 0xefc60000UL;
|
||||||
|
y ^= (y >> 18);
|
||||||
|
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* generates a random number on [0,0x7fffffff]-interval */
|
||||||
|
long genrand_int31(void)
|
||||||
|
{
|
||||||
|
return (long)(genrand_int32()>>1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* generates a random number on [0,1]-real-interval */
|
||||||
|
double genrand_real1(void)
|
||||||
|
{
|
||||||
|
return genrand_int32()*(1.0/4294967295.0);
|
||||||
|
/* divided by 2^32-1 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* generates a random number on [0,1)-real-interval */
|
||||||
|
double genrand_real2(void)
|
||||||
|
{
|
||||||
|
return genrand_int32()*(1.0/4294967296.0);
|
||||||
|
/* divided by 2^32 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* generates a random number on (0,1)-real-interval */
|
||||||
|
double genrand_real3(void)
|
||||||
|
{
|
||||||
|
return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0);
|
||||||
|
/* divided by 2^32 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* generates a random number on [0,1) with 53-bit resolution*/
|
||||||
|
double genrand_res53(void)
|
||||||
|
{
|
||||||
|
unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6;
|
||||||
|
return(a*67108864.0+b)*(1.0/9007199254740992.0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/* These real versions are due to Isaku Wada, 2002/01/09 added */
|
||||||
|
#if 0
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned long init[4]={0x123, 0x234, 0x345, 0x456}, length=4;
|
||||||
|
init_by_array(init, length);
|
||||||
|
printf("1000 outputs of genrand_int32()\n");
|
||||||
|
for (i=0; i<1000; i++) {
|
||||||
|
printf("%10lu ", genrand_int32());
|
||||||
|
if (i%5==4) printf("\n");
|
||||||
|
}
|
||||||
|
printf("\n1000 outputs of genrand_real2()\n");
|
||||||
|
for (i=0; i<1000; i++) {
|
||||||
|
printf("%10.8f ", genrand_real2());
|
||||||
|
if (i%5==4) printf("\n");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,44 @@
|
||||||
|
my c library (jlibc)
|
||||||
|
------------
|
||||||
|
|
||||||
|
* bytevector utilities: memswap, memreverse, swap_el, etc.
|
||||||
|
* hashing, random#s: int32hash, int64hash, int64to32hash, lookup3, ptrhash
|
||||||
|
* utf8
|
||||||
|
* bitvector
|
||||||
|
- iostream, socket, asynch io
|
||||||
|
- cross-platform pathnames, cwd, exename, date/time, etc.
|
||||||
|
* floating point number utils: comparison, print_real, print_cplx
|
||||||
|
- strtab (with prefix searching)
|
||||||
|
|
||||||
|
(- pool allocator with hooks for gc (sweep function))
|
||||||
|
(- list (dequeue))
|
||||||
|
(- sort: msort list, qsort numbers) not too important since stdlib has qsort
|
||||||
|
|
||||||
|
- use non-allocating APIs. this means the interface never allocates or
|
||||||
|
frees memory for you. you have to manage space for objects yourself.
|
||||||
|
|
||||||
|
- separate math library. includes numal, cephes, my complex number routines,
|
||||||
|
more special functions
|
||||||
|
|
||||||
|
|
||||||
|
stream redesign:
|
||||||
|
|
||||||
|
memstream, single-descriptor-backed, pipe (read/write on separate descriptors)
|
||||||
|
|
||||||
|
do our own buffering, so we can implement getline without seek/skip
|
||||||
|
|
||||||
|
all provided functions must be in terms of read,write,poll,flush only
|
||||||
|
seek/skip will be available, but only works on files and strings
|
||||||
|
change semantics of bit i/o so it doesn't require skip(-1)
|
||||||
|
|
||||||
|
compare our implementation to somebody else's fread,fwrite,etc.
|
||||||
|
|
||||||
|
|
||||||
|
cool trick for faking string streams with stdio:
|
||||||
|
|
||||||
|
char buf[256];
|
||||||
|
v = list2(number(6), number(4));
|
||||||
|
FILE *f = fopen("/dev/null", "a");
|
||||||
|
setbuffer(f, buf, sizeof(buf));
|
||||||
|
print(f, v, 0);
|
||||||
|
printf("got '%s'\n", buf);
|
|
@ -0,0 +1,316 @@
|
||||||
|
#include <limits.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "dtypes.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "ieee754.h"
|
||||||
|
|
||||||
|
// given a number, determine an appropriate type for storing it
|
||||||
|
#if 0
|
||||||
|
numerictype_t effective_numerictype(double r)
|
||||||
|
{
|
||||||
|
double fp;
|
||||||
|
|
||||||
|
fp = fpart(r);
|
||||||
|
if (fp != 0 || r > U64_MAX || r < S64_MIN) {
|
||||||
|
if (r > FLT_MAX || r < -FLT_MAX || (fabs(r) < FLT_MIN)) {
|
||||||
|
return T_DOUBLE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return T_FLOAT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (r >= SCHAR_MIN && r <= SCHAR_MAX) {
|
||||||
|
return T_INT8;
|
||||||
|
}
|
||||||
|
else if (r >= SHRT_MIN && r <= SHRT_MAX) {
|
||||||
|
return T_INT16;
|
||||||
|
}
|
||||||
|
else if (r >= INT_MIN && r <= INT_MAX) {
|
||||||
|
return T_INT32;
|
||||||
|
}
|
||||||
|
else if (r <= S64_MAX) {
|
||||||
|
return T_INT64;
|
||||||
|
}
|
||||||
|
return T_UINT64;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// simpler version implementing a smaller preferred type repertoire
|
||||||
|
numerictype_t effective_numerictype(double r)
|
||||||
|
{
|
||||||
|
double fp;
|
||||||
|
|
||||||
|
fp = fpart(r);
|
||||||
|
if (fp != 0 || r > U64_MAX || r < S64_MIN) {
|
||||||
|
return T_DOUBLE;
|
||||||
|
}
|
||||||
|
else if (r >= INT_MIN && r <= INT_MAX) {
|
||||||
|
return T_INT32;
|
||||||
|
}
|
||||||
|
else if (r <= S64_MAX) {
|
||||||
|
return T_INT64;
|
||||||
|
}
|
||||||
|
return T_UINT64;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
double conv_to_double(void *data, numerictype_t tag)
|
||||||
|
{
|
||||||
|
double d=0;
|
||||||
|
switch (tag) {
|
||||||
|
case T_INT8: d = (double)*(int8_t*)data; break;
|
||||||
|
case T_UINT8: d = (double)*(uint8_t*)data; break;
|
||||||
|
case T_INT16: d = (double)*(int16_t*)data; break;
|
||||||
|
case T_UINT16: d = (double)*(uint16_t*)data; break;
|
||||||
|
case T_INT32: d = (double)*(int32_t*)data; break;
|
||||||
|
case T_UINT32: d = (double)*(uint32_t*)data; break;
|
||||||
|
case T_INT64:
|
||||||
|
d = (double)*(int64_t*)data;
|
||||||
|
if (d > 0 && *(int64_t*)data < 0) // can happen!
|
||||||
|
d = -d;
|
||||||
|
break;
|
||||||
|
case T_UINT64: d = (double)*(uint64_t*)data; break;
|
||||||
|
case T_FLOAT: d = (double)*(float*)data; break;
|
||||||
|
case T_DOUBLE: return *(double*)data;
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void conv_from_double(void *dest, double d, numerictype_t tag)
|
||||||
|
{
|
||||||
|
switch (tag) {
|
||||||
|
case T_INT8: *(int8_t*)dest = d; break;
|
||||||
|
case T_UINT8: *(uint8_t*)dest = d; break;
|
||||||
|
case T_INT16: *(int16_t*)dest = d; break;
|
||||||
|
case T_UINT16: *(uint16_t*)dest = d; break;
|
||||||
|
case T_INT32: *(int32_t*)dest = d; break;
|
||||||
|
case T_UINT32: *(uint32_t*)dest = d; break;
|
||||||
|
case T_INT64:
|
||||||
|
*(int64_t*)dest = d;
|
||||||
|
if (d > 0 && *(int64_t*)dest < 0) // 0x8000000000000000 is a bitch
|
||||||
|
*(int64_t*)dest = S64_MAX;
|
||||||
|
break;
|
||||||
|
case T_UINT64: *(uint64_t*)dest = d; break;
|
||||||
|
case T_FLOAT: *(float*)dest = d; break;
|
||||||
|
case T_DOUBLE: *(double*)dest = d; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CONV_TO_INTTYPE(type) \
|
||||||
|
type##_t conv_to_##type(void *data, numerictype_t tag) \
|
||||||
|
{ \
|
||||||
|
type##_t i=0; \
|
||||||
|
switch (tag) { \
|
||||||
|
case T_INT8: i = (type##_t)*(int8_t*)data; break; \
|
||||||
|
case T_UINT8: i = (type##_t)*(uint8_t*)data; break; \
|
||||||
|
case T_INT16: i = (type##_t)*(int16_t*)data; break; \
|
||||||
|
case T_UINT16: i = (type##_t)*(uint16_t*)data; break; \
|
||||||
|
case T_INT32: i = (type##_t)*(int32_t*)data; break; \
|
||||||
|
case T_UINT32: i = (type##_t)*(uint32_t*)data; break; \
|
||||||
|
case T_INT64: i = (type##_t)*(int64_t*)data; break; \
|
||||||
|
case T_UINT64: i = (type##_t)*(uint64_t*)data; break; \
|
||||||
|
case T_FLOAT: i = (type##_t)*(float*)data; break; \
|
||||||
|
case T_DOUBLE: i = (type##_t)*(double*)data; break; \
|
||||||
|
} \
|
||||||
|
return i; \
|
||||||
|
}
|
||||||
|
|
||||||
|
CONV_TO_INTTYPE(int64)
|
||||||
|
CONV_TO_INTTYPE(uint64)
|
||||||
|
CONV_TO_INTTYPE(int32)
|
||||||
|
CONV_TO_INTTYPE(uint32)
|
||||||
|
|
||||||
|
int cmp_same_lt(void *a, void *b, numerictype_t tag)
|
||||||
|
{
|
||||||
|
switch (tag) {
|
||||||
|
case T_INT8: return *(int8_t*)a < *(int8_t*)b;
|
||||||
|
case T_UINT8: return *(uint8_t*)a < *(uint8_t*)b;
|
||||||
|
case T_INT16: return *(int16_t*)a < *(int16_t*)b;
|
||||||
|
case T_UINT16: return *(uint16_t*)a < *(uint16_t*)b;
|
||||||
|
case T_INT32: return *(int32_t*)a < *(int32_t*)b;
|
||||||
|
case T_UINT32: return *(uint32_t*)a < *(uint32_t*)b;
|
||||||
|
case T_INT64: return *(int64_t*)a < *(int64_t*)b;
|
||||||
|
case T_UINT64: return *(uint64_t*)a < *(uint64_t*)b;
|
||||||
|
case T_FLOAT: return *(float*)a < *(float*)b;
|
||||||
|
case T_DOUBLE: return *(double*)a < *(double*)b;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmp_same_eq(void *a, void *b, numerictype_t tag)
|
||||||
|
{
|
||||||
|
switch (tag) {
|
||||||
|
case T_INT8: return *(int8_t*)a == *(int8_t*)b;
|
||||||
|
case T_UINT8: return *(uint8_t*)a == *(uint8_t*)b;
|
||||||
|
case T_INT16: return *(int16_t*)a == *(int16_t*)b;
|
||||||
|
case T_UINT16: return *(uint16_t*)a == *(uint16_t*)b;
|
||||||
|
case T_INT32: return *(int32_t*)a == *(int32_t*)b;
|
||||||
|
case T_UINT32: return *(uint32_t*)a == *(uint32_t*)b;
|
||||||
|
case T_INT64: return *(int64_t*)a == *(int64_t*)b;
|
||||||
|
case T_UINT64: return *(uint64_t*)a == *(uint64_t*)b;
|
||||||
|
case T_FLOAT: return flt_equals(*(float*)a, *(float*)b);
|
||||||
|
case T_DOUBLE: return dbl_equals(*(double*)a, *(double*)b);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmp_lt(void *a, numerictype_t atag, void *b, numerictype_t btag)
|
||||||
|
{
|
||||||
|
if (atag==btag)
|
||||||
|
return cmp_same_lt(a, b, atag);
|
||||||
|
|
||||||
|
double da = conv_to_double(a, atag);
|
||||||
|
double db = conv_to_double(b, btag);
|
||||||
|
|
||||||
|
// casting to double will only get the wrong answer for big int64s
|
||||||
|
// that differ in low bits
|
||||||
|
if (da < db)
|
||||||
|
return 1;
|
||||||
|
if (db < da)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (atag == T_UINT64) {
|
||||||
|
// this is safe because if a had been bigger than S64_MAX,
|
||||||
|
// we would already have concluded that it's bigger than b.
|
||||||
|
if (btag == T_INT64) {
|
||||||
|
return ((int64_t)*(uint64_t*)a < *(int64_t*)b);
|
||||||
|
}
|
||||||
|
else if (btag == T_DOUBLE) {
|
||||||
|
return (*(uint64_t*)a < (uint64_t)*(double*)b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (atag == T_INT64) {
|
||||||
|
if (btag == T_UINT64) {
|
||||||
|
return (*(int64_t*)a < (int64_t)*(uint64_t*)b);
|
||||||
|
}
|
||||||
|
else if (btag == T_DOUBLE) {
|
||||||
|
return (*(int64_t*)a < (int64_t)*(double*)b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (btag == T_UINT64) {
|
||||||
|
if (atag == T_INT64) {
|
||||||
|
return ((int64_t)*(uint64_t*)b > *(int64_t*)a);
|
||||||
|
}
|
||||||
|
else if (atag == T_DOUBLE) {
|
||||||
|
return (*(uint64_t*)b > (uint64_t)*(double*)a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (btag == T_INT64) {
|
||||||
|
if (atag == T_UINT64) {
|
||||||
|
return (*(int64_t*)b > (int64_t)*(uint64_t*)a);
|
||||||
|
}
|
||||||
|
else if (atag == T_DOUBLE) {
|
||||||
|
return (*(int64_t*)b > (int64_t)*(double*)a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmp_eq(void *a, numerictype_t atag, void *b, numerictype_t btag)
|
||||||
|
{
|
||||||
|
if (atag==btag)
|
||||||
|
return cmp_same_eq(a, b, atag);
|
||||||
|
|
||||||
|
double da = conv_to_double(a, atag);
|
||||||
|
double db = conv_to_double(b, btag);
|
||||||
|
|
||||||
|
if ((int)atag >= T_FLOAT && (int)btag >= T_FLOAT)
|
||||||
|
return dbl_equals(da, db);
|
||||||
|
|
||||||
|
if (da != db)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (atag == T_UINT64) {
|
||||||
|
// this is safe because if a had been bigger than S64_MAX,
|
||||||
|
// we would already have concluded that it's bigger than b.
|
||||||
|
if (btag == T_INT64) {
|
||||||
|
return ((int64_t)*(uint64_t*)a == *(int64_t*)b);
|
||||||
|
}
|
||||||
|
else if (btag == T_DOUBLE) {
|
||||||
|
return (*(uint64_t*)a == (uint64_t)*(double*)b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (atag == T_INT64) {
|
||||||
|
if (btag == T_UINT64) {
|
||||||
|
return (*(int64_t*)a == (int64_t)*(uint64_t*)b);
|
||||||
|
}
|
||||||
|
else if (btag == T_DOUBLE) {
|
||||||
|
return (*(int64_t*)a == (int64_t)*(double*)b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (btag == T_UINT64) {
|
||||||
|
if (atag == T_INT64) {
|
||||||
|
return ((int64_t)*(uint64_t*)b == *(int64_t*)a);
|
||||||
|
}
|
||||||
|
else if (atag == T_DOUBLE) {
|
||||||
|
return (*(uint64_t*)b == (uint64_t)*(double*)a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (btag == T_INT64) {
|
||||||
|
if (atag == T_UINT64) {
|
||||||
|
return (*(int64_t*)b == (int64_t)*(uint64_t*)a);
|
||||||
|
}
|
||||||
|
else if (atag == T_DOUBLE) {
|
||||||
|
return (*(int64_t*)b == (int64_t)*(double*)a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_LLT_TEST
|
||||||
|
void test_operators()
|
||||||
|
{
|
||||||
|
int8_t i8, i8b;
|
||||||
|
uint8_t ui8, ui8b;
|
||||||
|
int16_t i16, i16b;
|
||||||
|
uint16_t ui16, ui16b;
|
||||||
|
int32_t i32, i32b;
|
||||||
|
uint32_t ui32, ui32b;
|
||||||
|
int64_t i64, i64b;
|
||||||
|
uint64_t ui64, ui64b;
|
||||||
|
float f, fb;
|
||||||
|
double d, db;
|
||||||
|
|
||||||
|
ui64 = U64_MAX;
|
||||||
|
ui64b = U64_MAX-1;
|
||||||
|
i64 = S64_MIN;
|
||||||
|
i64b = i64+1;
|
||||||
|
d = (double)ui64;
|
||||||
|
db = (double)i64b;
|
||||||
|
|
||||||
|
assert(cmp_lt(&i64, T_INT64, &ui64, T_UINT64));
|
||||||
|
assert(!cmp_lt(&ui64, T_UINT64, &i64, T_INT64));
|
||||||
|
assert(cmp_lt(&i64, T_INT64, &ui64b, T_UINT64));
|
||||||
|
assert(!cmp_lt(&ui64b, T_UINT64, &i64, T_INT64));
|
||||||
|
assert(cmp_lt(&i64, T_INT64, &i64b, T_INT64));
|
||||||
|
assert(!cmp_lt(&i64b, T_INT64, &i64, T_INT64));
|
||||||
|
|
||||||
|
// try to compare a double too big to fit in an int64 with an
|
||||||
|
// int64 requiring too much precision to fit in a double...
|
||||||
|
// this case fails but it's very difficult/expensive to support
|
||||||
|
//assert(cmp_lt(&ui64b, T_UINT64, &d, T_DOUBLE));
|
||||||
|
|
||||||
|
i64 = S64_MAX;
|
||||||
|
ui64 = S64_MAX-1;
|
||||||
|
assert(cmp_lt(&ui64, T_UINT64, &i64, T_INT64));
|
||||||
|
assert(!cmp_lt(&i64, T_INT64, &ui64, T_UINT64));
|
||||||
|
i64 = S64_MAX-1;
|
||||||
|
ui64 = S64_MAX;
|
||||||
|
assert(cmp_lt(&i64, T_INT64, &ui64, T_UINT64));
|
||||||
|
assert(!cmp_lt(&ui64, T_UINT64, &i64, T_INT64));
|
||||||
|
|
||||||
|
d = DBL_MAXINT;
|
||||||
|
i64 = DBL_MAXINT+100;
|
||||||
|
assert(cmp_lt(&d, T_DOUBLE, &i64, T_INT64));
|
||||||
|
assert(!cmp_lt(&i64, T_INT64, &d, T_DOUBLE));
|
||||||
|
i64 = DBL_MAXINT+10;
|
||||||
|
assert(cmp_lt(&d, T_DOUBLE, &i64, T_INT64));
|
||||||
|
assert(!cmp_lt(&i64, T_INT64, &d, T_DOUBLE));
|
||||||
|
i64 = DBL_MAXINT+1;
|
||||||
|
assert(cmp_lt(&d, T_DOUBLE, &i64, T_INT64));
|
||||||
|
assert(!cmp_lt(&i64, T_INT64, &d, T_DOUBLE));
|
||||||
|
|
||||||
|
assert(!cmp_eq(&d, T_DOUBLE, &i64, T_INT64));
|
||||||
|
i64 = DBL_MAXINT;
|
||||||
|
assert(cmp_eq(&d, T_DOUBLE, &i64, T_INT64));
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,195 @@
|
||||||
|
/*
|
||||||
|
pointer hash table
|
||||||
|
optimized for storing info about particular values
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include "dtypes.h"
|
||||||
|
#include "ptrhash.h"
|
||||||
|
#include "hashing.h"
|
||||||
|
|
||||||
|
#define ptrhash_size(h) ((h)->size/2)
|
||||||
|
|
||||||
|
ptrhash_t *ptrhash_new(ptrhash_t *h, size_t size)
|
||||||
|
{
|
||||||
|
size = nextipow2(size);
|
||||||
|
size *= 2; // 2 pointers per key/value pair
|
||||||
|
size *= 2; // aim for 50% occupancy
|
||||||
|
h->size = size;
|
||||||
|
h->table = (void**)malloc(size*sizeof(void*));
|
||||||
|
if (h->table == NULL) return NULL;
|
||||||
|
size_t i;
|
||||||
|
for(i=0; i < size; i++)
|
||||||
|
h->table[i] = PH_NOTFOUND;
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ptrhash_free(ptrhash_t *h)
|
||||||
|
{
|
||||||
|
free(h->table);
|
||||||
|
}
|
||||||
|
|
||||||
|
// empty and reduce size
|
||||||
|
void ptrhash_reset(ptrhash_t *h, size_t sz)
|
||||||
|
{
|
||||||
|
if (h->size > sz*4) {
|
||||||
|
size_t newsz = sz*4;
|
||||||
|
void **newtab = (void**)realloc(h->table, newsz*sizeof(void*));
|
||||||
|
if (newtab == NULL)
|
||||||
|
return;
|
||||||
|
h->size = newsz;
|
||||||
|
h->table = newtab;
|
||||||
|
}
|
||||||
|
size_t i, hsz=h->size;
|
||||||
|
for(i=0; i < hsz; i++)
|
||||||
|
h->table[i] = PH_NOTFOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute empirical max-probe for a given size
|
||||||
|
#define ph_max_probe(size) ((size)>>5)
|
||||||
|
|
||||||
|
static void **ptrhash_lookup_bp(ptrhash_t *h, void *key)
|
||||||
|
{
|
||||||
|
uint_t hv;
|
||||||
|
size_t i, orig, index, iter;
|
||||||
|
size_t newsz, sz = ptrhash_size(h);
|
||||||
|
size_t maxprobe = ph_max_probe(sz);
|
||||||
|
void **tab = h->table;
|
||||||
|
void **ol;
|
||||||
|
|
||||||
|
hv = inthash((uptrint_t)key);
|
||||||
|
retry_bp:
|
||||||
|
iter = 0;
|
||||||
|
index = (index_t)(hv & (sz-1)) * 2;
|
||||||
|
sz *= 2;
|
||||||
|
orig = index;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (tab[index] == PH_NOTFOUND) {
|
||||||
|
tab[index] = key;
|
||||||
|
return &tab[index+1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == tab[index])
|
||||||
|
return &tab[index+1];
|
||||||
|
|
||||||
|
index = (index+2) & (sz-1);
|
||||||
|
iter++;
|
||||||
|
if (iter > maxprobe)
|
||||||
|
break;
|
||||||
|
} while (index != orig);
|
||||||
|
|
||||||
|
// table full
|
||||||
|
// quadruple size, rehash, retry the insert
|
||||||
|
// it's important to grow the table really fast; otherwise we waste
|
||||||
|
// lots of time rehashing all the keys over and over.
|
||||||
|
sz = h->size;
|
||||||
|
ol = h->table;
|
||||||
|
if (sz >= (1<<19))
|
||||||
|
newsz = sz<<1;
|
||||||
|
else
|
||||||
|
newsz = sz<<2;
|
||||||
|
//printf("trying to allocate %d words.\n", newsz); fflush(stdout);
|
||||||
|
tab = (void**)malloc(newsz*sizeof(void*));
|
||||||
|
if (tab == NULL)
|
||||||
|
return NULL;
|
||||||
|
for(i=0; i < newsz; i++)
|
||||||
|
tab[i] = PH_NOTFOUND;
|
||||||
|
h->table = tab;
|
||||||
|
h->size = newsz;
|
||||||
|
for(i=0; i < sz; i+=2) {
|
||||||
|
if (ol[i] != PH_NOTFOUND && ol[i+1] != PH_NOTFOUND) {
|
||||||
|
(*ptrhash_lookup_bp(h, ol[i])) = ol[i+1];
|
||||||
|
/*
|
||||||
|
// this condition is not really possible
|
||||||
|
if (bp == NULL) {
|
||||||
|
free(h->table);
|
||||||
|
h->table = ol;
|
||||||
|
h->size = sz;
|
||||||
|
// another thing we could do in this situation
|
||||||
|
// is newsz<<=1 and go back to the malloc, retrying with
|
||||||
|
// a bigger buffer on this level of recursion.
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(ol);
|
||||||
|
|
||||||
|
sz = ptrhash_size(h);
|
||||||
|
maxprobe = ph_max_probe(sz);
|
||||||
|
|
||||||
|
goto retry_bp;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ptrhash_put(ptrhash_t *h, void *key, void *val)
|
||||||
|
{
|
||||||
|
void **bp = ptrhash_lookup_bp(h, key);
|
||||||
|
|
||||||
|
*bp = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void **ptrhash_bp(ptrhash_t *h, void *key)
|
||||||
|
{
|
||||||
|
return ptrhash_lookup_bp(h, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns bp if key is in hash, otherwise NULL
|
||||||
|
static void **ptrhash_peek_bp(ptrhash_t *h, void *key)
|
||||||
|
{
|
||||||
|
size_t sz = ptrhash_size(h);
|
||||||
|
size_t maxprobe = ph_max_probe(sz);
|
||||||
|
void **tab = h->table;
|
||||||
|
size_t index = (index_t)(inthash((uptrint_t)key) & (sz-1)) * 2;
|
||||||
|
sz *= 2;
|
||||||
|
size_t orig = index;
|
||||||
|
size_t iter = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (tab[index] == PH_NOTFOUND)
|
||||||
|
return NULL;
|
||||||
|
if (key == tab[index] && tab[index+1] != PH_NOTFOUND)
|
||||||
|
return &tab[index+1];
|
||||||
|
|
||||||
|
index = (index+2) & (sz-1);
|
||||||
|
iter++;
|
||||||
|
if (iter > maxprobe)
|
||||||
|
break;
|
||||||
|
} while (index != orig);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *ptrhash_get(ptrhash_t *h, void *key)
|
||||||
|
{
|
||||||
|
void **bp = ptrhash_peek_bp(h, key);
|
||||||
|
if (bp == NULL)
|
||||||
|
return PH_NOTFOUND;
|
||||||
|
return *bp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ptrhash_has(ptrhash_t *h, void *key)
|
||||||
|
{
|
||||||
|
return (ptrhash_get(h,key) != PH_NOTFOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ptrhash_remove(ptrhash_t *h, void *key)
|
||||||
|
{
|
||||||
|
void **bp = ptrhash_peek_bp(h, key);
|
||||||
|
if (bp != NULL)
|
||||||
|
*bp = PH_NOTFOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ptrhash_adjoin(ptrhash_t *h, void *key, void *val)
|
||||||
|
{
|
||||||
|
void **bp = ptrhash_lookup_bp(h, key);
|
||||||
|
if (*bp == PH_NOTFOUND)
|
||||||
|
*bp = val;
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
#ifndef __PTRHASH_H_
|
||||||
|
#define __PTRHASH_H_
|
||||||
|
|
||||||
|
typedef struct _ptrhash_t {
|
||||||
|
size_t size;
|
||||||
|
void **table;
|
||||||
|
} ptrhash_t;
|
||||||
|
|
||||||
|
// define this to be an invalid key/value
|
||||||
|
#define PH_NOTFOUND ((void*)2)
|
||||||
|
|
||||||
|
// initialize and free
|
||||||
|
ptrhash_t *ptrhash_new(ptrhash_t *h, size_t size);
|
||||||
|
void ptrhash_free(ptrhash_t *h);
|
||||||
|
|
||||||
|
// clear and (possibly) change size
|
||||||
|
void ptrhash_reset(ptrhash_t *h, size_t sz);
|
||||||
|
|
||||||
|
// return value, or PH_NOTFOUND if key not found
|
||||||
|
void *ptrhash_get(ptrhash_t *h, void *key);
|
||||||
|
|
||||||
|
// add key/value binding
|
||||||
|
void ptrhash_put(ptrhash_t *h, void *key, void *val);
|
||||||
|
|
||||||
|
// add binding iff key is unbound
|
||||||
|
void ptrhash_adjoin(ptrhash_t *h, void *key, void *val);
|
||||||
|
|
||||||
|
// does key exist?
|
||||||
|
int ptrhash_has(ptrhash_t *h, void *key);
|
||||||
|
|
||||||
|
// logically remove key
|
||||||
|
void ptrhash_remove(ptrhash_t *h, void *key);
|
||||||
|
|
||||||
|
// get a pointer to the location of the value for the given key.
|
||||||
|
// creates the location if it doesn't exist. only returns NULL
|
||||||
|
// if memory allocation fails.
|
||||||
|
// this should be used for updates, for example:
|
||||||
|
// void **bp = ptrhash_bp(h, key);
|
||||||
|
// *bp = f(*bp);
|
||||||
|
// do not reuse bp if there might be intervening calls to ptrhash_put,
|
||||||
|
// ptrhash_bp, ptrhash_reset, or ptrhash_free.
|
||||||
|
void **ptrhash_bp(ptrhash_t *h, void *key);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,176 @@
|
||||||
|
/* null stream */
|
||||||
|
off_t null_seek(struct _stream *s, off_t where)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t null_skip(struct _stream *s, off_t offs)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t null_seek_end(struct _stream *s)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t null_read(struct _stream *s, char *dest, size_t size)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t null_write(struct _stream *s, char *data, size_t size)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t null_trunc(struct _stream *s, size_t size)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void null_flush(struct _stream *s)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool_t null_eof(struct _stream *s)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_null_stream(stream_t *s)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT stream_interface_t null_funcs =
|
||||||
|
{free_null_stream, null_seek, null_seek_end, null_skip,
|
||||||
|
null_read, null_write, null_trunc, null_eof, null_flush};
|
||||||
|
|
||||||
|
stream_t *nullstream_new()
|
||||||
|
{
|
||||||
|
stream_t *s;
|
||||||
|
|
||||||
|
s = (stream_t*)obj_alloc(stream_pool);
|
||||||
|
s->funcs = &null_funcs;
|
||||||
|
s->byteswap = false;
|
||||||
|
s->bitpos = s->bitbuf = 0;
|
||||||
|
s->pos = 0;
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_roms_stream(stream_t *s)
|
||||||
|
{
|
||||||
|
(void)s;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t roms_write(struct _stream *s, char *data, size_t size)
|
||||||
|
{
|
||||||
|
(void)s;
|
||||||
|
(void)data;
|
||||||
|
(void)size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t roms_trunc(struct _stream *s, size_t size)
|
||||||
|
{
|
||||||
|
(void)size;
|
||||||
|
return s->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void roms_flush(struct _stream *s)
|
||||||
|
{
|
||||||
|
s->bitpos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream_interface_t roms_funcs =
|
||||||
|
{free_roms_stream, ms_seek, ms_seek_end, ms_skip,
|
||||||
|
ms_read, roms_write, roms_trunc, ms_eof, roms_flush};
|
||||||
|
|
||||||
|
/* read-only memory stream */
|
||||||
|
stream_t *romemstream_new(stream_t *s, char *data, size_t len)
|
||||||
|
{
|
||||||
|
memstream_new(s, 0);
|
||||||
|
|
||||||
|
s->funcs = &roms_funcs;
|
||||||
|
|
||||||
|
s->data = data;
|
||||||
|
s->size = len;
|
||||||
|
s->maxsize = len+1;
|
||||||
|
s->pos = 0;
|
||||||
|
s->bitpos = s->bitbuf = 0;
|
||||||
|
s->byteswap = false;
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
int stream_vput_int(stream_t *s, int nargs, ...)
|
||||||
|
{
|
||||||
|
u_int32_t val, i, c=0;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, nargs);
|
||||||
|
for(i=0; i < (unsigned)nargs; i++) {
|
||||||
|
val = va_arg(ap, int);
|
||||||
|
c += stream_put_int(s, val);
|
||||||
|
}
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
// after this function you are guaranteed to be able to perform
|
||||||
|
// operations of the kind requested.
|
||||||
|
static int _ios_setstate(ios_t *s, iostate_t newstate)
|
||||||
|
{
|
||||||
|
if (s->state != newstate) {
|
||||||
|
if (s->state == iost_none || s->bm == bm_mem || s->bm == bm_none) {
|
||||||
|
}
|
||||||
|
else if (s->state == iost_rd) {
|
||||||
|
// reading -> writing; try to put back unused buffer data
|
||||||
|
// todo: another possibility here is to seek back s->size bytes,
|
||||||
|
// not move any data, and retain the ability to seek backwards
|
||||||
|
// within the buffer. the downside to that would be redundant
|
||||||
|
// writes of stuff that was already in the file.
|
||||||
|
ios_skip(s, -(off_t)(s->size - s->bpos));
|
||||||
|
// todo: if the seek fails...?
|
||||||
|
_discard_partial_buffer(s);
|
||||||
|
// note: bitpos is left alone, so if all goes well we pick up
|
||||||
|
// writing exactly where we stopped reading.
|
||||||
|
}
|
||||||
|
else if (s->state == iost_wr) {
|
||||||
|
ios_flush(s);
|
||||||
|
}
|
||||||
|
s->state = newstate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now make sure buffer is set up for the state we're in
|
||||||
|
if (s->state == iost_wr) {
|
||||||
|
// TODO: fill buffer if stenciling is requested
|
||||||
|
}
|
||||||
|
else if (s->state == iost_rd) {
|
||||||
|
// TODO: fill buffer if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* convert double to int64 in software */
|
||||||
|
int64_t double_to_int64(double d)
|
||||||
|
{
|
||||||
|
int64_t i;
|
||||||
|
int ex;
|
||||||
|
union ieee754_double dl;
|
||||||
|
|
||||||
|
if (fabs(d) < 1) return 0;
|
||||||
|
|
||||||
|
dl.d = d;
|
||||||
|
ex = dl.ieee.exponent - IEEE754_DOUBLE_BIAS;
|
||||||
|
// fill mantissa into bits 0 to 51
|
||||||
|
i = ((((int64_t)dl.mantissa0)<<32) | ((int64_t)dl.mantissa1));
|
||||||
|
if (ex < 52)
|
||||||
|
i >>= (52-ex);
|
||||||
|
else if (ex > 52)
|
||||||
|
i <<= (ex-52);
|
||||||
|
}
|
|
@ -0,0 +1,212 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "dtypes.h"
|
||||||
|
#include "socket.h"
|
||||||
|
|
||||||
|
|
||||||
|
int mysocket(int domain, int type, int protocol)
|
||||||
|
{
|
||||||
|
int val;
|
||||||
|
int s = socket(domain, type, protocol);
|
||||||
|
if (s < 0)
|
||||||
|
return s;
|
||||||
|
val = 4096;
|
||||||
|
setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&val, sizeof(int));
|
||||||
|
val = 4096;
|
||||||
|
setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&val, sizeof(int));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
void bzero(void *s, size_t n)
|
||||||
|
{
|
||||||
|
memset(s, 0, n);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* returns a socket on which to accept() connections */
|
||||||
|
int open_tcp_port(short portno)
|
||||||
|
{
|
||||||
|
int sockfd;
|
||||||
|
struct sockaddr_in serv_addr;
|
||||||
|
|
||||||
|
sockfd = mysocket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
if (sockfd < 0)
|
||||||
|
return -1;
|
||||||
|
bzero(&serv_addr, sizeof(serv_addr));
|
||||||
|
serv_addr.sin_family = AF_INET;
|
||||||
|
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
serv_addr.sin_port = htons(portno);
|
||||||
|
if (bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
|
||||||
|
fprintf(stderr, "could not bind to port %d.\n",
|
||||||
|
portno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
listen(sockfd, 4);
|
||||||
|
return sockfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* returns a socket on which to accept() connections, finding some
|
||||||
|
available port (portno is value-return) */
|
||||||
|
int open_any_tcp_port(short *portno)
|
||||||
|
|
||||||
|
{
|
||||||
|
int sockfd;
|
||||||
|
struct sockaddr_in serv_addr;
|
||||||
|
|
||||||
|
sockfd = mysocket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
if (sockfd < 0)
|
||||||
|
return -1;
|
||||||
|
bzero(&serv_addr, sizeof(serv_addr));
|
||||||
|
serv_addr.sin_family = AF_INET;
|
||||||
|
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
serv_addr.sin_port = htons(*portno);
|
||||||
|
while (bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
|
||||||
|
(*portno)++;
|
||||||
|
serv_addr.sin_port = htons(*portno);
|
||||||
|
}
|
||||||
|
|
||||||
|
listen(sockfd, 4);
|
||||||
|
return sockfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* returns a socket on which to accept() connections, finding some
|
||||||
|
available port (portno is value-return) */
|
||||||
|
int open_any_udp_port(short *portno)
|
||||||
|
{
|
||||||
|
int sockfd;
|
||||||
|
struct sockaddr_in serv_addr;
|
||||||
|
|
||||||
|
sockfd = mysocket(PF_INET, SOCK_DGRAM, IPPROTO_TCP);
|
||||||
|
if (sockfd < 0)
|
||||||
|
return -1;
|
||||||
|
bzero(&serv_addr, sizeof(serv_addr));
|
||||||
|
serv_addr.sin_family = AF_INET;
|
||||||
|
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
serv_addr.sin_port = htons(*portno);
|
||||||
|
while (bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
|
||||||
|
(*portno)++;
|
||||||
|
serv_addr.sin_port = htons(*portno);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sockfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef WIN32
|
||||||
|
void closesocket(int fd)
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* returns a socket to use to send data to the given address */
|
||||||
|
int connect_to_host(char *hostname, short portno)
|
||||||
|
{
|
||||||
|
struct hostent *host_info;
|
||||||
|
int sockfd, yes=1;
|
||||||
|
struct sockaddr_in host_addr;
|
||||||
|
|
||||||
|
host_info = gethostbyname(hostname);
|
||||||
|
if (host_info == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sockfd = mysocket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
if (sockfd < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
(void)setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
|
||||||
|
memset((char*)&host_addr, 0, sizeof(host_addr));
|
||||||
|
host_addr.sin_family = host_info->h_addrtype;
|
||||||
|
memcpy((char*)&host_addr.sin_addr, host_info->h_addr,
|
||||||
|
host_info->h_length);
|
||||||
|
|
||||||
|
host_addr.sin_port = htons(portno);
|
||||||
|
|
||||||
|
if (connect(sockfd, (struct sockaddr*)&host_addr,
|
||||||
|
sizeof(struct sockaddr_in)) != 0) {
|
||||||
|
closesocket(sockfd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sockfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int connect_to_addr(struct sockaddr_in *host_addr)
|
||||||
|
{
|
||||||
|
int sockfd, yes=1;
|
||||||
|
|
||||||
|
sockfd = mysocket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
if (sockfd < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
(void)setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
|
||||||
|
|
||||||
|
if (connect(sockfd, (struct sockaddr*)host_addr,
|
||||||
|
sizeof(struct sockaddr_in)) != 0) {
|
||||||
|
closesocket(sockfd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sockfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* repeated send until all of buffer is sent */
|
||||||
|
int sendall(int sockfd, char *buffer, int bufLen, int flags)
|
||||||
|
{
|
||||||
|
int numBytesToSend=bufLen, length;
|
||||||
|
|
||||||
|
while (numBytesToSend>0) {
|
||||||
|
length = send(sockfd, (void *) buffer, numBytesToSend, flags);
|
||||||
|
if (length < 0) {
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
numBytesToSend -= length ;
|
||||||
|
buffer += length ;
|
||||||
|
}
|
||||||
|
return(bufLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* repeated read until all of buffer is read */
|
||||||
|
int readall(int sockfd, char *buffer, int bufLen, int flags)
|
||||||
|
{
|
||||||
|
int numBytesToRead=bufLen, length;
|
||||||
|
|
||||||
|
while (numBytesToRead>0) {
|
||||||
|
length = recv(sockfd, buffer, numBytesToRead, flags);
|
||||||
|
if (length <= 0) {
|
||||||
|
return(length);
|
||||||
|
}
|
||||||
|
numBytesToRead -= length;
|
||||||
|
buffer += length;
|
||||||
|
}
|
||||||
|
return(bufLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
int addr_eq(struct sockaddr_in *a, struct sockaddr_in *b)
|
||||||
|
{
|
||||||
|
if (a->sin_port == b->sin_port &&
|
||||||
|
a->sin_addr.s_addr == b->sin_addr.s_addr)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int socket_ready(int sock)
|
||||||
|
{
|
||||||
|
fd_set fds;
|
||||||
|
struct timeval timeout;
|
||||||
|
|
||||||
|
timeout.tv_sec = 0;
|
||||||
|
timeout.tv_usec = 1000;
|
||||||
|
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(sock, &fds);
|
||||||
|
select(sock+1, &fds, NULL, NULL, &timeout);
|
||||||
|
return FD_ISSET(sock, &fds);
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef __JCSOCKET_H_
|
||||||
|
#define __JCSOCKET_H_
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <winsock2.h>
|
||||||
|
#else
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int open_tcp_port(short portno);
|
||||||
|
int open_any_tcp_port(short *portno);
|
||||||
|
int open_any_udp_port(short *portno);
|
||||||
|
int connect_to_host(char *hostname, short portno);
|
||||||
|
int connect_to_addr(struct sockaddr_in *host_addr);
|
||||||
|
int sendall(int sockfd, char *buffer, int bufLen, int flags);
|
||||||
|
int readall(int sockfd, char *buffer, int bufLen, int flags);
|
||||||
|
int addr_eq(struct sockaddr_in *a, struct sockaddr_in *b);
|
||||||
|
int socket_ready(int sock);
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
void bzero(void *s, size_t n);
|
||||||
|
#endif
|
||||||
|
#ifndef WIN32
|
||||||
|
void closesocket(int fd);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,601 @@
|
||||||
|
function varargout = textread(filename, format, varargin)
|
||||||
|
% textread Formatted file read to one or more variables
|
||||||
|
%
|
||||||
|
% Syntax:
|
||||||
|
% [<variable-1> <<,variable-2>> <<,variable-N>> ] = ...
|
||||||
|
% textread( <input-filename>, <format-specifiers> <<,number-of-lines-to-read>> )
|
||||||
|
%
|
||||||
|
% This function is available for task parallel processing.
|
||||||
|
%
|
||||||
|
% ************
|
||||||
|
%
|
||||||
|
% The Star-P M implementation of this function exhibits the same signature and output characteristics as the Matlab
|
||||||
|
% function of the same name.
|
||||||
|
%
|
||||||
|
% For details, please see matlab:textread.
|
||||||
|
%
|
||||||
|
% ************************
|
||||||
|
%
|
||||||
|
%
|
||||||
|
|
||||||
|
% DOC % A
|
||||||
|
if nargin < 2, error('Not enough input arguments.'); end
|
||||||
|
|
||||||
|
if ~ischar(filename), error('Filename must be a string.'); end
|
||||||
|
|
||||||
|
ifExist = exist(filename, 'file');
|
||||||
|
if ifExist ~= 2 && ifExist ~= 4, error('File not found'); end
|
||||||
|
|
||||||
|
fid = fopen(filename, 'r');
|
||||||
|
if fid == -1, error(lasterror()); end;
|
||||||
|
|
||||||
|
formatin = formatread(format);
|
||||||
|
argin = readvarargin(varargin{:});
|
||||||
|
|
||||||
|
|
||||||
|
% Проверка количества исходящих аргументов
|
||||||
|
count = 0;
|
||||||
|
for k = 1:length(formatin),
|
||||||
|
if ~isequal(formatin(k).symbol, '*'), count = count + 1; end;
|
||||||
|
end
|
||||||
|
if count ~= nargout, error('widthber of outputs must match the widthber of unskipped input fields.');end
|
||||||
|
|
||||||
|
% Флаг flag_N - опредиляет сколько раз использовать строку формата
|
||||||
|
% (N или пока не считаем весь файл)
|
||||||
|
flag_N = 1;
|
||||||
|
if ~isempty(argin.N)
|
||||||
|
N = argin.N;
|
||||||
|
else
|
||||||
|
N = 1; flag_N = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
% Пропустить первые N == headerlines линий
|
||||||
|
for i = 1:argin.headerlines
|
||||||
|
text = fgets(fid);
|
||||||
|
end
|
||||||
|
|
||||||
|
% Если строка пустая считать следующую
|
||||||
|
text = fgets(fid);
|
||||||
|
|
||||||
|
t = 1;
|
||||||
|
k = 1;
|
||||||
|
|
||||||
|
maxlen = 1;
|
||||||
|
vararginEmpty = 1;
|
||||||
|
|
||||||
|
while N
|
||||||
|
|
||||||
|
t = 1;
|
||||||
|
if ~isempty(format)
|
||||||
|
if passLine(text, argin)
|
||||||
|
for j = 1:length(formatin)
|
||||||
|
s = formatin(j);
|
||||||
|
|
||||||
|
if s.type == 'c' && isempty(text)
|
||||||
|
while 1
|
||||||
|
text = fgets(fid);
|
||||||
|
if ~ischar(text)
|
||||||
|
fclose(fid);
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
if ~(text(1) == 13)
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% Удалить первые лишние пробелы
|
||||||
|
text = removeAllFirstSpaces(text, argin.delimiter);
|
||||||
|
% Считать следующее слово указанного типа
|
||||||
|
[out, text] = switchType(text, s, argin, fid);
|
||||||
|
% Пропустить слово если установлен параметр *
|
||||||
|
|
||||||
|
if ~isequal(s.symbol, '*')
|
||||||
|
if ~isempty(text) || ~(isempty(out) || isequal(out, {''}))
|
||||||
|
out = setEmptyValue(out, s, argin);
|
||||||
|
if vararginEmpty
|
||||||
|
varargout{t}(1, :) = out;
|
||||||
|
else
|
||||||
|
varargout{t}(end + 1, :) = out;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
t = t + 1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
% Убрать первый символ если он равен delimiter
|
||||||
|
if ~isempty(argin.delimiter) && ~isempty(text) && isa(text, 'char')
|
||||||
|
if find(argin.delimiter == text(1))
|
||||||
|
text = text(2:end);
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
vararginEmpty = 0;
|
||||||
|
end
|
||||||
|
else % Если строка формата не задана читать как double
|
||||||
|
|
||||||
|
if passLine(text, argin)
|
||||||
|
[out, text] = readDoubleArray(text, argin);
|
||||||
|
curmaxlen = maxlen;
|
||||||
|
if length(out) > maxlen, maxlen = length(out); end;
|
||||||
|
for z = 1:k
|
||||||
|
for q = curmaxlen+1:maxlen
|
||||||
|
varargout{1}(z, q) = argin.emptyvalue;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for q = length(out)+1:maxlen
|
||||||
|
out(q) = argin.emptyvalue;
|
||||||
|
end
|
||||||
|
|
||||||
|
varargout{1}(k, :) = out;
|
||||||
|
k = k + 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
text = removeAllFirstSpaces(text, argin.delimiter);
|
||||||
|
% Если строка пустая считать следующую
|
||||||
|
if isempty(text)
|
||||||
|
text = fgets(fid);
|
||||||
|
elseif find(text(1) == [10 13])
|
||||||
|
text = fgets(fid);
|
||||||
|
end
|
||||||
|
% Выйти если не смогли считать строку
|
||||||
|
if ~ischar(text), break; end;
|
||||||
|
|
||||||
|
if flag_N, N = N - 1; end;
|
||||||
|
end
|
||||||
|
|
||||||
|
fclose(fid);
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
% -------- Работа с текстом ---------------------------
|
||||||
|
|
||||||
|
% Удаляет все первые разделители
|
||||||
|
function text = removeAllFirstSpaces(text, delimiter)
|
||||||
|
%if ~isempty(delimiter), return; end;
|
||||||
|
idx = [];
|
||||||
|
for k = 1:length(text)
|
||||||
|
idx = find(text(k) ~= ' ', 1);
|
||||||
|
if ~isempty(idx), break; end;
|
||||||
|
end
|
||||||
|
if ~isempty(idx)
|
||||||
|
text = text(k:end);
|
||||||
|
else
|
||||||
|
text = '';
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% Читает первые n - символов
|
||||||
|
function [word, text] = readCharacters(text, n, fid)
|
||||||
|
word = '';
|
||||||
|
while n
|
||||||
|
if n > length(text)
|
||||||
|
word = [word text(1:end)];
|
||||||
|
n = n - length(text);
|
||||||
|
text = fgets(fid);
|
||||||
|
if ~ischar(text), error(sprintf('Trouble reading characters from file: %s', text)); end
|
||||||
|
else
|
||||||
|
word = [word text(1:n)];
|
||||||
|
text = text(n+1:end);
|
||||||
|
n = 0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% Читает первое слово до разделитель или первые n - символов
|
||||||
|
function [word, text] = readString(text, n, delimiter)
|
||||||
|
if isempty(delimiter), delimiter = [13, 10, 32];
|
||||||
|
else
|
||||||
|
delimiter = [delimiter, 13, 10];
|
||||||
|
end
|
||||||
|
|
||||||
|
word = '';
|
||||||
|
if isempty(n) || n > length(text) , n = length(text); end;
|
||||||
|
for k = 1:n
|
||||||
|
if find(delimiter == text(k))
|
||||||
|
word = text(1:k-1);
|
||||||
|
text = text(k:end);
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
word = text(1:k);
|
||||||
|
text = text(k+1:end);
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
% Читает первые числа до разделителяили или первые n - символов
|
||||||
|
function [word, text] = readNumber(text, n)
|
||||||
|
|
||||||
|
if isempty(text), word = ''; end;
|
||||||
|
|
||||||
|
word = [];
|
||||||
|
if isempty(n) || length(text) < n, n = length(text); end;
|
||||||
|
|
||||||
|
for k = 1:n
|
||||||
|
if text(k) < 48 || text(k) > 57
|
||||||
|
word = text(1:k-1);
|
||||||
|
text = text(k:end);
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
word = text(1:k);
|
||||||
|
text = text(k+1:end);
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
% Читает число с точкой до разделителяили или первые n - символов
|
||||||
|
function [word, text] = readFloat(text, s)
|
||||||
|
|
||||||
|
if isempty(text), word = ''; return; end;
|
||||||
|
|
||||||
|
if isempty(s), s.width = []; s.precision = []; end;
|
||||||
|
|
||||||
|
if isempty(s.width) || length(text) < s.width
|
||||||
|
n = length(text);
|
||||||
|
else
|
||||||
|
n = s.width;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if isempty(s.precision), s.precision = n; end;
|
||||||
|
|
||||||
|
% Чтение знака
|
||||||
|
[sign, text] = getSign(text);
|
||||||
|
if ~isempty(sign), n = n - 1; end;
|
||||||
|
|
||||||
|
point = 0;
|
||||||
|
npoint = 0;
|
||||||
|
word = sign;
|
||||||
|
for k = 1:n
|
||||||
|
if point
|
||||||
|
npoint = npoint + 1;
|
||||||
|
end
|
||||||
|
if text(k) == '.' && ~point
|
||||||
|
point = 1;
|
||||||
|
continue;
|
||||||
|
end
|
||||||
|
if text(k) < 48 || text(k) > 57 || npoint > s.precision
|
||||||
|
word = [word text(1:k-1)];
|
||||||
|
text = text(k:end);
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
word = [word text(1:k)];
|
||||||
|
text = text(k+1:end);
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
% Определяет знак
|
||||||
|
function [sign, text] = getSign(text)
|
||||||
|
if isempty(text), sign = ''; return; end;
|
||||||
|
if text(1) == '+' || text(1) == '-'
|
||||||
|
sign = text(1);
|
||||||
|
text = text(2:end);
|
||||||
|
if isempty(text) || text(1) < 48 || text(1) > 57, error(sprintf('Trouble reading double from file: %s', text)); end;
|
||||||
|
else
|
||||||
|
sign = [];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% 0 - пропустить строку, 1 - обрабатывать
|
||||||
|
function out = passLine(text, argin)
|
||||||
|
|
||||||
|
isdelimiter = 0;
|
||||||
|
if argin.delimiter
|
||||||
|
if ~isempty(find(text == argin.delimiter, 1))
|
||||||
|
isdelimiter = 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
isnewline = 0;
|
||||||
|
if ~isempty(find(text(1) == [10 13], 1))
|
||||||
|
isnewline = 1;
|
||||||
|
end
|
||||||
|
if ~isnewline || isdelimiter
|
||||||
|
out = 1;
|
||||||
|
else
|
||||||
|
out = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% -------- Парс входящих параметров ---------------------------
|
||||||
|
|
||||||
|
% Читает входящие параметры в структуру
|
||||||
|
function argin = readvarargin(varargin)
|
||||||
|
|
||||||
|
|
||||||
|
argin = struct();
|
||||||
|
argin(1).N = [];
|
||||||
|
argin(1).bufsize = 4095;
|
||||||
|
argin(1).commentstyle = [];
|
||||||
|
argin(1).delimiter = '';
|
||||||
|
argin(1).emptyvalue = 0;
|
||||||
|
argin(1).endofline = [];
|
||||||
|
argin(1).expchars = [];
|
||||||
|
argin(1).headerlines = 0;
|
||||||
|
argin(1).whitespace = [];
|
||||||
|
|
||||||
|
if nargin == 0, return; end;
|
||||||
|
|
||||||
|
k = 1;
|
||||||
|
if isnumeric(varargin{1})
|
||||||
|
argin.N = varargin{1};
|
||||||
|
k = k + 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
count = (length(varargin(k:end)) / 2);
|
||||||
|
if floor(count) - count ~= 0, error('Param/value pairs must come in pairs'); end;
|
||||||
|
|
||||||
|
while k < nargin
|
||||||
|
switch varargin{k}
|
||||||
|
|
||||||
|
case 'bufsize'
|
||||||
|
k = k + 1;
|
||||||
|
if isinteger(varargin{k}) && isscalar(varargin{k})
|
||||||
|
argin(1).bufsize = str2double(varargin{k});
|
||||||
|
else
|
||||||
|
error('Buffer size must be a scalar integer.');
|
||||||
|
end
|
||||||
|
|
||||||
|
case 'commentstyle'
|
||||||
|
k = k + 1;
|
||||||
|
switch varargin{k}
|
||||||
|
case 'matlab'
|
||||||
|
argin(1).commentstyle = '%';
|
||||||
|
case 'shell'
|
||||||
|
argin(1).commentstyle = '#';
|
||||||
|
case 'c++'
|
||||||
|
argin(1).commentstyle = '//';
|
||||||
|
otherwise
|
||||||
|
error('Invalid comment style.');
|
||||||
|
end
|
||||||
|
|
||||||
|
case 'delimiter'
|
||||||
|
k = k + 1;
|
||||||
|
switch varargin{k}
|
||||||
|
case '\n'
|
||||||
|
num = 10;
|
||||||
|
case '\r'
|
||||||
|
num = 13;
|
||||||
|
otherwise
|
||||||
|
num = double(varargin{k});
|
||||||
|
end
|
||||||
|
argin(1).delimiter = num;
|
||||||
|
|
||||||
|
case 'emptyvalue'
|
||||||
|
k = k + 1;
|
||||||
|
if isnumeric(varargin{k}) && isscalar(varargin{k})
|
||||||
|
argin(1).emptyvalue = varargin{k};
|
||||||
|
else
|
||||||
|
error('Emptyvalue must be a scalar double.');
|
||||||
|
end
|
||||||
|
|
||||||
|
case 'endofline'
|
||||||
|
k = k + 1;
|
||||||
|
if ischar(varargin{k})
|
||||||
|
argin(1).endofline = varargin{k};
|
||||||
|
else
|
||||||
|
error('endofline must be a scalar double.');
|
||||||
|
end
|
||||||
|
|
||||||
|
case 'expchars'
|
||||||
|
|
||||||
|
case 'headerlines'
|
||||||
|
k = k + 1;
|
||||||
|
if isnumeric(varargin{k}) && isscalar(varargin{k})
|
||||||
|
argin(1).headerlines = varargin{k};
|
||||||
|
else
|
||||||
|
error('Headerlines must be a scalar integer.');
|
||||||
|
end
|
||||||
|
|
||||||
|
case 'whitespace'
|
||||||
|
|
||||||
|
otherwise
|
||||||
|
error('Unknown option');
|
||||||
|
end
|
||||||
|
|
||||||
|
k = k + 1;
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
% Читает строку формата в структуру
|
||||||
|
function R = formatread(format)
|
||||||
|
|
||||||
|
formatType = ['d', 'u', 'f', 's', 'q', 'c'];
|
||||||
|
k = 1;
|
||||||
|
t = 1;
|
||||||
|
s = struct();
|
||||||
|
s(t).type = [];
|
||||||
|
s(t).width = [];
|
||||||
|
s(t).precision = [];
|
||||||
|
s(t).symbol = [];
|
||||||
|
s(t).text = [];
|
||||||
|
|
||||||
|
while ~isempty(format)
|
||||||
|
|
||||||
|
type = [];
|
||||||
|
width = [];
|
||||||
|
precision = [];
|
||||||
|
symbol = [];
|
||||||
|
text = [];
|
||||||
|
|
||||||
|
format = removeAllFirstSpaces(format, '');
|
||||||
|
if format(1) == '%'
|
||||||
|
format = format(2:end);
|
||||||
|
|
||||||
|
|
||||||
|
if format(1) == '*'
|
||||||
|
symbol = '*';
|
||||||
|
format = format(2:end);
|
||||||
|
end;
|
||||||
|
|
||||||
|
[width, format] = readNumber(format, []);
|
||||||
|
if format(1) == '.'
|
||||||
|
format = format(2:end);
|
||||||
|
[precision, format] = readNumber(format, []);
|
||||||
|
end
|
||||||
|
|
||||||
|
type = format(1);
|
||||||
|
format = format(2:end);
|
||||||
|
|
||||||
|
% Check and save correct format
|
||||||
|
idx = find( formatType == type );
|
||||||
|
if isempty(idx)
|
||||||
|
error('Incorrect format');
|
||||||
|
end;
|
||||||
|
|
||||||
|
% Save width
|
||||||
|
if ~isempty(width), width = str2double(width);end;
|
||||||
|
% Save precision
|
||||||
|
if ~isempty(precision), precision = str2double(precision);end;
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
[text, format] = readString(format, [], [' ', '%']);
|
||||||
|
symbol = '*';
|
||||||
|
type = 'r';
|
||||||
|
end
|
||||||
|
|
||||||
|
s(t).type = type;
|
||||||
|
s(t).width = width;
|
||||||
|
s(t).precision = precision;
|
||||||
|
s(t).symbol = symbol;
|
||||||
|
s(t).text = text;
|
||||||
|
|
||||||
|
t = t + 1;
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
R = s;
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
% ------------- Вспомагательные функции --------------------
|
||||||
|
|
||||||
|
function [out, text] = switchType(text, s, argin, fid)
|
||||||
|
|
||||||
|
switch s.type
|
||||||
|
|
||||||
|
case 'd'
|
||||||
|
width = s.width;
|
||||||
|
% Чтение знака числа
|
||||||
|
[sign, text] = getSign(text);
|
||||||
|
if ~isempty(sign), width = width - 1; end;
|
||||||
|
% Чиение числа
|
||||||
|
[word, text] = readNumber(text, width);
|
||||||
|
% Обьеденить знак и число
|
||||||
|
out = [sign word];
|
||||||
|
% Если опция emptyvalue установлена и число пустое то заменить на заданное
|
||||||
|
if ~isempty(out)
|
||||||
|
out = str2double(out);
|
||||||
|
if isequalwithequalnans(out, NaN), error(sprintf('Trouble reading double from file: %s', text)); end;
|
||||||
|
else
|
||||||
|
if ~isempty(text) && isempty(find(text(1) == [13, 10], 1))
|
||||||
|
error(sprintf('Trouble reading integer from file: %s', text));
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
case 'u'
|
||||||
|
if isempty(text) || ~isempty(find(text(1) == [13, 10], 1))
|
||||||
|
out = []; return;
|
||||||
|
end
|
||||||
|
[out, text] = readNumber(text, s.width);
|
||||||
|
% Если опция emptyvalue установлена и число пустое то заменить на заданное
|
||||||
|
if ~isempty(out)
|
||||||
|
out = str2double(out);
|
||||||
|
if isequalwithequalnans(out, NaN), error(sprintf('Trouble reading integer from file: %s', text)); end;
|
||||||
|
else
|
||||||
|
if ~isempty(text) && isempty(find(text(1) == [13, 10], 1))
|
||||||
|
error(sprintf('Trouble reading integer from file: %s', text));
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
case 'f'
|
||||||
|
% Чтение числа
|
||||||
|
[out, text] = readFloat(text, s);
|
||||||
|
% Если опция emptyvalue установлена и число пустое то заменить на заданное
|
||||||
|
if ~isempty(out)
|
||||||
|
out = str2double(out);
|
||||||
|
if isequalwithequalnans(out, NaN), error(sprintf('Trouble reading double from file: %s', text)); end;
|
||||||
|
else
|
||||||
|
if ~isempty(text) && isempty(find(text(1) == [13, 10], 1))
|
||||||
|
error(sprintf('Trouble reading integer from file: %s', text));
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
case 's'
|
||||||
|
[word, text] = readString(text, s.width, argin.delimiter);
|
||||||
|
if isempty(word)
|
||||||
|
out = {''};
|
||||||
|
else
|
||||||
|
out = {word};
|
||||||
|
end
|
||||||
|
|
||||||
|
case 'q'
|
||||||
|
|
||||||
|
case 'c'
|
||||||
|
n = 1;
|
||||||
|
if ~isempty(s.width), n = s.width; end;
|
||||||
|
[word, text] = readCharacters(text, n, fid);
|
||||||
|
out = word(:);
|
||||||
|
|
||||||
|
case 'r'
|
||||||
|
[out, text] = readCharacters(text, length(s.text));
|
||||||
|
if ~isequal(out, s.text), error('Trouble reading characters from file'); end;
|
||||||
|
|
||||||
|
otherwise
|
||||||
|
error('Error');
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function out = setEmptyValue(text, s, argin)
|
||||||
|
out = text;
|
||||||
|
if isempty(text)
|
||||||
|
if find(['d', 'u', 'f'] == s.type)
|
||||||
|
out = argin.emptyvalue;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function [out, text] = readDoubleArray(text, argin)
|
||||||
|
|
||||||
|
if isempty(text); out = []; return; end;
|
||||||
|
t = 1;
|
||||||
|
while isempty(find(text(1) == [13 10], 1))
|
||||||
|
% Чтение знака
|
||||||
|
[sign, text] = getSign(text);
|
||||||
|
% Чтение числа
|
||||||
|
[word, text] = readFloat(text, []);
|
||||||
|
% Обьеденить знак и число
|
||||||
|
word = [sign word];
|
||||||
|
% Если опция emptyvalue установлена и число пустое то заменить на заданное
|
||||||
|
if ~isempty(argin.emptyvalue) && isempty(word)
|
||||||
|
out(t) = argin.emptyvalue;
|
||||||
|
else
|
||||||
|
out(t) = str2double(word);
|
||||||
|
if isequalwithequalnans(out(t), NaN), error('Trouble reading integer from file'); end;
|
||||||
|
end
|
||||||
|
|
||||||
|
% Убрать первый символ если он равен delimiter
|
||||||
|
if ~isempty(argin.delimiter) && ~isempty(text)
|
||||||
|
if find(argin.delimiter == text(1))
|
||||||
|
text = text(2:end);
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
t = t + 1;
|
||||||
|
if isempty(text); break; end;
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,164 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <sys/timeb.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "dtypes.h"
|
||||||
|
#include "timefuncs.h"
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
double tvals2float(struct tm *t, struct timeb *tstruct)
|
||||||
|
{
|
||||||
|
return (double)t->tm_hour * 3600 + (double)t->tm_min * 60 +
|
||||||
|
(double)t->tm_sec + (double)tstruct->millitm/1.0e3;
|
||||||
|
}
|
||||||
|
|
||||||
|
double floattime()
|
||||||
|
{
|
||||||
|
struct timeb tstruct;
|
||||||
|
|
||||||
|
ftime(&tstruct);
|
||||||
|
return (double)tstruct.time + (double)tstruct.millitm/1.0e3;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
double tv2float(struct timeval *tv)
|
||||||
|
{
|
||||||
|
return (double)tv->tv_sec + (double)tv->tv_usec/1.0e6;
|
||||||
|
}
|
||||||
|
|
||||||
|
double diff_time(struct timeval *tv1, struct timeval *tv2)
|
||||||
|
{
|
||||||
|
return tv2float(tv1) - tv2float(tv2);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// return as many bits of system randomness as we can get our hands on
|
||||||
|
u_int64_t i64time()
|
||||||
|
{
|
||||||
|
u_int64_t a;
|
||||||
|
#ifdef WIN32
|
||||||
|
struct timeb tstruct;
|
||||||
|
ftime(&tstruct);
|
||||||
|
a = (((u_int64_t)tstruct.time)<<32) + (u_int64_t)tstruct.millitm;
|
||||||
|
#else
|
||||||
|
struct timeval now;
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
a = (((u_int64_t)now.tv_sec)<<32) + (u_int64_t)now.tv_usec;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
double clock_now()
|
||||||
|
{
|
||||||
|
#ifdef WIN32
|
||||||
|
return floattime();
|
||||||
|
#else
|
||||||
|
struct timeval now;
|
||||||
|
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
return tv2float(&now);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef LINUX
|
||||||
|
static char *wdaystr[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
|
||||||
|
static char *monthstr[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug",
|
||||||
|
"Sep","Oct","Nov","Dec"};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void timestring(double seconds, char *buffer, size_t len)
|
||||||
|
{
|
||||||
|
time_t tme = (time_t)seconds;
|
||||||
|
char *fmt = "%c"; /* needed to suppress GCC warning */
|
||||||
|
|
||||||
|
#ifdef LINUX
|
||||||
|
struct tm tm;
|
||||||
|
|
||||||
|
localtime_r(&tme, &tm);
|
||||||
|
strftime(buffer, len, fmt, &tm);
|
||||||
|
#else
|
||||||
|
struct tm *tm;
|
||||||
|
int hr;
|
||||||
|
|
||||||
|
tm = localtime(&tme);
|
||||||
|
hr = tm->tm_hour;
|
||||||
|
if (hr > 12) hr -= 12;
|
||||||
|
if (hr == 0) hr = 12;
|
||||||
|
snprintf(buffer, len, "%s %02d %s %d %02d:%02d:%02d %s %s",
|
||||||
|
wdaystr[tm->tm_wday], tm->tm_mday, monthstr[tm->tm_mon],
|
||||||
|
tm->tm_year+1900, hr, tm->tm_min, tm->tm_sec,
|
||||||
|
tm->tm_hour>11 ? "PM" : "AM", "");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LINUX
|
||||||
|
extern char *strptime(const char *s, const char *format, struct tm *tm);
|
||||||
|
double parsetime(char *str)
|
||||||
|
{
|
||||||
|
char *fmt = "%c"; /* needed to suppress GCC warning */
|
||||||
|
char *res;
|
||||||
|
time_t t;
|
||||||
|
struct tm tm;
|
||||||
|
|
||||||
|
res = strptime(str, fmt, &tm);
|
||||||
|
if (res != NULL) {
|
||||||
|
t = mktime(&tm);
|
||||||
|
if (t == ((time_t)-1))
|
||||||
|
return -1;
|
||||||
|
return (double)t;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// TODO
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void sleep_ms(int ms)
|
||||||
|
{
|
||||||
|
if (ms == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
Sleep(ms);
|
||||||
|
#else
|
||||||
|
struct timeval timeout;
|
||||||
|
|
||||||
|
timeout.tv_sec = ms/1000;
|
||||||
|
timeout.tv_usec = (ms % 1000) * 1000;
|
||||||
|
select(0, NULL, NULL, NULL, &timeout);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void timeparts(int32_t *buf, double t)
|
||||||
|
{
|
||||||
|
time_t tme = (time_t)t;
|
||||||
|
|
||||||
|
#ifndef WIN32
|
||||||
|
struct tm tm;
|
||||||
|
localtime_r(&tme, &tm);
|
||||||
|
tm.tm_year += 1900;
|
||||||
|
memcpy(buf, (char*)&tm, sizeof(struct tm));
|
||||||
|
#else
|
||||||
|
struct tm *tm;
|
||||||
|
|
||||||
|
tm = localtime(&tme);
|
||||||
|
tm->tm_year += 1900;
|
||||||
|
memcpy(buf, (char*)tm, sizeof(struct tm));
|
||||||
|
#endif
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
#ifndef __TIMEFUNCS_H_
|
||||||
|
#define __TIMEFUNCS_H_
|
||||||
|
|
||||||
|
u_int64_t i64time();
|
||||||
|
double clock_now();
|
||||||
|
void timestring(double seconds, char *buffer, size_t len);
|
||||||
|
double parsetime(char *str);
|
||||||
|
void sleep_ms(int ms);
|
||||||
|
void timeparts(int32_t *buf, double t);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,19 @@
|
||||||
|
% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов
|
||||||
|
% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов
|
||||||
|
% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов
|
||||||
|
% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов
|
||||||
|
% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов
|
||||||
|
% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов
|
||||||
|
% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов
|
||||||
|
% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов
|
||||||
|
% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов
|
||||||
|
% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов
|
||||||
|
% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов
|
||||||
|
% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов
|
||||||
|
% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов
|
||||||
|
% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов
|
||||||
|
% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов
|
||||||
|
% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов
|
||||||
|
% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов
|
||||||
|
% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка количества исходящих аргументов% Проверка к
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#include "llt.h"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
llt_init();
|
||||||
|
|
||||||
|
test_dblprint();
|
||||||
|
test_operators();
|
||||||
|
|
||||||
|
/*
|
||||||
|
char *buf = malloc(20000);
|
||||||
|
char *buf2 = malloc(20000);
|
||||||
|
FILE *f = fopen("textread.m","rb");
|
||||||
|
int i=0;
|
||||||
|
while (!feof(f))
|
||||||
|
buf[i++] = fgetc(f);
|
||||||
|
buf[i-1] = '\0';
|
||||||
|
int len = i-1;
|
||||||
|
double t0 = clock_now();
|
||||||
|
int j=0;
|
||||||
|
for(i=0; i < 20000; i++) {
|
||||||
|
//j+=u8_charnum(buf,len);
|
||||||
|
u8_reverse(buf2, buf, len);
|
||||||
|
}
|
||||||
|
printf("textread took %.4f sec (%d)\n", clock_now()-t0, j);
|
||||||
|
|
||||||
|
FILE *f2 = fopen("u8.txt","rb");
|
||||||
|
i=0;
|
||||||
|
while (!feof(f2))
|
||||||
|
buf[i++] = fgetc(f2);
|
||||||
|
buf[i-1] = '\0';
|
||||||
|
len = i-1;
|
||||||
|
t0 = clock_now();
|
||||||
|
j=0;
|
||||||
|
for(i=0; i < 20000; i++) {
|
||||||
|
//j+=u8_charnum(buf,len);
|
||||||
|
u8_reverse(buf2, buf, len);
|
||||||
|
}
|
||||||
|
printf("u8 took %.4f sec (%d)\n\n", clock_now()-t0, j);
|
||||||
|
*/
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prettycplx(double r, double i)
|
||||||
|
{
|
||||||
|
char str[64];
|
||||||
|
snprint_cplx(str, sizeof(str), r, i, 0, 16, 3, 10, 1);
|
||||||
|
fputs(str, stdout);
|
||||||
|
fputc('\n', stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prettyreal(double r)
|
||||||
|
{
|
||||||
|
char str[64];
|
||||||
|
snprint_real(str, sizeof(str), r, 0, 16, 3, 10);
|
||||||
|
fputs(str, stdout);
|
||||||
|
fputc('\n', stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_dblprint()
|
||||||
|
{
|
||||||
|
char str[64];
|
||||||
|
|
||||||
|
dbl_tolerance(1e-12);
|
||||||
|
|
||||||
|
prettycplx(0,0);
|
||||||
|
prettycplx(1,0);
|
||||||
|
prettycplx(0,1);
|
||||||
|
prettycplx(1,1);
|
||||||
|
prettycplx(-1,0);
|
||||||
|
prettycplx(0,-1);
|
||||||
|
prettycplx(1,-1);
|
||||||
|
prettycplx(-1,1);
|
||||||
|
prettycplx(-1,-1);
|
||||||
|
prettycplx(2,0);
|
||||||
|
prettycplx(0,2);
|
||||||
|
prettycplx(2,2);
|
||||||
|
prettycplx(-2,0);
|
||||||
|
prettycplx(0,-2);
|
||||||
|
prettycplx(2,-2);
|
||||||
|
prettycplx(-2,2);
|
||||||
|
prettycplx(-2,-2);
|
||||||
|
|
||||||
|
prettyreal(1.5);
|
||||||
|
prettyreal(1.1);
|
||||||
|
prettyreal(1.1e-100);
|
||||||
|
prettyreal(1.1e20);
|
||||||
|
prettyreal(123456789);
|
||||||
|
prettyreal(1234567890);
|
||||||
|
prettyreal(12345678901);
|
||||||
|
prettyreal(-12345678901);
|
||||||
|
prettyreal(12345678901223);
|
||||||
|
prettyreal(-12345678901223);
|
||||||
|
prettyreal(.02);
|
||||||
|
prettyreal(.002);
|
||||||
|
prettyreal(.0002);
|
||||||
|
prettyreal(-.0002);
|
||||||
|
prettyreal(.00002);
|
||||||
|
prettyreal(-.00002);
|
||||||
|
|
||||||
|
prettyreal(1.0/0);
|
||||||
|
prettyreal(-1.0/0);
|
||||||
|
prettyreal(strtod("nan",NULL));
|
||||||
|
prettyreal(0.0/0);
|
||||||
|
prettyreal(-0.0/0);
|
||||||
|
|
||||||
|
prettyreal(DBL_EPSILON);
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#include "llt.h"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
llt_init();
|
||||||
|
|
||||||
|
test_dblprint();
|
||||||
|
test_operators();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prettycplx(double r, double i)
|
||||||
|
{
|
||||||
|
char str[64];
|
||||||
|
snprint_cplx(str, sizeof(str), r, i, 0, 16, 3, 10, 1);
|
||||||
|
fputs(str, stdout);
|
||||||
|
fputc('\n', stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prettyreal(double r)
|
||||||
|
{
|
||||||
|
char str[64];
|
||||||
|
snprint_real(str, sizeof(str), r, 0, 16, 3, 10);
|
||||||
|
fputs(str, stdout);
|
||||||
|
fputc('\n', stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_dblprint()
|
||||||
|
{
|
||||||
|
char str[64];
|
||||||
|
|
||||||
|
dbl_tolerance(1e-12);
|
||||||
|
|
||||||
|
prettycplx(0,0);
|
||||||
|
prettycplx(1,0);
|
||||||
|
prettycplx(0,1);
|
||||||
|
prettycplx(1,1);
|
||||||
|
prettycplx(-1,0);
|
||||||
|
prettycplx(0,-1);
|
||||||
|
prettycplx(1,-1);
|
||||||
|
prettycplx(-1,1);
|
||||||
|
prettycplx(-1,-1);
|
||||||
|
prettycplx(2,0);
|
||||||
|
prettycplx(0,2);
|
||||||
|
prettycplx(2,2);
|
||||||
|
prettycplx(-2,0);
|
||||||
|
prettycplx(0,-2);
|
||||||
|
prettycplx(2,-2);
|
||||||
|
prettycplx(-2,2);
|
||||||
|
prettycplx(-2,-2);
|
||||||
|
|
||||||
|
prettyreal(1.5);
|
||||||
|
prettyreal(1.1);
|
||||||
|
prettyreal(1.1e-100);
|
||||||
|
prettyreal(1.1e20);
|
||||||
|
prettyreal(123456789);
|
||||||
|
prettyreal(1234567890);
|
||||||
|
prettyreal(12345678901);
|
||||||
|
prettyreal(-12345678901);
|
||||||
|
prettyreal(12345678901223);
|
||||||
|
prettyreal(-12345678901223);
|
||||||
|
prettyreal(.02);
|
||||||
|
prettyreal(.002);
|
||||||
|
prettyreal(.0002);
|
||||||
|
prettyreal(-.0002);
|
||||||
|
prettyreal(.00002);
|
||||||
|
prettyreal(-.00002);
|
||||||
|
|
||||||
|
prettyreal(1.0/0);
|
||||||
|
prettyreal(-1.0/0);
|
||||||
|
prettyreal(strtod("nan",NULL));
|
||||||
|
prettyreal(0.0/0);
|
||||||
|
prettyreal(-0.0/0);
|
||||||
|
|
||||||
|
prettyreal(DBL_EPSILON);
|
||||||
|
}
|
|
@ -0,0 +1,728 @@
|
||||||
|
/*
|
||||||
|
Basic UTF-8 manipulation routines
|
||||||
|
by Jeff Bezanson
|
||||||
|
placed in the public domain Fall 2005
|
||||||
|
|
||||||
|
This code is designed to provide the utilities you need to manipulate
|
||||||
|
UTF-8 as an internal string encoding. These functions do not perform the
|
||||||
|
error checking normally needed when handling UTF-8 data, so if you happen
|
||||||
|
to be from the Unicode Consortium you will want to flay me alive.
|
||||||
|
I do this because error checking can be performed at the boundaries (I/O),
|
||||||
|
with these routines reserved for higher performance on data known to be
|
||||||
|
valid.
|
||||||
|
A UTF-8 validation routine is included.
|
||||||
|
*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#include <wctype.h>
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <malloc.h>
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#else
|
||||||
|
#include <alloca.h>
|
||||||
|
#endif
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "utf8.h"
|
||||||
|
|
||||||
|
static const u_int32_t offsetsFromUTF8[6] = {
|
||||||
|
0x00000000UL, 0x00003080UL, 0x000E2080UL,
|
||||||
|
0x03C82080UL, 0xFA082080UL, 0x82082080UL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char trailingBytesForUTF8[256] = {
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||||
|
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
|
||||||
|
};
|
||||||
|
|
||||||
|
/* returns length of next utf-8 sequence */
|
||||||
|
size_t u8_seqlen(const char *s)
|
||||||
|
{
|
||||||
|
return trailingBytesForUTF8[(unsigned int)(unsigned char)s[0]] + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* returns the # of bytes needed to encode a certain character
|
||||||
|
0 means the character cannot (or should not) be encoded. */
|
||||||
|
size_t u8_charlen(u_int32_t ch)
|
||||||
|
{
|
||||||
|
if (ch < 0x80)
|
||||||
|
return 1;
|
||||||
|
else if (ch < 0x800)
|
||||||
|
return 2;
|
||||||
|
else if (ch < 0x10000)
|
||||||
|
return 3;
|
||||||
|
else if (ch < 0x110000)
|
||||||
|
return 4;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t u8_codingsize(u_int32_t *wcstr, size_t n)
|
||||||
|
{
|
||||||
|
size_t i, c=0;
|
||||||
|
|
||||||
|
for(i=0; i < n; i++)
|
||||||
|
c += u8_charlen(wcstr[i]);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* conversions without error checking
|
||||||
|
only works for valid UTF-8, i.e. no 5- or 6-byte sequences
|
||||||
|
srcsz = source size in bytes
|
||||||
|
sz = dest size in # of wide characters
|
||||||
|
|
||||||
|
returns # characters converted
|
||||||
|
if sz = srcsz+1 (i.e. 4*srcsz+4 bytes), there will always be enough space.
|
||||||
|
*/
|
||||||
|
size_t u8_toucs(u_int32_t *dest, size_t sz, const char *src, size_t srcsz)
|
||||||
|
{
|
||||||
|
u_int32_t ch;
|
||||||
|
const char *src_end = src + srcsz;
|
||||||
|
size_t nb;
|
||||||
|
size_t i=0;
|
||||||
|
|
||||||
|
if (sz == 0 || srcsz == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while (i < sz) {
|
||||||
|
nb = trailingBytesForUTF8[(unsigned char)*src];
|
||||||
|
if (src + nb >= src_end)
|
||||||
|
break;
|
||||||
|
ch = 0;
|
||||||
|
switch (nb) {
|
||||||
|
/* these fall through deliberately */
|
||||||
|
case 3: ch += (unsigned char)*src++; ch <<= 6;
|
||||||
|
case 2: ch += (unsigned char)*src++; ch <<= 6;
|
||||||
|
case 1: ch += (unsigned char)*src++; ch <<= 6;
|
||||||
|
case 0: ch += (unsigned char)*src++;
|
||||||
|
}
|
||||||
|
ch -= offsetsFromUTF8[nb];
|
||||||
|
dest[i++] = ch;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* srcsz = number of source characters
|
||||||
|
sz = size of dest buffer in bytes
|
||||||
|
|
||||||
|
returns # bytes stored in dest
|
||||||
|
the destination string will never be bigger than the source string.
|
||||||
|
*/
|
||||||
|
size_t u8_toutf8(char *dest, size_t sz, const u_int32_t *src, size_t srcsz)
|
||||||
|
{
|
||||||
|
u_int32_t ch;
|
||||||
|
size_t i = 0;
|
||||||
|
char *dest0 = dest;
|
||||||
|
char *dest_end = dest + sz;
|
||||||
|
|
||||||
|
while (i < srcsz) {
|
||||||
|
ch = src[i];
|
||||||
|
if (ch < 0x80) {
|
||||||
|
if (dest >= dest_end)
|
||||||
|
break;
|
||||||
|
*dest++ = (char)ch;
|
||||||
|
}
|
||||||
|
else if (ch < 0x800) {
|
||||||
|
if (dest >= dest_end-1)
|
||||||
|
break;
|
||||||
|
*dest++ = (ch>>6) | 0xC0;
|
||||||
|
*dest++ = (ch & 0x3F) | 0x80;
|
||||||
|
}
|
||||||
|
else if (ch < 0x10000) {
|
||||||
|
if (dest >= dest_end-2)
|
||||||
|
break;
|
||||||
|
*dest++ = (ch>>12) | 0xE0;
|
||||||
|
*dest++ = ((ch>>6) & 0x3F) | 0x80;
|
||||||
|
*dest++ = (ch & 0x3F) | 0x80;
|
||||||
|
}
|
||||||
|
else if (ch < 0x110000) {
|
||||||
|
if (dest >= dest_end-3)
|
||||||
|
break;
|
||||||
|
*dest++ = (ch>>18) | 0xF0;
|
||||||
|
*dest++ = ((ch>>12) & 0x3F) | 0x80;
|
||||||
|
*dest++ = ((ch>>6) & 0x3F) | 0x80;
|
||||||
|
*dest++ = (ch & 0x3F) | 0x80;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return (dest-dest0);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t u8_wc_toutf8(char *dest, u_int32_t ch)
|
||||||
|
{
|
||||||
|
if (ch < 0x80) {
|
||||||
|
dest[0] = (char)ch;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (ch < 0x800) {
|
||||||
|
dest[0] = (ch>>6) | 0xC0;
|
||||||
|
dest[1] = (ch & 0x3F) | 0x80;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if (ch < 0x10000) {
|
||||||
|
dest[0] = (ch>>12) | 0xE0;
|
||||||
|
dest[1] = ((ch>>6) & 0x3F) | 0x80;
|
||||||
|
dest[2] = (ch & 0x3F) | 0x80;
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
if (ch < 0x110000) {
|
||||||
|
dest[0] = (ch>>18) | 0xF0;
|
||||||
|
dest[1] = ((ch>>12) & 0x3F) | 0x80;
|
||||||
|
dest[2] = ((ch>>6) & 0x3F) | 0x80;
|
||||||
|
dest[3] = (ch & 0x3F) | 0x80;
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* charnum => byte offset */
|
||||||
|
size_t u8_offset(const char *s, size_t charnum)
|
||||||
|
{
|
||||||
|
size_t i=0;
|
||||||
|
|
||||||
|
while (charnum > 0) {
|
||||||
|
if (s[i++] & 0x80) {
|
||||||
|
(void)(isutf(s[++i]) || isutf(s[++i]) || ++i);
|
||||||
|
}
|
||||||
|
charnum--;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* byte offset => charnum */
|
||||||
|
size_t u8_charnum(const char *s, size_t offset)
|
||||||
|
{
|
||||||
|
size_t charnum = 0, i=0;
|
||||||
|
|
||||||
|
while (i < offset) {
|
||||||
|
if (s[i++] & 0x80) {
|
||||||
|
(void)(isutf(s[++i]) || isutf(s[++i]) || ++i);
|
||||||
|
}
|
||||||
|
charnum++;
|
||||||
|
}
|
||||||
|
return charnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* number of characters in NUL-terminated string */
|
||||||
|
size_t u8_strlen(const char *s)
|
||||||
|
{
|
||||||
|
size_t count = 0;
|
||||||
|
size_t i = 0, lasti;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
lasti = i;
|
||||||
|
while (s[i] > 0)
|
||||||
|
i++;
|
||||||
|
count += (i-lasti);
|
||||||
|
if (s[i++]==0) break;
|
||||||
|
(void)(isutf(s[++i]) || isutf(s[++i]) || ++i);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t u8_strwidth(const char *s)
|
||||||
|
{
|
||||||
|
u_int32_t ch;
|
||||||
|
size_t nb, tot=0;
|
||||||
|
int w;
|
||||||
|
signed char sc;
|
||||||
|
|
||||||
|
while ((sc = (signed char)*s) != 0) {
|
||||||
|
if (sc >= 0) {
|
||||||
|
s++;
|
||||||
|
if (sc) tot++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nb = trailingBytesForUTF8[(unsigned char)sc];
|
||||||
|
ch = 0;
|
||||||
|
switch (nb) {
|
||||||
|
/* these fall through deliberately */
|
||||||
|
case 3: ch += (unsigned char)*s++; ch <<= 6;
|
||||||
|
case 2: ch += (unsigned char)*s++; ch <<= 6;
|
||||||
|
case 1: ch += (unsigned char)*s++; ch <<= 6;
|
||||||
|
case 0: ch += (unsigned char)*s++;
|
||||||
|
}
|
||||||
|
ch -= offsetsFromUTF8[nb];
|
||||||
|
w = wcwidth(ch);
|
||||||
|
if (w > 0) tot += w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reads the next utf-8 sequence out of a string, updating an index */
|
||||||
|
u_int32_t u8_nextchar(const char *s, size_t *i)
|
||||||
|
{
|
||||||
|
u_int32_t ch = 0;
|
||||||
|
size_t sz = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
ch <<= 6;
|
||||||
|
ch += (unsigned char)s[(*i)];
|
||||||
|
sz++;
|
||||||
|
} while (s[*i] && (++(*i)) && !isutf(s[*i]));
|
||||||
|
ch -= offsetsFromUTF8[sz-1];
|
||||||
|
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* next character without NUL character terminator */
|
||||||
|
u_int32_t u8_nextmemchar(const char *s, size_t *i)
|
||||||
|
{
|
||||||
|
u_int32_t ch = 0;
|
||||||
|
size_t sz = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
ch <<= 6;
|
||||||
|
ch += (unsigned char)s[(*i)++];
|
||||||
|
sz++;
|
||||||
|
} while (!isutf(s[*i]));
|
||||||
|
ch -= offsetsFromUTF8[sz-1];
|
||||||
|
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
void u8_inc(const char *s, size_t *i)
|
||||||
|
{
|
||||||
|
(void)(isutf(s[++(*i)]) || isutf(s[++(*i)]) || isutf(s[++(*i)]) || ++(*i));
|
||||||
|
}
|
||||||
|
|
||||||
|
void u8_dec(const char *s, size_t *i)
|
||||||
|
{
|
||||||
|
(void)(isutf(s[--(*i)]) || isutf(s[--(*i)]) || isutf(s[--(*i)]) || --(*i));
|
||||||
|
}
|
||||||
|
|
||||||
|
int octal_digit(char c)
|
||||||
|
{
|
||||||
|
return (c >= '0' && c <= '7');
|
||||||
|
}
|
||||||
|
|
||||||
|
int hex_digit(char c)
|
||||||
|
{
|
||||||
|
return ((c >= '0' && c <= '9') ||
|
||||||
|
(c >= 'A' && c <= 'F') ||
|
||||||
|
(c >= 'a' && c <= 'f'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* assumes that src points to the character after a backslash
|
||||||
|
returns number of input characters processed */
|
||||||
|
int u8_read_escape_sequence(const char *str, u_int32_t *dest)
|
||||||
|
{
|
||||||
|
u_int32_t ch;
|
||||||
|
char digs[9]="\0\0\0\0\0\0\0\0\0";
|
||||||
|
int dno=0, i=1;
|
||||||
|
|
||||||
|
ch = (u_int32_t)str[0]; /* take literal character */
|
||||||
|
if (str[0] == 'n')
|
||||||
|
ch = L'\n';
|
||||||
|
else if (str[0] == 't')
|
||||||
|
ch = L'\t';
|
||||||
|
else if (str[0] == 'r')
|
||||||
|
ch = L'\r';
|
||||||
|
else if (str[0] == 'b')
|
||||||
|
ch = L'\b';
|
||||||
|
else if (str[0] == 'f')
|
||||||
|
ch = L'\f';
|
||||||
|
else if (str[0] == 'v')
|
||||||
|
ch = L'\v';
|
||||||
|
else if (str[0] == 'a')
|
||||||
|
ch = L'\a';
|
||||||
|
else if (octal_digit(str[0])) {
|
||||||
|
i = 0;
|
||||||
|
do {
|
||||||
|
digs[dno++] = str[i++];
|
||||||
|
} while (octal_digit(str[i]) && dno < 3);
|
||||||
|
ch = strtol(digs, NULL, 8);
|
||||||
|
}
|
||||||
|
else if (str[0] == 'x') {
|
||||||
|
while (hex_digit(str[i]) && dno < 2) {
|
||||||
|
digs[dno++] = str[i++];
|
||||||
|
}
|
||||||
|
if (dno > 0)
|
||||||
|
ch = strtol(digs, NULL, 16);
|
||||||
|
}
|
||||||
|
else if (str[0] == 'u') {
|
||||||
|
while (hex_digit(str[i]) && dno < 4) {
|
||||||
|
digs[dno++] = str[i++];
|
||||||
|
}
|
||||||
|
if (dno > 0)
|
||||||
|
ch = strtol(digs, NULL, 16);
|
||||||
|
}
|
||||||
|
else if (str[0] == 'U') {
|
||||||
|
while (hex_digit(str[i]) && dno < 8) {
|
||||||
|
digs[dno++] = str[i++];
|
||||||
|
}
|
||||||
|
if (dno > 0)
|
||||||
|
ch = strtol(digs, NULL, 16);
|
||||||
|
}
|
||||||
|
*dest = ch;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* convert a string with literal \uxxxx or \Uxxxxxxxx characters to UTF-8
|
||||||
|
example: u8_unescape(mybuf, 256, "hello\\u220e")
|
||||||
|
note the double backslash is needed if called on a C string literal */
|
||||||
|
size_t u8_unescape(char *buf, size_t sz, const char *src)
|
||||||
|
{
|
||||||
|
size_t c=0, amt;
|
||||||
|
u_int32_t ch;
|
||||||
|
char temp[4];
|
||||||
|
|
||||||
|
while (*src && c < sz) {
|
||||||
|
if (*src == '\\') {
|
||||||
|
src++;
|
||||||
|
amt = u8_read_escape_sequence(src, &ch);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ch = (u_int32_t)*src;
|
||||||
|
amt = 1;
|
||||||
|
}
|
||||||
|
src += amt;
|
||||||
|
amt = u8_wc_toutf8(temp, ch);
|
||||||
|
if (amt > sz-c)
|
||||||
|
break;
|
||||||
|
memcpy(&buf[c], temp, amt);
|
||||||
|
c += amt;
|
||||||
|
}
|
||||||
|
if (c < sz)
|
||||||
|
buf[c] = '\0';
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int buf_put2c(char *buf, const char *src)
|
||||||
|
{
|
||||||
|
buf[0] = src[0];
|
||||||
|
buf[1] = src[1];
|
||||||
|
buf[2] = '\0';
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int u8_escape_wchar(char *buf, size_t sz, u_int32_t ch)
|
||||||
|
{
|
||||||
|
assert(sz > 2);
|
||||||
|
if (ch == L'\n')
|
||||||
|
return buf_put2c(buf, "\\n");
|
||||||
|
else if (ch == L'\t')
|
||||||
|
return buf_put2c(buf, "\\t");
|
||||||
|
else if (ch == L'\r')
|
||||||
|
return buf_put2c(buf, "\\r");
|
||||||
|
else if (ch == L'\b')
|
||||||
|
return buf_put2c(buf, "\\b");
|
||||||
|
else if (ch == L'\f')
|
||||||
|
return buf_put2c(buf, "\\f");
|
||||||
|
else if (ch == L'\v')
|
||||||
|
return buf_put2c(buf, "\\v");
|
||||||
|
else if (ch == L'\a')
|
||||||
|
return buf_put2c(buf, "\\a");
|
||||||
|
else if (ch == L'\\')
|
||||||
|
return buf_put2c(buf, "\\\\");
|
||||||
|
else if (ch < 32 || ch == 0x7f)
|
||||||
|
return snprintf(buf, sz, "\\x%.2hhX", (unsigned char)ch);
|
||||||
|
else if (ch > 0xFFFF)
|
||||||
|
return snprintf(buf, sz, "\\U%.8X", (u_int32_t)ch);
|
||||||
|
else if (ch >= 0x80)
|
||||||
|
return snprintf(buf, sz, "\\u%.4hX", (unsigned short)ch);
|
||||||
|
|
||||||
|
buf[0] = (char)ch;
|
||||||
|
buf[1] = '\0';
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t u8_escape(char *buf, size_t sz, const char *src, size_t *pi, size_t end,
|
||||||
|
int escape_quotes, int ascii)
|
||||||
|
{
|
||||||
|
size_t i = *pi, i0;
|
||||||
|
u_int32_t ch;
|
||||||
|
char *start = buf;
|
||||||
|
char *blim = start + sz-11;
|
||||||
|
assert(sz > 11);
|
||||||
|
|
||||||
|
while (i<end && buf<blim) {
|
||||||
|
// sz-11: leaves room for longest escape sequence
|
||||||
|
if (escape_quotes && src[i] == '"') {
|
||||||
|
buf += buf_put2c(buf, "\\\"");
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
else if (src[i] == '\\') {
|
||||||
|
buf += buf_put2c(buf, "\\\\");
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
i0 = i;
|
||||||
|
ch = u8_nextmemchar(src, &i);
|
||||||
|
if (ascii || !iswprint((wint_t)ch)) {
|
||||||
|
buf += u8_escape_wchar(buf, sz - (buf-start), ch);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
i = i0;
|
||||||
|
do {
|
||||||
|
*buf++ = src[i++];
|
||||||
|
} while (!isutf(src[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*buf++ = '\0';
|
||||||
|
*pi = i;
|
||||||
|
return (buf-start);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *u8_strchr(const char *s, u_int32_t ch, size_t *charn)
|
||||||
|
{
|
||||||
|
size_t i = 0, lasti=0;
|
||||||
|
u_int32_t c;
|
||||||
|
|
||||||
|
*charn = 0;
|
||||||
|
while (s[i]) {
|
||||||
|
c = u8_nextchar(s, &i);
|
||||||
|
if (c == ch) {
|
||||||
|
/* it's const for us, but not necessarily the caller */
|
||||||
|
return (char*)&s[lasti];
|
||||||
|
}
|
||||||
|
lasti = i;
|
||||||
|
(*charn)++;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *u8_memchr(const char *s, u_int32_t ch, size_t sz, size_t *charn)
|
||||||
|
{
|
||||||
|
size_t i = 0, lasti=0;
|
||||||
|
u_int32_t c;
|
||||||
|
int csz;
|
||||||
|
|
||||||
|
*charn = 0;
|
||||||
|
while (i < sz) {
|
||||||
|
c = csz = 0;
|
||||||
|
do {
|
||||||
|
c <<= 6;
|
||||||
|
c += (unsigned char)s[i++];
|
||||||
|
csz++;
|
||||||
|
} while (i < sz && !isutf(s[i]));
|
||||||
|
c -= offsetsFromUTF8[csz-1];
|
||||||
|
|
||||||
|
if (c == ch) {
|
||||||
|
return (char*)&s[lasti];
|
||||||
|
}
|
||||||
|
lasti = i;
|
||||||
|
(*charn)++;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *u8_memrchr(const char *s, u_int32_t ch, size_t sz)
|
||||||
|
{
|
||||||
|
size_t i = sz-1, tempi=0;
|
||||||
|
u_int32_t c;
|
||||||
|
|
||||||
|
if (sz == 0) return NULL;
|
||||||
|
|
||||||
|
while (i && !isutf(s[i])) i--;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
tempi = i;
|
||||||
|
c = u8_nextmemchar(s, &tempi);
|
||||||
|
if (c == ch) {
|
||||||
|
return (char*)&s[i];
|
||||||
|
}
|
||||||
|
if (i == 0)
|
||||||
|
break;
|
||||||
|
tempi = i;
|
||||||
|
u8_dec(s, &i);
|
||||||
|
if (i > tempi)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int u8_is_locale_utf8(const char *locale)
|
||||||
|
{
|
||||||
|
/* this code based on libutf8 */
|
||||||
|
const char* cp = locale;
|
||||||
|
|
||||||
|
for (; *cp != '\0' && *cp != '@' && *cp != '+' && *cp != ','; cp++) {
|
||||||
|
if (*cp == '.') {
|
||||||
|
const char* encoding = ++cp;
|
||||||
|
for (; *cp != '\0' && *cp != '@' && *cp != '+' && *cp != ','; cp++)
|
||||||
|
;
|
||||||
|
if ((cp-encoding == 5 && !strncmp(encoding, "UTF-8", 5))
|
||||||
|
|| (cp-encoding == 4 && !strncmp(encoding, "utf8", 4)))
|
||||||
|
return 1; /* it's UTF-8 */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t u8_vprintf(const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
size_t cnt, sz=0, nc;
|
||||||
|
char *buf;
|
||||||
|
u_int32_t *wcs;
|
||||||
|
|
||||||
|
sz = 512;
|
||||||
|
buf = (char*)alloca(sz);
|
||||||
|
try_print:
|
||||||
|
cnt = vsnprintf(buf, sz, fmt, ap);
|
||||||
|
if (cnt >= sz) {
|
||||||
|
buf = (char*)alloca(cnt - sz + 1);
|
||||||
|
sz = cnt + 1;
|
||||||
|
goto try_print;
|
||||||
|
}
|
||||||
|
wcs = (u_int32_t*)alloca((cnt+1) * sizeof(u_int32_t));
|
||||||
|
nc = u8_toucs(wcs, cnt+1, buf, cnt);
|
||||||
|
wcs[nc] = 0;
|
||||||
|
printf("%ls", (wchar_t*)wcs);
|
||||||
|
return nc;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t u8_printf(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
size_t cnt;
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
|
||||||
|
cnt = u8_vprintf(fmt, args);
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* based on the valid_utf8 routine from the PCRE library by Philip Hazel
|
||||||
|
|
||||||
|
length is in bytes, since without knowing whether the string is valid
|
||||||
|
it's hard to know how many characters there are! */
|
||||||
|
int u8_isvalid(const char *str, int length)
|
||||||
|
{
|
||||||
|
const unsigned char *p, *pend = (unsigned char*)str + length;
|
||||||
|
unsigned char c;
|
||||||
|
int ab;
|
||||||
|
|
||||||
|
for (p = (unsigned char*)str; p < pend; p++) {
|
||||||
|
c = *p;
|
||||||
|
if (c < 128)
|
||||||
|
continue;
|
||||||
|
if ((c & 0xc0) != 0xc0)
|
||||||
|
return 0;
|
||||||
|
ab = trailingBytesForUTF8[c];
|
||||||
|
if (length < ab)
|
||||||
|
return 0;
|
||||||
|
length -= ab;
|
||||||
|
|
||||||
|
p++;
|
||||||
|
/* Check top bits in the second byte */
|
||||||
|
if ((*p & 0xc0) != 0x80)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Check for overlong sequences for each different length */
|
||||||
|
switch (ab) {
|
||||||
|
/* Check for xx00 000x */
|
||||||
|
case 1:
|
||||||
|
if ((c & 0x3e) == 0) return 0;
|
||||||
|
continue; /* We know there aren't any more bytes to check */
|
||||||
|
|
||||||
|
/* Check for 1110 0000, xx0x xxxx */
|
||||||
|
case 2:
|
||||||
|
if (c == 0xe0 && (*p & 0x20) == 0) return 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Check for 1111 0000, xx00 xxxx */
|
||||||
|
case 3:
|
||||||
|
if (c == 0xf0 && (*p & 0x30) == 0) return 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Check for 1111 1000, xx00 0xxx */
|
||||||
|
case 4:
|
||||||
|
if (c == 0xf8 && (*p & 0x38) == 0) return 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Check for leading 0xfe or 0xff,
|
||||||
|
and then for 1111 1100, xx00 00xx */
|
||||||
|
case 5:
|
||||||
|
if (c == 0xfe || c == 0xff ||
|
||||||
|
(c == 0xfc && (*p & 0x3c) == 0)) return 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for valid bytes after the 2nd, if any; all must start 10 */
|
||||||
|
while (--ab > 0) {
|
||||||
|
if ((*(++p) & 0xc0) != 0x80) return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int u8_reverse(char *dest, char * src, size_t len)
|
||||||
|
{
|
||||||
|
size_t si=0, di=len;
|
||||||
|
unsigned char c;
|
||||||
|
|
||||||
|
dest[di] = '\0';
|
||||||
|
while (si < len) {
|
||||||
|
c = (unsigned char)src[si];
|
||||||
|
if ((~c) & 0x80) {
|
||||||
|
di--;
|
||||||
|
dest[di] = c;
|
||||||
|
si++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
switch (c>>4) {
|
||||||
|
case 0xC:
|
||||||
|
case 0xD:
|
||||||
|
di -= 2;
|
||||||
|
*((int16_t*)&dest[di]) = *((int16_t*)&src[si]);
|
||||||
|
si += 2;
|
||||||
|
break;
|
||||||
|
case 0xE:
|
||||||
|
di -= 3;
|
||||||
|
dest[di] = src[si];
|
||||||
|
*((int16_t*)&dest[di+1]) = *((int16_t*)&src[si+1]);
|
||||||
|
si += 3;
|
||||||
|
break;
|
||||||
|
case 0xF:
|
||||||
|
di -= 4;
|
||||||
|
*((int32_t*)&dest[di]) = *((int32_t*)&src[si]);
|
||||||
|
si += 4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u_int32_t u8_fgetc(FILE *f)
|
||||||
|
{
|
||||||
|
int amt=0, sz, c;
|
||||||
|
u_int32_t ch=0;
|
||||||
|
char c0;
|
||||||
|
|
||||||
|
c = fgetc(f);
|
||||||
|
if (c == EOF)
|
||||||
|
return UEOF;
|
||||||
|
ch = (u_int32_t)c;
|
||||||
|
c0 = (char)ch;
|
||||||
|
amt = sz = u8_seqlen(&c0);
|
||||||
|
while (--amt) {
|
||||||
|
ch <<= 6;
|
||||||
|
c = fgetc(f);
|
||||||
|
if (c == EOF)
|
||||||
|
return UEOF;
|
||||||
|
ch += (u_int32_t)c;
|
||||||
|
}
|
||||||
|
ch -= offsetsFromUTF8[sz-1];
|
||||||
|
|
||||||
|
return ch;
|
||||||
|
}
|
|
@ -0,0 +1,128 @@
|
||||||
|
#ifndef __UTF8_H_
|
||||||
|
#define __UTF8_H_
|
||||||
|
|
||||||
|
#ifndef MACOSX
|
||||||
|
#if !defined(__DTYPES_H_) && !defined(_SYS_TYPES_H)
|
||||||
|
typedef char int8_t;
|
||||||
|
typedef short int16_t;
|
||||||
|
typedef int int32_t;
|
||||||
|
typedef long long int64_t;
|
||||||
|
typedef unsigned char u_int8_t;
|
||||||
|
typedef unsigned short u_int16_t;
|
||||||
|
typedef unsigned int u_int32_t;
|
||||||
|
typedef unsigned long long u_int64_t;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* is c the start of a utf8 sequence? */
|
||||||
|
#define isutf(c) (((c)&0xC0)!=0x80)
|
||||||
|
|
||||||
|
#define UEOF ((u_int32_t)-1)
|
||||||
|
|
||||||
|
/* convert UTF-8 data to wide character */
|
||||||
|
size_t u8_toucs(u_int32_t *dest, size_t sz, const char *src, size_t srcsz);
|
||||||
|
|
||||||
|
/* the opposite conversion */
|
||||||
|
size_t u8_toutf8(char *dest, size_t sz, const u_int32_t *src, size_t srcsz);
|
||||||
|
|
||||||
|
/* single character to UTF-8, returns # bytes written */
|
||||||
|
size_t u8_wc_toutf8(char *dest, u_int32_t ch);
|
||||||
|
|
||||||
|
/* character number to byte offset */
|
||||||
|
size_t u8_offset(const char *str, size_t charnum);
|
||||||
|
|
||||||
|
/* byte offset to character number */
|
||||||
|
size_t u8_charnum(const char *s, size_t offset);
|
||||||
|
|
||||||
|
/* return next character, updating an index variable */
|
||||||
|
u_int32_t u8_nextchar(const char *s, size_t *i);
|
||||||
|
|
||||||
|
/* next character without NUL character terminator */
|
||||||
|
u_int32_t u8_nextmemchar(const char *s, size_t *i);
|
||||||
|
|
||||||
|
/* move to next character */
|
||||||
|
void u8_inc(const char *s, size_t *i);
|
||||||
|
|
||||||
|
/* move to previous character */
|
||||||
|
void u8_dec(const char *s, size_t *i);
|
||||||
|
|
||||||
|
/* returns length of next utf-8 sequence */
|
||||||
|
size_t u8_seqlen(const char *s);
|
||||||
|
|
||||||
|
/* returns the # of bytes needed to encode a certain character */
|
||||||
|
size_t u8_charlen(u_int32_t ch);
|
||||||
|
|
||||||
|
/* computes the # of bytes needed to encode a WC string as UTF-8 */
|
||||||
|
size_t u8_codingsize(u_int32_t *wcstr, size_t n);
|
||||||
|
|
||||||
|
/* assuming src points to the character after a backslash, read an
|
||||||
|
escape sequence, storing the result in dest and returning the number of
|
||||||
|
input characters processed */
|
||||||
|
int u8_read_escape_sequence(const char *src, u_int32_t *dest);
|
||||||
|
|
||||||
|
/* given a wide character, convert it to an ASCII escape sequence stored in
|
||||||
|
buf, where buf is "sz" bytes. returns the number of characters output.
|
||||||
|
sz must be at least 3. */
|
||||||
|
int u8_escape_wchar(char *buf, size_t sz, u_int32_t ch);
|
||||||
|
|
||||||
|
/* convert a string "src" containing escape sequences to UTF-8 */
|
||||||
|
size_t u8_unescape(char *buf, size_t sz, const char *src);
|
||||||
|
|
||||||
|
/* convert UTF-8 "src" to escape sequences.
|
||||||
|
|
||||||
|
sz is buf size in bytes. must be at least 12.
|
||||||
|
|
||||||
|
if escape_quotes is nonzero, quote characters will be escaped.
|
||||||
|
|
||||||
|
if ascii is nonzero, the output is 7-bit ASCII, no UTF-8 survives.
|
||||||
|
|
||||||
|
starts at src[*pi], updates *pi to point to the first unprocessed
|
||||||
|
byte of the input.
|
||||||
|
|
||||||
|
end is one more than the last allowable value of *pi.
|
||||||
|
|
||||||
|
returns number of bytes placed in buf, including a NUL terminator.
|
||||||
|
*/
|
||||||
|
size_t u8_escape(char *buf, size_t sz, const char *src, size_t *pi, size_t end,
|
||||||
|
int escape_quotes, int ascii);
|
||||||
|
|
||||||
|
/* utility predicates used by the above */
|
||||||
|
int octal_digit(char c);
|
||||||
|
int hex_digit(char c);
|
||||||
|
|
||||||
|
/* return a pointer to the first occurrence of ch in s, or NULL if not
|
||||||
|
found. character index of found character returned in *charn. */
|
||||||
|
char *u8_strchr(const char *s, u_int32_t ch, size_t *charn);
|
||||||
|
|
||||||
|
/* same as the above, but searches a buffer of a given size instead of
|
||||||
|
a NUL-terminated string. */
|
||||||
|
char *u8_memchr(const char *s, u_int32_t ch, size_t sz, size_t *charn);
|
||||||
|
|
||||||
|
char *u8_memrchr(const char *s, u_int32_t ch, size_t sz);
|
||||||
|
|
||||||
|
/* count the number of characters in a UTF-8 string */
|
||||||
|
size_t u8_strlen(const char *s);
|
||||||
|
|
||||||
|
/* number of columns occupied by a string */
|
||||||
|
size_t u8_strwidth(const char *s);
|
||||||
|
|
||||||
|
int u8_is_locale_utf8(const char *locale);
|
||||||
|
|
||||||
|
/* printf where the format string and arguments may be in UTF-8.
|
||||||
|
you can avoid this function and just use ordinary printf() if the current
|
||||||
|
locale is UTF-8. */
|
||||||
|
size_t u8_vprintf(const char *fmt, va_list ap);
|
||||||
|
size_t u8_printf(const char *fmt, ...);
|
||||||
|
|
||||||
|
/* determine whether a sequence of bytes is valid UTF-8. length is in bytes */
|
||||||
|
int u8_isvalid(const char *str, int length);
|
||||||
|
|
||||||
|
/* reverse a UTF-8 string. len is length in bytes. dest and src must both
|
||||||
|
be allocated to at least len+1 bytes. returns 1 for error, 0 otherwise */
|
||||||
|
int u8_reverse(char *dest, char *src, size_t len);
|
||||||
|
|
||||||
|
#include <stdio.h> // temporary, until u8_fgetc is gone
|
||||||
|
/* read a UTF-8 sequence from a stream and return a wide character or UEOF */
|
||||||
|
u_int32_t u8_fgetc(FILE *f);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,311 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <alloca.h>
|
||||||
|
#include "dtypes.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
void memswap(char *a, char *b, size_t sz)
|
||||||
|
{
|
||||||
|
int8_t i8;
|
||||||
|
int32_t i32;
|
||||||
|
int32_t *a4, *b4;
|
||||||
|
|
||||||
|
if (sz < 4) {
|
||||||
|
while (sz--) {
|
||||||
|
i8 = *a;
|
||||||
|
*a++ = *b;
|
||||||
|
*b++ = i8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
while (sz & 0x3) {
|
||||||
|
i8 = *a;
|
||||||
|
*a++ = *b;
|
||||||
|
*b++ = i8;
|
||||||
|
sz--;
|
||||||
|
}
|
||||||
|
a4 = (int32_t*)a;
|
||||||
|
b4 = (int32_t*)b;
|
||||||
|
sz >>= 2;
|
||||||
|
while (sz--) {
|
||||||
|
i32 = *a4;
|
||||||
|
*a4++ = *b4;
|
||||||
|
*b4++ = i32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void memreverse(char *a, size_t n, size_t elsz)
|
||||||
|
{
|
||||||
|
int64_t i64, *pi64;
|
||||||
|
int32_t i32, *pi32;
|
||||||
|
int16_t i16, *pi16;
|
||||||
|
int8_t i8;
|
||||||
|
size_t i;
|
||||||
|
char *temp;
|
||||||
|
size_t eli, tot;
|
||||||
|
|
||||||
|
if (n==0 || elsz==0) return;
|
||||||
|
switch(elsz) {
|
||||||
|
case 16:
|
||||||
|
pi64 = (int64_t*)a;
|
||||||
|
for(i=0; i < n/2; i++) {
|
||||||
|
i64 = pi64[2*i];
|
||||||
|
pi64[2*i] = pi64[2*(n-i-1)];
|
||||||
|
pi64[2*(n-i-1)] = i64;
|
||||||
|
|
||||||
|
i64 = pi64[2*i+1];
|
||||||
|
pi64[2*i+1] = pi64[2*(n-i-1)+1];
|
||||||
|
pi64[2*(n-i-1)+1] = i64;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
pi64 = (int64_t*)a;
|
||||||
|
for(i=0; i < n/2; i++) {
|
||||||
|
i64 = pi64[i];
|
||||||
|
pi64[i] = pi64[n-i-1];
|
||||||
|
pi64[n-i-1] = i64;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
pi32 = (int32_t*)a;
|
||||||
|
for(i=0; i < n/2; i++) {
|
||||||
|
i32 = pi32[i];
|
||||||
|
pi32[i] = pi32[n-i-1];
|
||||||
|
pi32[n-i-1] = i32;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
pi16 = (int16_t*)a;
|
||||||
|
for(i=0; i < n/2; i++) {
|
||||||
|
i16 = pi16[i];
|
||||||
|
pi16[i] = pi16[n-i-1];
|
||||||
|
pi16[n-i-1] = i16;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
for(i=0; i < n/2; i++) {
|
||||||
|
i8 = a[i];
|
||||||
|
a[i] = a[n-i-1];
|
||||||
|
a[n-i-1] = i8;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
tot = n*elsz;
|
||||||
|
if (elsz < 4097)
|
||||||
|
temp = alloca(elsz);
|
||||||
|
else
|
||||||
|
temp = malloc(elsz);
|
||||||
|
|
||||||
|
if (temp != NULL) {
|
||||||
|
for(i=0, eli=0; i < n/2; i++, eli+=elsz) {
|
||||||
|
memcpy(temp, &a[eli], elsz);
|
||||||
|
memcpy(&a[eli], &a[tot-eli-elsz], elsz);
|
||||||
|
memcpy(&a[tot-eli-elsz], temp, elsz);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elsz >= 4097)
|
||||||
|
free(temp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void memreverse_to(char *dest, char *a, size_t n, size_t elsz)
|
||||||
|
{
|
||||||
|
int64_t *pi64, *di64;
|
||||||
|
int32_t *pi32, *di32;
|
||||||
|
int16_t *pi16, *di16;
|
||||||
|
size_t i;
|
||||||
|
size_t eli, tot;
|
||||||
|
if (n==0 || elsz==0) return;
|
||||||
|
switch(elsz) {
|
||||||
|
case 16:
|
||||||
|
pi64 = (int64_t*)a;
|
||||||
|
di64 = (int64_t*)dest;
|
||||||
|
for(i=0; i < n/2; i++) {
|
||||||
|
di64[2*i] = pi64[2*(n-i-1)];
|
||||||
|
di64[2*(n-i-1)] = pi64[2*i];
|
||||||
|
|
||||||
|
di64[2*i+1] = pi64[2*(n-i-1)+1];
|
||||||
|
di64[2*(n-i-1)+1] = pi64[2*i+1];
|
||||||
|
}
|
||||||
|
if (n&0x1) {
|
||||||
|
di64[2*i] = pi64[2*i];
|
||||||
|
di64[2*i+1] = pi64[2*i+1];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
pi64 = (int64_t*)a;
|
||||||
|
di64 = (int64_t*)dest;
|
||||||
|
for(i=0; i < n/2; i++) {
|
||||||
|
di64[i] = pi64[n-i-1];
|
||||||
|
di64[n-i-1] = pi64[i];
|
||||||
|
}
|
||||||
|
if (n&0x1)
|
||||||
|
di64[i] = pi64[i];
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
pi32 = (int32_t*)a;
|
||||||
|
di32 = (int32_t*)dest;
|
||||||
|
for(i=0; i < n/2; i++) {
|
||||||
|
di32[i] = pi32[n-i-1];
|
||||||
|
di32[n-i-1] = pi32[i];
|
||||||
|
}
|
||||||
|
if (n&0x1)
|
||||||
|
di32[i] = pi32[i];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
pi16 = (int16_t*)a;
|
||||||
|
di16 = (int16_t*)dest;
|
||||||
|
for(i=0; i < n/2; i++) {
|
||||||
|
di16[i] = pi16[n-i-1];
|
||||||
|
di16[n-i-1] = pi16[i];
|
||||||
|
}
|
||||||
|
if (n&0x1)
|
||||||
|
di16[i] = pi16[i];
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
for(i=0; i < n/2; i++) {
|
||||||
|
dest[i] = a[n-i-1];
|
||||||
|
dest[n-i-1] = a[i];
|
||||||
|
}
|
||||||
|
if (n&0x1)
|
||||||
|
dest[i] = a[i];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
tot = n*elsz;
|
||||||
|
for(i=0, eli=0; i < n/2; i++, eli+=elsz) {
|
||||||
|
memcpy(&dest[eli], &a[tot - eli - elsz], elsz);
|
||||||
|
memcpy(&dest[tot - eli - elsz], &a[eli], elsz);
|
||||||
|
}
|
||||||
|
if (n&0x1)
|
||||||
|
memcpy(&dest[eli], &a[eli], elsz);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bswap_buffer(byte_t *data, size_t sz, size_t npts)
|
||||||
|
{
|
||||||
|
size_t i, b;
|
||||||
|
byte_t *el;
|
||||||
|
byte_t temp;
|
||||||
|
|
||||||
|
if (sz <= 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (sz) {
|
||||||
|
case 8:
|
||||||
|
for(i=0; i < npts; i++) {
|
||||||
|
((u_int64_t*)data)[i] = bswap_64(((u_int64_t*)data)[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
for(i=0; i < npts; i++) {
|
||||||
|
((u_int32_t*)data)[i] = bswap_32(((u_int32_t*)data)[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
for(i=0; i < npts; i++) {
|
||||||
|
((u_int16_t*)data)[i] = bswap_16(((u_int16_t*)data)[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
for(i=0; i < sz * npts; i += sz) {
|
||||||
|
el = data + i;
|
||||||
|
for(b=0; b < sz/2; b++) {
|
||||||
|
temp = el[b];
|
||||||
|
el[b] = el[sz-b-1];
|
||||||
|
el[sz-b-1] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bswap(byte_t *s, size_t n)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
char temp;
|
||||||
|
|
||||||
|
switch (n) {
|
||||||
|
case 8:
|
||||||
|
*(u_int64_t*)s = bswap_64(*(u_int64_t*)s); break;
|
||||||
|
case 4:
|
||||||
|
*(u_int32_t*)s = bswap_32(*(u_int32_t*)s); break;
|
||||||
|
case 2:
|
||||||
|
*(u_int16_t*)s = bswap_16(*(u_int16_t*)s); break;
|
||||||
|
case 1:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
for(i=0; i < n/2; i++) {
|
||||||
|
temp = s[i];
|
||||||
|
s[i] = s[n-i-1];
|
||||||
|
s[n-i-1] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bswap_to(byte_t *dest, byte_t *src, size_t n)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
switch (n) {
|
||||||
|
case 8:
|
||||||
|
*(u_int64_t*)dest = bswap_64(*(u_int64_t*)src); break;
|
||||||
|
case 4:
|
||||||
|
*(u_int32_t*)dest = bswap_32(*(u_int32_t*)src); break;
|
||||||
|
case 2:
|
||||||
|
*(u_int16_t*)dest = bswap_16(*(u_int16_t*)src); break;
|
||||||
|
case 1:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
for(i=0; i < n; i++) {
|
||||||
|
dest[i] = src[n-i-1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ALIGNED_TO_ACTUAL(p) (((char*)p) - ((long*)p)[-1])
|
||||||
|
|
||||||
|
static void *aligned_ptr(char *ptr, size_t align_size)
|
||||||
|
{
|
||||||
|
char *ptr2, *aligned_ptr;
|
||||||
|
|
||||||
|
ptr2 = ptr + sizeof(long);
|
||||||
|
aligned_ptr = (char*)ALIGN(((uptrint_t)ptr2), align_size);
|
||||||
|
|
||||||
|
((long*)aligned_ptr)[-1] = (long)(aligned_ptr - ptr);
|
||||||
|
|
||||||
|
return aligned_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* align_size has to be a power of two */
|
||||||
|
void *malloc_aligned(size_t size, size_t align_size)
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
ptr = (char*)malloc(size + align_size-1 + sizeof(long));
|
||||||
|
if (ptr == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return aligned_ptr(ptr, align_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_aligned(void *ptr)
|
||||||
|
{
|
||||||
|
free(ALIGNED_TO_ACTUAL(ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
void *realloc_aligned(void *ptr, size_t size, size_t align_size)
|
||||||
|
{
|
||||||
|
char *pnew;
|
||||||
|
|
||||||
|
if (ptr != NULL)
|
||||||
|
ptr = ALIGNED_TO_ACTUAL(ptr);
|
||||||
|
pnew = realloc(ptr, size + align_size-1 + sizeof(long));
|
||||||
|
if (pnew == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return aligned_ptr(pnew, align_size);
|
||||||
|
}
|
|
@ -0,0 +1,154 @@
|
||||||
|
#ifndef __UTILS_H_
|
||||||
|
#define __UTILS_H_
|
||||||
|
|
||||||
|
/* these functions byteswap any-size units --------------------- */
|
||||||
|
void bswap(byte_t *s, size_t n);
|
||||||
|
void bswap_to(byte_t *dest, byte_t *src, size_t n);
|
||||||
|
void bswap_buffer(byte_t *data, size_t sz, size_t npts);
|
||||||
|
/* ------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* reverse the order of elements of any size, in place or out of place */
|
||||||
|
/* n is the number of elements */
|
||||||
|
void memreverse(char *a, size_t n, size_t elsz);
|
||||||
|
void memreverse_to(char *dest, char *a, size_t n, size_t elsz);
|
||||||
|
|
||||||
|
/* swap the contents of two buffers */
|
||||||
|
void memswap(char *a, char *b, size_t sz);
|
||||||
|
|
||||||
|
/* allocating aligned blocks ----------------------------------- */
|
||||||
|
void *malloc_aligned(size_t size, size_t align_size);
|
||||||
|
void free_aligned(void *ptr);
|
||||||
|
void *realloc_aligned(void *ptr, size_t size, size_t align_size);
|
||||||
|
/* ------------------------------------------------------------- */
|
||||||
|
|
||||||
|
int dbl_equals(double a, double b);
|
||||||
|
int flt_equals(float a, float b);
|
||||||
|
void dbl_tolerance(double tol);
|
||||||
|
void flt_tolerance(float tol);
|
||||||
|
int double_exponent(double d);
|
||||||
|
double double_mantissa(double d);
|
||||||
|
int float_exponent(float f);
|
||||||
|
float float_mantissa(float f);
|
||||||
|
void snprint_real(char *s, size_t cnt, double r,
|
||||||
|
int width, // printf field width, or 0
|
||||||
|
int dec, // # decimal digits desired, recommend 16
|
||||||
|
// # of zeros in .00...0x before using scientific notation
|
||||||
|
// recommend 3-4 or so
|
||||||
|
int max_digs_rt,
|
||||||
|
// # of digits left of decimal before scientific notation
|
||||||
|
// recommend 10
|
||||||
|
int max_digs_lf);
|
||||||
|
void snprint_cplx(char *s, size_t cnt, double re, double im,
|
||||||
|
// args to pass on to snprint_real
|
||||||
|
int width, int dec,
|
||||||
|
int max_digs_rt, int max_digs_lf,
|
||||||
|
// print spaces around sign in a+bi
|
||||||
|
int spflag);
|
||||||
|
|
||||||
|
extern double trunc(double x);
|
||||||
|
|
||||||
|
STATIC_INLINE double fpart(double arg)
|
||||||
|
{
|
||||||
|
return arg - trunc(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ipart(x) trunc(x)
|
||||||
|
|
||||||
|
numerictype_t effective_numerictype(double r);
|
||||||
|
double conv_to_double(void *data, numerictype_t tag);
|
||||||
|
void conv_from_double(void *data, double d, numerictype_t tag);
|
||||||
|
int64_t conv_to_int64(void *data, numerictype_t tag);
|
||||||
|
uint64_t conv_to_uint64(void *data, numerictype_t tag);
|
||||||
|
int32_t conv_to_int32(void *data, numerictype_t tag);
|
||||||
|
uint32_t conv_to_uint32(void *data, numerictype_t tag);
|
||||||
|
#ifdef BITS64
|
||||||
|
#define conv_to_long conv_to_int64
|
||||||
|
#define conv_to_ulong conv_to_uint64
|
||||||
|
#else
|
||||||
|
#define conv_to_long conv_to_int32
|
||||||
|
#define conv_to_ulong conv_to_uint32
|
||||||
|
#endif
|
||||||
|
int cmp_same_lt(void *a, void *b, numerictype_t tag);
|
||||||
|
int cmp_same_eq(void *a, void *b, numerictype_t tag);
|
||||||
|
int cmp_lt(void *a, numerictype_t atag, void *b, numerictype_t btag);
|
||||||
|
int cmp_eq(void *a, numerictype_t atag, void *b, numerictype_t btag);
|
||||||
|
|
||||||
|
#ifdef ARCH_X86_64
|
||||||
|
# define LEGACY_REGS "=Q"
|
||||||
|
#else
|
||||||
|
# define LEGACY_REGS "=q"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__INTEL_COMPILER) && (defined(ARCH_X86) || defined(ARCH_X86_64))
|
||||||
|
STATIC_INLINE u_int16_t ByteSwap16(u_int16_t x)
|
||||||
|
{
|
||||||
|
__asm("xchgb %b0,%h0" :
|
||||||
|
LEGACY_REGS (x) :
|
||||||
|
"0" (x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
#define bswap_16(x) ByteSwap16(x)
|
||||||
|
|
||||||
|
STATIC_INLINE u_int32_t ByteSwap32(u_int32_t x)
|
||||||
|
{
|
||||||
|
#if __CPU__ > 386
|
||||||
|
__asm("bswap %0":
|
||||||
|
"=r" (x) :
|
||||||
|
#else
|
||||||
|
__asm("xchgb %b0,%h0\n"\
|
||||||
|
" rorl $16,%0\n"
|
||||||
|
" xchgb %b0,%h0":
|
||||||
|
LEGACY_REGS (x) :
|
||||||
|
#endif
|
||||||
|
"0" (x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define bswap_32(x) ByteSwap32(x)
|
||||||
|
|
||||||
|
STATIC_INLINE u_int64_t ByteSwap64(u_int64_t x)
|
||||||
|
{
|
||||||
|
#ifdef ARCH_X86_64
|
||||||
|
__asm("bswap %0":
|
||||||
|
"=r" (x) :
|
||||||
|
"0" (x));
|
||||||
|
return x;
|
||||||
|
#else
|
||||||
|
register union { __extension__ u_int64_t __ll;
|
||||||
|
u_int32_t __l[2]; } __x;
|
||||||
|
asm("xchgl %0,%1":
|
||||||
|
"=r"(__x.__l[0]),"=r"(__x.__l[1]):
|
||||||
|
"0"(bswap_32((unsigned long)x)),"1"(bswap_32((unsigned long)(x>>32))));
|
||||||
|
return __x.__ll;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#define bswap_64(x) ByteSwap64(x)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define bswap_16(x) (((x) & 0x00ff) << 8 | ((x) & 0xff00) >> 8)
|
||||||
|
|
||||||
|
#ifdef __INTEL_COMPILER
|
||||||
|
#define bswap_32(x) _bswap(x)
|
||||||
|
#else
|
||||||
|
#define bswap_32(x) \
|
||||||
|
((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
|
||||||
|
(((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
STATIC_INLINE u_int64_t ByteSwap64(u_int64_t x)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
u_int64_t ll;
|
||||||
|
u_int32_t l[2];
|
||||||
|
} w, r;
|
||||||
|
w.ll = x;
|
||||||
|
r.l[0] = bswap_32 (w.l[1]);
|
||||||
|
r.l[1] = bswap_32 (w.l[0]);
|
||||||
|
return r.ll;
|
||||||
|
}
|
||||||
|
#define bswap_64(x) ByteSwap64(x)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue