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