Initial import of libucore
This commit is contained in:
+82
@@ -0,0 +1,82 @@
|
|||||||
|
import os
|
||||||
|
import platform
|
||||||
|
|
||||||
|
#version info of the library
|
||||||
|
revision = svn_version = os.popen('svnversion').read()[:-1]
|
||||||
|
|
||||||
|
version_info = {
|
||||||
|
'version_major': 1 ,
|
||||||
|
'version_minor': 0 ,
|
||||||
|
'version_patch': 0 ,
|
||||||
|
'version_revision': revision,
|
||||||
|
}
|
||||||
|
|
||||||
|
AddOption('--build_type',
|
||||||
|
dest = 'build_type',
|
||||||
|
type = 'string',
|
||||||
|
nargs = 1,
|
||||||
|
action='store',
|
||||||
|
default='debug',
|
||||||
|
metavar='TYPE',
|
||||||
|
help = 'debug|release - Build a Debug (default) or Release variant'
|
||||||
|
)
|
||||||
|
AddOption('--prefix',
|
||||||
|
dest='prefix',
|
||||||
|
type='string',
|
||||||
|
nargs=1,
|
||||||
|
action='store',
|
||||||
|
metavar='DIR',
|
||||||
|
default='/usr',
|
||||||
|
help='installation prefix'
|
||||||
|
)
|
||||||
|
|
||||||
|
AddOption('--test_xml',
|
||||||
|
dest='test_xml',
|
||||||
|
action='store_true',
|
||||||
|
help='Create a result.xml when running the testsuite'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
build_type = GetOption('build_type')
|
||||||
|
test_xml = GetOption('test_xml')
|
||||||
|
prefix = GetOption('prefix')
|
||||||
|
if not (build_type in ['debug', 'release']):
|
||||||
|
print "Error: expected 'debug' or 'release', found: " + build_type
|
||||||
|
Exit(1)
|
||||||
|
|
||||||
|
def InstallPerm(env, dest, files, perm):
|
||||||
|
obj = env.Install(dest, files)
|
||||||
|
for i in obj:
|
||||||
|
env.AddPostAction(i, Chmod(str(i), perm))
|
||||||
|
return dest
|
||||||
|
|
||||||
|
|
||||||
|
env = Environment(tools = ['default', 'textfile'])
|
||||||
|
env.AddMethod(InstallPerm)
|
||||||
|
Export('env', 'build_type', 'prefix', 'version_info', 'test_xml')
|
||||||
|
|
||||||
|
env['CFLAGS'] = ['-Wall', '-Wextra', '-pipe', '-ggdb']
|
||||||
|
env['LINKFLAGS'] = ['-O2']
|
||||||
|
env['CPPDEFINES'] = ['_FILE_OFFSET_BITS=64']
|
||||||
|
|
||||||
|
if build_type == 'release':
|
||||||
|
env['CFLAGS'] += ['-O2']
|
||||||
|
|
||||||
|
#this will turn off assert()
|
||||||
|
env['CPPDEFINES'] += ['NDEBUG']
|
||||||
|
|
||||||
|
elif build_type == 'debug':
|
||||||
|
env['CPPDEFINES'] += ['DEBUG']
|
||||||
|
|
||||||
|
#put all .sconsign files in one place
|
||||||
|
env.SConsignFile()
|
||||||
|
|
||||||
|
subdirs = [
|
||||||
|
'src',
|
||||||
|
'test'
|
||||||
|
]
|
||||||
|
|
||||||
|
for subdir in subdirs:
|
||||||
|
SConscript(subdir + '/SConscript', variant_dir='#build/' + subdir, src_dir='#'+subdir, duplicate=0)
|
||||||
|
|
||||||
|
env.Default('src')
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import os
|
||||||
|
Import('env', 'build_type', 'prefix', 'version_info')
|
||||||
|
|
||||||
|
ucore_env = env.Clone()
|
||||||
|
|
||||||
|
#substitute @version_xx@ strings
|
||||||
|
subst_version_info = dict(('@' + key + '@', version_info[key]) for key in version_info)
|
||||||
|
ucore_env.Substfile('ucore_version.c.in', SUBST_DICT = subst_version_info)
|
||||||
|
|
||||||
|
sources = ucore_env.Glob('*.c')
|
||||||
|
headers = ucore_env.Glob('*.h')
|
||||||
|
|
||||||
|
#print 'ucore_env', dir(ucore_env)
|
||||||
|
#print ucore_env.Dump()
|
||||||
|
#print 'sources:', sources[len(sources)-2]
|
||||||
|
|
||||||
|
#Build library
|
||||||
|
ucore_lib = ucore_env.StaticLibrary(target='ucore_' + build_type , source=sources)
|
||||||
|
|
||||||
|
#install targets
|
||||||
|
ucore_env.Alias('install',
|
||||||
|
ucore_env.Install(os.path.join(prefix, 'lib'), ucore_lib))
|
||||||
|
|
||||||
|
ucore_env.Alias('install',
|
||||||
|
ucore_env.InstallPerm(os.path.join(prefix, 'include', 'ucore'), headers, 0644))
|
||||||
|
|
||||||
+97
@@ -0,0 +1,97 @@
|
|||||||
|
#ifndef IO_MUX_H_
|
||||||
|
#define IO_MUX_H_
|
||||||
|
|
||||||
|
#include "ucore_timers.h"
|
||||||
|
|
||||||
|
#define MUX_EV_READ (1 << 0x00)
|
||||||
|
#define MUX_EV_WRITE (1 << 0x01)
|
||||||
|
//#define MUX_EV_EXCEPT (1 << 0x02)
|
||||||
|
#define MUX_EV_MASK (MUX_EV_READ | MUX_EV_WRITE )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mux implementation to use
|
||||||
|
*/
|
||||||
|
enum IOMUX_TYPE {
|
||||||
|
IOMUX_TYPE_DEFAULT = 0,
|
||||||
|
IOMUX_TYPE_SELECT,
|
||||||
|
IOMUX_TYPE_EPOLL
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Opaque struct */
|
||||||
|
struct IOMux;
|
||||||
|
struct IOMuxFD;
|
||||||
|
typedef void (*iomux_cb)(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event);
|
||||||
|
|
||||||
|
/** Represents a watched file descriptor */
|
||||||
|
struct IOMuxFD {
|
||||||
|
/** The file descriptor */
|
||||||
|
int fd;
|
||||||
|
/** The events to watch for, MUX_EV_XX mask */
|
||||||
|
unsigned int what;
|
||||||
|
/** callback to call on an event */
|
||||||
|
iomux_cb callback;
|
||||||
|
/** values available to the caller. These will bbe passed
|
||||||
|
* back on the callback */
|
||||||
|
void *cookie_ptr;
|
||||||
|
int cookie_int;
|
||||||
|
int cookie_int2;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Creates a new IOMux.
|
||||||
|
*/
|
||||||
|
struct IOMux *iomux_create(enum IOMUX_TYPE type);
|
||||||
|
|
||||||
|
/** Deletes the IOMux and frees its resources.
|
||||||
|
* Can not be called from within a callback */
|
||||||
|
void iomux_delete(struct IOMux *mux);
|
||||||
|
|
||||||
|
/** Runs the event loop of the mux
|
||||||
|
* returns if the number of file descriptors is 0 or
|
||||||
|
* an error occurs */
|
||||||
|
int iomux_run(struct IOMux *mux);
|
||||||
|
|
||||||
|
/* Adds a file descriptor to the watch set,
|
||||||
|
* returns 0 on success, an errno value on error */
|
||||||
|
int iomux_register_fd(struct IOMux *mux, struct IOMuxFD *fd);
|
||||||
|
|
||||||
|
/** Removes the file descriptor*/
|
||||||
|
int iomux_unregister_fd(struct IOMux *mux, struct IOMuxFD *fd);
|
||||||
|
|
||||||
|
/** Updates the events to watch for in fd->what
|
||||||
|
* returns 0 on success, an errno value on error */
|
||||||
|
int iomux_update_events(struct IOMux *mux, struct IOMuxFD *fd);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience macro for setting the new event
|
||||||
|
*/
|
||||||
|
#define iomux_set_event(mux, fd, what)\
|
||||||
|
({\
|
||||||
|
(fd)->what = (what);\
|
||||||
|
iomux_update_events((mux), (fd));\
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience macro for clearing the new event
|
||||||
|
*/
|
||||||
|
#define iomux_clear_event(mux, fd, what)\
|
||||||
|
({\
|
||||||
|
(fd)->what &= ~(what);\
|
||||||
|
iomux_update_events((mux), (fd));\
|
||||||
|
})
|
||||||
|
/**
|
||||||
|
* Convenience macro for adding the new event to the existing events
|
||||||
|
*/
|
||||||
|
#define iomux_add_event(mux, fd, what)\
|
||||||
|
({\
|
||||||
|
(fd)->what &= (what);\
|
||||||
|
iomux_update_events((mux), (fd));\
|
||||||
|
})
|
||||||
|
|
||||||
|
/** Returns a UCTimer instance tied to this mux.
|
||||||
|
* Used to schedule timers within this mux.
|
||||||
|
*/
|
||||||
|
struct UCTimers *iomux_get_timers(struct IOMux *mux);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,224 @@
|
|||||||
|
#include <sys/epoll.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "iomux_impl.h"
|
||||||
|
|
||||||
|
//epoll (linux specific) IO mux.
|
||||||
|
//We stuff the struct IOMuxFD pointer in the event.data.ptr slot
|
||||||
|
//for the kernel to keep track of, so we don't have to.
|
||||||
|
///we do not use edge triggered mode
|
||||||
|
|
||||||
|
//number of events we wait for in one go
|
||||||
|
#define EPOLL_WAIT_EVENTS (256)
|
||||||
|
|
||||||
|
struct IOMuxEpoll {
|
||||||
|
//number of file descriptors we're watching
|
||||||
|
size_t num_descriptors;
|
||||||
|
//the epoll file descriptor
|
||||||
|
int epoll_fd;
|
||||||
|
|
||||||
|
struct epoll_event pending_events[EPOLL_WAIT_EVENTS];
|
||||||
|
//number of pending events
|
||||||
|
int pending;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline uint32_t mux_2_epoll_events(unsigned int events)
|
||||||
|
{
|
||||||
|
uint32_t epoll_events = 0;
|
||||||
|
|
||||||
|
if(events & MUX_EV_READ)
|
||||||
|
epoll_events |= EPOLLIN;
|
||||||
|
|
||||||
|
if(events & MUX_EV_WRITE)
|
||||||
|
epoll_events |= EPOLLOUT;
|
||||||
|
|
||||||
|
return epoll_events;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int epoll_2_mux_events(uint32_t events)
|
||||||
|
{
|
||||||
|
unsigned int mux_events = 0;
|
||||||
|
|
||||||
|
//epoll always waits for EPOLLHUP and EPOLLERR , we map
|
||||||
|
//those to read events which will hopefully do the right thing
|
||||||
|
if(events & (EPOLLIN | EPOLLHUP | EPOLLERR))
|
||||||
|
mux_events |= MUX_EV_READ;
|
||||||
|
|
||||||
|
if(events & EPOLLOUT)
|
||||||
|
mux_events |= MUX_EV_WRITE;
|
||||||
|
|
||||||
|
return mux_events;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iomux_epoll_update_events(struct IOMux *mux_, struct IOMuxFD *fd)
|
||||||
|
{
|
||||||
|
struct IOMuxEpoll *mux = mux_->instance;
|
||||||
|
struct epoll_event e_event = {0, {0}};
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
//if we EPOLL_CTL_MOD with events of 0, epoll
|
||||||
|
//will still wait for HUP/ERR , which can lead to
|
||||||
|
//strange things. (e.g. updating fd->what to 0 on a pipe
|
||||||
|
//in order to try to "pause" reading can lead to missing or false
|
||||||
|
//read events.
|
||||||
|
assert(fd->what != 0);
|
||||||
|
if(fd->what == 0)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
|
||||||
|
e_event.events = mux_2_epoll_events(fd->what);
|
||||||
|
e_event.data.ptr = fd;
|
||||||
|
|
||||||
|
rc = epoll_ctl(mux->epoll_fd, EPOLL_CTL_MOD, fd->fd, &e_event);
|
||||||
|
assert(rc == 0);
|
||||||
|
if(rc != 0)
|
||||||
|
return errno;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iomux_epoll_register_fd(struct IOMux *mux_, struct IOMuxFD *fd)
|
||||||
|
{
|
||||||
|
struct IOMuxEpoll *mux = mux_->instance;
|
||||||
|
struct epoll_event e_event = {0, {0}};
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if(fd->what == 0 || fd->callback == NULL)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
e_event.events = mux_2_epoll_events(fd->what);
|
||||||
|
e_event.data.ptr = fd;
|
||||||
|
|
||||||
|
rc = epoll_ctl(mux->epoll_fd, EPOLL_CTL_ADD, fd->fd, &e_event);
|
||||||
|
assert(rc == 0);
|
||||||
|
if(rc != 0) {
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
mux->num_descriptors++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static int iomux_epoll_unregister_fd(struct IOMux *mux_, struct IOMuxFD *fd)
|
||||||
|
{
|
||||||
|
struct IOMuxEpoll *mux = mux_->instance;
|
||||||
|
struct epoll_event e_event = {0,{ 0}};
|
||||||
|
int i;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = epoll_ctl(mux->epoll_fd, EPOLL_CTL_DEL, fd->fd, &e_event);
|
||||||
|
assert(rc == 0);
|
||||||
|
if(rc != 0)
|
||||||
|
return errno;
|
||||||
|
|
||||||
|
//if the fd is pending, remove it from pending_events
|
||||||
|
//This ensures that it's safe to unregister a descriptor
|
||||||
|
//that is currently pending a callback
|
||||||
|
for(i = 0; i < mux->pending; i++) {
|
||||||
|
struct IOMuxFD *fdi = mux->pending_events[i].data.ptr;
|
||||||
|
if(fdi == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(fd == fdi) {
|
||||||
|
mux->pending_events[i].data.ptr = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mux->num_descriptors--;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
static inline int timeval_to_ms(const struct timeval *t)
|
||||||
|
{
|
||||||
|
int ms = t->tv_sec * 1000;
|
||||||
|
|
||||||
|
ms += (t->tv_usec + 999) / 1000; //round upwards
|
||||||
|
|
||||||
|
return ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iomux_epoll_run(struct IOMux *mux_, struct timeval *timeout)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct IOMuxEpoll *mux = mux_->instance;
|
||||||
|
int rc;
|
||||||
|
int timeout_ms;
|
||||||
|
int event_cnt;
|
||||||
|
|
||||||
|
if(mux->num_descriptors == 0 && timeout == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
//epoll takes the timeout in miliseconds
|
||||||
|
if(timeout)
|
||||||
|
timeout_ms = timeval_to_ms(timeout);
|
||||||
|
else
|
||||||
|
timeout_ms = -1;
|
||||||
|
|
||||||
|
rc = epoll_wait(mux->epoll_fd, mux->pending_events, EPOLL_WAIT_EVENTS, timeout_ms);
|
||||||
|
assert(rc >= 0);
|
||||||
|
if(rc < 0)
|
||||||
|
return errno;
|
||||||
|
|
||||||
|
mux->pending = rc;
|
||||||
|
|
||||||
|
event_cnt = iomux_timers_run(mux_); //process timers
|
||||||
|
|
||||||
|
if(rc == 0) //Just the timeout
|
||||||
|
return event_cnt;
|
||||||
|
|
||||||
|
for(i = 0; i < rc; i++) {
|
||||||
|
struct IOMuxFD *fd = mux->pending_events[i].data.ptr;
|
||||||
|
if(fd != NULL) { //calling _unregister from a callback could have removed it
|
||||||
|
unsigned int events;
|
||||||
|
|
||||||
|
events = epoll_2_mux_events(mux->pending_events[i].events);
|
||||||
|
assert(fd->callback != NULL);
|
||||||
|
fd->callback(mux_, fd, events);
|
||||||
|
//be sure not to use fd after the callback, it might been removed.
|
||||||
|
|
||||||
|
event_cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mux->pending = 0;
|
||||||
|
|
||||||
|
return event_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iomux_epoll_delete(struct IOMux *mux)
|
||||||
|
{
|
||||||
|
assert(mux != NULL && mux->instance != NULL);
|
||||||
|
if(mux != NULL && mux->instance != NULL) {
|
||||||
|
struct IOMuxEpoll *mux_epoll = mux->instance;
|
||||||
|
close(mux_epoll->epoll_fd);
|
||||||
|
free(mux_epoll);
|
||||||
|
mux->instance = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int iomux_epoll_init(struct IOMux *mux)
|
||||||
|
{
|
||||||
|
struct IOMuxEpoll *mux_epoll = calloc(1, sizeof *mux_epoll);
|
||||||
|
if(mux_epoll == NULL)
|
||||||
|
return ENOMEM;
|
||||||
|
|
||||||
|
mux_epoll->epoll_fd = epoll_create(128);
|
||||||
|
if(mux_epoll->epoll_fd == -1) {
|
||||||
|
free(mux_epoll);
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
mux->instance = mux_epoll;
|
||||||
|
mux->run_impl = iomux_epoll_run;
|
||||||
|
mux->delete_impl = iomux_epoll_delete;
|
||||||
|
mux->register_fd_impl = iomux_epoll_register_fd;
|
||||||
|
mux->unregister_fd_impl = iomux_epoll_unregister_fd;
|
||||||
|
mux->update_events_impl = iomux_epoll_update_events;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "iomux_impl.h"
|
||||||
|
|
||||||
|
|
||||||
|
//dispatchers for the IOMux implementations */
|
||||||
|
|
||||||
|
struct IOMux *iomux_create(enum IOMUX_TYPE type)
|
||||||
|
{
|
||||||
|
struct IOMux *mux = calloc(1, sizeof *mux);
|
||||||
|
int rc = -1;
|
||||||
|
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case IOMUX_TYPE_DEFAULT:
|
||||||
|
case IOMUX_TYPE_EPOLL:
|
||||||
|
rc = iomux_epoll_init(mux);
|
||||||
|
break;
|
||||||
|
case IOMUX_TYPE_SELECT:
|
||||||
|
rc = iomux_select_init(mux);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rc != 0) {
|
||||||
|
//try fallback to select
|
||||||
|
rc = iomux_select_init(mux);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rc == 0) {
|
||||||
|
rc = gettimeofday(&mux->now, NULL);
|
||||||
|
assert(rc == 0);
|
||||||
|
uc_timers_init(&mux->timers);
|
||||||
|
} else {
|
||||||
|
free(mux);
|
||||||
|
mux = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mux;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iomux_delete(struct IOMux *mux)
|
||||||
|
{
|
||||||
|
mux->delete_impl(mux);
|
||||||
|
memset(mux, 0xfa, sizeof *mux);
|
||||||
|
free(mux);
|
||||||
|
}
|
||||||
|
|
||||||
|
//convert the difference between future and now
|
||||||
|
static inline void future_to_interval(struct timeval *future, const struct timeval *now, struct timeval *result)
|
||||||
|
{
|
||||||
|
if(timercmp(future, now, >)) {
|
||||||
|
timersub(future, now, result);
|
||||||
|
} else {
|
||||||
|
result->tv_sec = 0;
|
||||||
|
result->tv_usec = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int iomux_run(struct IOMux *mux)
|
||||||
|
{
|
||||||
|
for(;;) {
|
||||||
|
int rc;
|
||||||
|
struct timeval first_timer;
|
||||||
|
struct timeval timeout;
|
||||||
|
struct timeval *timeoutp;;
|
||||||
|
int has_timers = 0;
|
||||||
|
|
||||||
|
|
||||||
|
rc = gettimeofday(&mux->now, NULL);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
if(uc_timers_first(&mux->timers, &first_timer) == 0) {
|
||||||
|
future_to_interval(&first_timer, &mux->now, &timeout);
|
||||||
|
timeoutp = &timeout;
|
||||||
|
/* fprintf(stdout, "now %d %d future %d %d interval %d %d\n", mux->now.tv_sec, mux->now.tv_usec,
|
||||||
|
first_timer.tv_sec, first_timer.tv_usec,
|
||||||
|
timeout.tv_sec, timeout.tv_usec);
|
||||||
|
fflush(stdout);
|
||||||
|
*/
|
||||||
|
|
||||||
|
assert(timeout.tv_sec >= 0);
|
||||||
|
assert(timeout.tv_usec >= 0);
|
||||||
|
|
||||||
|
has_timers = 1;
|
||||||
|
} else {
|
||||||
|
timeoutp = NULL; //no timeout
|
||||||
|
}
|
||||||
|
rc = mux->run_impl(mux, timeoutp);
|
||||||
|
if(rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
if(rc == 0 && !has_timers) //no more events, ever
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iomux_timers_run(struct IOMux *mux)
|
||||||
|
{
|
||||||
|
int event_cnt;
|
||||||
|
gettimeofday(&mux->now, NULL);
|
||||||
|
|
||||||
|
event_cnt = uc_timers_run(&mux->timers, &mux->now);
|
||||||
|
assert(event_cnt >= 0);
|
||||||
|
|
||||||
|
return event_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iomux_register_fd(struct IOMux *mux, struct IOMuxFD *fd)
|
||||||
|
{
|
||||||
|
assert(mux != NULL);
|
||||||
|
assert(fd != NULL);
|
||||||
|
assert(fd->callback != NULL);
|
||||||
|
return mux->register_fd_impl(mux, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int iomux_unregister_fd(struct IOMux *mux, struct IOMuxFD *fd)
|
||||||
|
{
|
||||||
|
assert(mux != NULL);
|
||||||
|
assert(fd != NULL);
|
||||||
|
return mux->unregister_fd_impl(mux, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int iomux_update_events(struct IOMux *mux, struct IOMuxFD *fd)
|
||||||
|
{
|
||||||
|
assert(mux != NULL);
|
||||||
|
assert(fd != NULL);
|
||||||
|
assert(fd->callback != NULL);
|
||||||
|
return mux->update_events_impl(mux, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct UCTimers *iomux_get_timers(struct IOMux *mux)
|
||||||
|
{
|
||||||
|
return &mux->timers;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#ifndef IO_MUX_IMPL_H_
|
||||||
|
#define IO_MUX_IMPL_H_
|
||||||
|
|
||||||
|
#include "iomux.h"
|
||||||
|
#include "ucore_timers.h"
|
||||||
|
/** struct for IOMux implementations */
|
||||||
|
struct IOMux {
|
||||||
|
|
||||||
|
/* TImer instance */
|
||||||
|
struct UCTimers timers;
|
||||||
|
|
||||||
|
/* Current time. Updated before calling run_impl, and updated
|
||||||
|
* by iomux_timers_run
|
||||||
|
*/
|
||||||
|
struct timeval now;
|
||||||
|
|
||||||
|
/* Used by mux implementations to hold their own data/instance */
|
||||||
|
void *instance;
|
||||||
|
|
||||||
|
/** Run one iteration of the mux.
|
||||||
|
* The mux implementation must honor the timeout, if given.
|
||||||
|
* The mux implementation must call iomux_timers_run after the
|
||||||
|
* polling has occured (or if it's polling times out)
|
||||||
|
*
|
||||||
|
* @mux The IOMux instance
|
||||||
|
* @timeout absolute time of a timeout - after which timers should run.
|
||||||
|
* If timeout is NULL, no timeout should be set on the poll.
|
||||||
|
*/
|
||||||
|
int (*run_impl)(struct IOMux *mux, struct timeval *timeout);
|
||||||
|
|
||||||
|
/* Deallocate the instance specific part of the IOMux */
|
||||||
|
void (*delete_impl)(struct IOMux *mux);
|
||||||
|
|
||||||
|
/** Register an IOMuxFD for events*/
|
||||||
|
int (*register_fd_impl)(struct IOMux *mux, struct IOMuxFD *fd);
|
||||||
|
/** Unregister an IOMuxFD */
|
||||||
|
int (*unregister_fd_impl)(struct IOMux *mux, struct IOMuxFD *fd);
|
||||||
|
/** Update an IOMuxFD (due to its events ('what') has changed*/
|
||||||
|
int (*update_events_impl)(struct IOMux *mux, struct IOMuxFD *fd);
|
||||||
|
};
|
||||||
|
|
||||||
|
int iomux_select_init(struct IOMux *mux);
|
||||||
|
int iomux_epoll_init(struct IOMux *mux);
|
||||||
|
int iomux_timers_run(struct IOMux *mux);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,212 @@
|
|||||||
|
#include <sys/select.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "iomux_impl.h"
|
||||||
|
#include "ucore_utils.h"
|
||||||
|
|
||||||
|
#define IOMUX_GROW_CHUNK (32)
|
||||||
|
|
||||||
|
struct IOMuxSelect {
|
||||||
|
fd_set master_read_set;
|
||||||
|
fd_set master_write_set;
|
||||||
|
|
||||||
|
struct IOMuxFD **descriptors; // array of pointers to the user IOMuxFD's
|
||||||
|
size_t alloc_descriptors; //allocated descriptors in 'descriptors'
|
||||||
|
size_t num_descriptors; //number of descriptors we're watching
|
||||||
|
size_t deleted_cnt; //used to rebuild the descriptors array
|
||||||
|
int max_fd; //keeps track of the max fd for select()
|
||||||
|
};
|
||||||
|
|
||||||
|
static int iomux_select_update_events(struct IOMux *mux_, struct IOMuxFD *fd);
|
||||||
|
|
||||||
|
//grows the descriptor array. We never shrink it.
|
||||||
|
static int iomux_select_grow(struct IOMuxSelect *mux)
|
||||||
|
{
|
||||||
|
void *tmp = realloc(mux->descriptors, (mux->num_descriptors + IOMUX_GROW_CHUNK) * sizeof *mux->descriptors);
|
||||||
|
assert(tmp != NULL);
|
||||||
|
if(tmp == NULL)
|
||||||
|
return ENOMEM;
|
||||||
|
|
||||||
|
mux->alloc_descriptors += IOMUX_GROW_CHUNK;
|
||||||
|
mux->descriptors = tmp;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iomux_select_remove(struct IOMuxSelect *mux, size_t idx)
|
||||||
|
{
|
||||||
|
if(mux->num_descriptors > 1) {
|
||||||
|
//move last element into the empty slot
|
||||||
|
size_t last_idx = mux->num_descriptors - 1;
|
||||||
|
mux->descriptors[idx] = mux->descriptors[last_idx];
|
||||||
|
mux->descriptors[last_idx] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mux->num_descriptors--;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iomux_select_rebuild(struct IOMuxSelect *mux)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
mux->max_fd = -1;
|
||||||
|
for(i = 0; i < mux->num_descriptors; ) {
|
||||||
|
if(mux->descriptors[i] == NULL) {
|
||||||
|
iomux_select_remove(mux, i);
|
||||||
|
//a deleted fd slot needs to be rechecked, no i++ here
|
||||||
|
} else {
|
||||||
|
mux->max_fd = UC_MAX(mux->descriptors[i]->fd, mux->max_fd);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//sets or clears the events.
|
||||||
|
static int iomux_select_update_events(struct IOMux *mux_, struct IOMuxFD *fd)
|
||||||
|
{
|
||||||
|
struct IOMuxSelect *mux = mux_->instance;
|
||||||
|
|
||||||
|
if(fd->what & MUX_EV_READ)
|
||||||
|
FD_SET(fd->fd, &mux->master_read_set);
|
||||||
|
else
|
||||||
|
FD_CLR(fd->fd, &mux->master_read_set);
|
||||||
|
|
||||||
|
if(fd->what & MUX_EV_WRITE)
|
||||||
|
FD_SET(fd->fd, &mux->master_write_set);
|
||||||
|
else
|
||||||
|
FD_CLR(fd->fd, &mux->master_write_set);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iomux_select_register_fd(struct IOMux *mux_, struct IOMuxFD *fd)
|
||||||
|
{
|
||||||
|
struct IOMuxSelect *mux = mux_->instance;
|
||||||
|
if(fd->what == 0 || fd->callback == NULL)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
if(mux->num_descriptors == mux->alloc_descriptors) {
|
||||||
|
if(iomux_select_grow(mux) != 0)
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
mux->descriptors[mux->num_descriptors] = fd;
|
||||||
|
mux->num_descriptors++;
|
||||||
|
|
||||||
|
iomux_select_update_events(mux_, fd);
|
||||||
|
|
||||||
|
mux->max_fd = UC_MAX(fd->fd, mux->max_fd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iomux_select_unregister_fd(struct IOMux *mux_, struct IOMuxFD *fd)
|
||||||
|
{
|
||||||
|
struct IOMuxSelect *mux = mux_->instance;
|
||||||
|
int rc = ENOENT;
|
||||||
|
|
||||||
|
size_t i;
|
||||||
|
for(i = 0; i < mux->num_descriptors; i++) {
|
||||||
|
if(fd == mux->descriptors[i]) {
|
||||||
|
int what = fd->what; //make sure we don't alter 'what' as seen from the user
|
||||||
|
fd->what &= ~MUX_EV_MASK;
|
||||||
|
iomux_select_update_events(mux_, fd);
|
||||||
|
mux->descriptors[i] = NULL; //set the slot to NULL, the event loop needs to rebuild it.
|
||||||
|
mux->deleted_cnt++;
|
||||||
|
fd->what = what;
|
||||||
|
rc = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iomux_select_run(struct IOMux *mux_, struct timeval *timeout)
|
||||||
|
{
|
||||||
|
struct IOMuxSelect *mux = mux_->instance;
|
||||||
|
|
||||||
|
int rc;
|
||||||
|
size_t i;
|
||||||
|
int event_cnt = 0;
|
||||||
|
|
||||||
|
if(mux->deleted_cnt) {
|
||||||
|
iomux_select_rebuild(mux);
|
||||||
|
mux->deleted_cnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mux->max_fd == -1 && timeout == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fd_set read_set = mux->master_read_set;
|
||||||
|
fd_set write_set = mux->master_write_set;
|
||||||
|
|
||||||
|
rc = select(mux->max_fd + 1, &read_set, &write_set, NULL, timeout); //we can use timeout directly
|
||||||
|
assert(rc >= 0);
|
||||||
|
if(rc < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
event_cnt = iomux_timers_run(mux_); //fire the timers
|
||||||
|
|
||||||
|
if(rc == 0) //Just the timeout
|
||||||
|
return event_cnt;
|
||||||
|
|
||||||
|
for(i = 0; rc >= 0 && i < mux->num_descriptors; i++) {
|
||||||
|
unsigned int events = 0;
|
||||||
|
|
||||||
|
if(mux->descriptors[i] == NULL) { //callback might have deleted it
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(FD_ISSET(mux->descriptors[i]->fd, &read_set)) {
|
||||||
|
events |= MUX_EV_READ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(FD_ISSET(mux->descriptors[i]->fd, &write_set)) {
|
||||||
|
events |= MUX_EV_WRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(events) {
|
||||||
|
assert(mux->descriptors[i]->callback != NULL);
|
||||||
|
mux->descriptors[i]->callback(mux_, mux->descriptors[i], events);
|
||||||
|
rc--;
|
||||||
|
event_cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return event_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iomux_select_delete(struct IOMux *mux)
|
||||||
|
{
|
||||||
|
if(mux != NULL && mux->instance != NULL) {
|
||||||
|
struct IOMuxSelect *mux_select = mux->instance;
|
||||||
|
free(mux_select->descriptors);
|
||||||
|
mux_select->descriptors = NULL;
|
||||||
|
free(mux_select);
|
||||||
|
mux->instance = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int iomux_select_init(struct IOMux *mux)
|
||||||
|
{
|
||||||
|
struct IOMuxSelect *mux_select = calloc(1, sizeof *mux_select);
|
||||||
|
if(mux_select == NULL)
|
||||||
|
return ENOMEM;
|
||||||
|
|
||||||
|
mux_select->max_fd = -1;
|
||||||
|
|
||||||
|
mux->instance = mux_select;
|
||||||
|
mux->run_impl = iomux_select_run;
|
||||||
|
mux->delete_impl = iomux_select_delete;
|
||||||
|
mux->register_fd_impl = iomux_select_register_fd;
|
||||||
|
mux->unregister_fd_impl = iomux_select_unregister_fd;
|
||||||
|
mux->update_events_impl = iomux_select_update_events;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
+741
@@ -0,0 +1,741 @@
|
|||||||
|
/* $NetBSD: tree.h,v 1.16 2008/03/21 13:07:15 ad Exp $ */
|
||||||
|
/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */
|
||||||
|
/*
|
||||||
|
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SYS_TREE_H_
|
||||||
|
#define _SYS_TREE_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file defines data structures for different types of trees:
|
||||||
|
* splay trees and red-black trees.
|
||||||
|
*
|
||||||
|
* A splay tree is a self-organizing data structure. Every operation
|
||||||
|
* on the tree causes a splay to happen. The splay moves the requested
|
||||||
|
* node to the root of the tree and partly rebalances it.
|
||||||
|
*
|
||||||
|
* This has the benefit that request locality causes faster lookups as
|
||||||
|
* the requested nodes move to the top of the tree. On the other hand,
|
||||||
|
* every lookup causes memory writes.
|
||||||
|
*
|
||||||
|
* The Balance Theorem bounds the total access time for m operations
|
||||||
|
* and n inserts on an initially empty tree as O((m + n)lg n). The
|
||||||
|
* amortized cost for a sequence of m accesses to a splay tree is O(lg n);
|
||||||
|
*
|
||||||
|
* A red-black tree is a binary search tree with the node color as an
|
||||||
|
* extra attribute. It fulfills a set of conditions:
|
||||||
|
* - every search path from the root to a leaf consists of the
|
||||||
|
* same number of black nodes,
|
||||||
|
* - each red node (except for the root) has a black parent,
|
||||||
|
* - each leaf node is black.
|
||||||
|
*
|
||||||
|
* Every operation on a red-black tree is bounded as O(lg n).
|
||||||
|
* The maximum height of a red-black tree is 2lg (n+1).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SPLAY_HEAD(name, type) \
|
||||||
|
struct name { \
|
||||||
|
struct type *sph_root; /* root of the tree */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SPLAY_INITIALIZER(root) \
|
||||||
|
{ NULL }
|
||||||
|
|
||||||
|
#define SPLAY_INIT(root) do { \
|
||||||
|
(root)->sph_root = NULL; \
|
||||||
|
} while (/*CONSTCOND*/ 0)
|
||||||
|
|
||||||
|
#define SPLAY_ENTRY(type) \
|
||||||
|
struct { \
|
||||||
|
struct type *spe_left; /* left element */ \
|
||||||
|
struct type *spe_right; /* right element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
|
||||||
|
#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
|
||||||
|
#define SPLAY_ROOT(head) (head)->sph_root
|
||||||
|
#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
|
||||||
|
|
||||||
|
/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
|
||||||
|
#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
|
||||||
|
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
|
||||||
|
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
|
||||||
|
(head)->sph_root = tmp; \
|
||||||
|
} while (/*CONSTCOND*/ 0)
|
||||||
|
|
||||||
|
#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
|
||||||
|
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
|
||||||
|
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
|
||||||
|
(head)->sph_root = tmp; \
|
||||||
|
} while (/*CONSTCOND*/ 0)
|
||||||
|
|
||||||
|
#define SPLAY_LINKLEFT(head, tmp, field) do { \
|
||||||
|
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
|
||||||
|
tmp = (head)->sph_root; \
|
||||||
|
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
|
||||||
|
} while (/*CONSTCOND*/ 0)
|
||||||
|
|
||||||
|
#define SPLAY_LINKRIGHT(head, tmp, field) do { \
|
||||||
|
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
|
||||||
|
tmp = (head)->sph_root; \
|
||||||
|
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
|
||||||
|
} while (/*CONSTCOND*/ 0)
|
||||||
|
|
||||||
|
#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
|
||||||
|
SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
|
||||||
|
SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
|
||||||
|
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
|
||||||
|
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
|
||||||
|
} while (/*CONSTCOND*/ 0)
|
||||||
|
|
||||||
|
/* Generates prototypes and inline functions */
|
||||||
|
|
||||||
|
#define SPLAY_PROTOTYPE(name, type, field, cmp) \
|
||||||
|
void name##_SPLAY(struct name *, struct type *); \
|
||||||
|
void name##_SPLAY_MINMAX(struct name *, int); \
|
||||||
|
struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
|
||||||
|
struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
|
||||||
|
\
|
||||||
|
/* Finds the node with the same key as elm */ \
|
||||||
|
static __inline struct type * \
|
||||||
|
name##_SPLAY_FIND(struct name *head, struct type *elm) \
|
||||||
|
{ \
|
||||||
|
if (SPLAY_EMPTY(head)) \
|
||||||
|
return(NULL); \
|
||||||
|
name##_SPLAY(head, elm); \
|
||||||
|
if ((cmp)(elm, (head)->sph_root) == 0) \
|
||||||
|
return (head->sph_root); \
|
||||||
|
return (NULL); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static __inline struct type * \
|
||||||
|
name##_SPLAY_NEXT(struct name *head, struct type *elm) \
|
||||||
|
{ \
|
||||||
|
name##_SPLAY(head, elm); \
|
||||||
|
if (SPLAY_RIGHT(elm, field) != NULL) { \
|
||||||
|
elm = SPLAY_RIGHT(elm, field); \
|
||||||
|
while (SPLAY_LEFT(elm, field) != NULL) { \
|
||||||
|
elm = SPLAY_LEFT(elm, field); \
|
||||||
|
} \
|
||||||
|
} else \
|
||||||
|
elm = NULL; \
|
||||||
|
return (elm); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static __inline struct type * \
|
||||||
|
name##_SPLAY_MIN_MAX(struct name *head, int val) \
|
||||||
|
{ \
|
||||||
|
name##_SPLAY_MINMAX(head, val); \
|
||||||
|
return (SPLAY_ROOT(head)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main splay operation.
|
||||||
|
* Moves node close to the key of elm to top
|
||||||
|
*/
|
||||||
|
#define SPLAY_GENERATE(name, type, field, cmp) \
|
||||||
|
struct type * \
|
||||||
|
name##_SPLAY_INSERT(struct name *head, struct type *elm) \
|
||||||
|
{ \
|
||||||
|
if (SPLAY_EMPTY(head)) { \
|
||||||
|
SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
|
||||||
|
} else { \
|
||||||
|
int __comp; \
|
||||||
|
name##_SPLAY(head, elm); \
|
||||||
|
__comp = (cmp)(elm, (head)->sph_root); \
|
||||||
|
if(__comp < 0) { \
|
||||||
|
SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
|
||||||
|
SPLAY_RIGHT(elm, field) = (head)->sph_root; \
|
||||||
|
SPLAY_LEFT((head)->sph_root, field) = NULL; \
|
||||||
|
} else if (__comp > 0) { \
|
||||||
|
SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
|
||||||
|
SPLAY_LEFT(elm, field) = (head)->sph_root; \
|
||||||
|
SPLAY_RIGHT((head)->sph_root, field) = NULL; \
|
||||||
|
} else \
|
||||||
|
return ((head)->sph_root); \
|
||||||
|
} \
|
||||||
|
(head)->sph_root = (elm); \
|
||||||
|
return (NULL); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
struct type * \
|
||||||
|
name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
|
||||||
|
{ \
|
||||||
|
struct type *__tmp; \
|
||||||
|
if (SPLAY_EMPTY(head)) \
|
||||||
|
return (NULL); \
|
||||||
|
name##_SPLAY(head, elm); \
|
||||||
|
if ((cmp)(elm, (head)->sph_root) == 0) { \
|
||||||
|
if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
|
||||||
|
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
|
||||||
|
} else { \
|
||||||
|
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
|
||||||
|
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
|
||||||
|
name##_SPLAY(head, elm); \
|
||||||
|
SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
|
||||||
|
} \
|
||||||
|
return (elm); \
|
||||||
|
} \
|
||||||
|
return (NULL); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void \
|
||||||
|
name##_SPLAY(struct name *head, struct type *elm) \
|
||||||
|
{ \
|
||||||
|
struct type __node, *__left, *__right, *__tmp; \
|
||||||
|
int __comp; \
|
||||||
|
\
|
||||||
|
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
|
||||||
|
__left = __right = &__node; \
|
||||||
|
\
|
||||||
|
while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \
|
||||||
|
if (__comp < 0) { \
|
||||||
|
__tmp = SPLAY_LEFT((head)->sph_root, field); \
|
||||||
|
if (__tmp == NULL) \
|
||||||
|
break; \
|
||||||
|
if ((cmp)(elm, __tmp) < 0){ \
|
||||||
|
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
|
||||||
|
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
SPLAY_LINKLEFT(head, __right, field); \
|
||||||
|
} else if (__comp > 0) { \
|
||||||
|
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
|
||||||
|
if (__tmp == NULL) \
|
||||||
|
break; \
|
||||||
|
if ((cmp)(elm, __tmp) > 0){ \
|
||||||
|
SPLAY_ROTATE_LEFT(head, __tmp, field); \
|
||||||
|
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
SPLAY_LINKRIGHT(head, __left, field); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Splay with either the minimum or the maximum element \
|
||||||
|
* Used to find minimum or maximum element in tree. \
|
||||||
|
*/ \
|
||||||
|
void name##_SPLAY_MINMAX(struct name *head, int __comp) \
|
||||||
|
{ \
|
||||||
|
struct type __node, *__left, *__right, *__tmp; \
|
||||||
|
\
|
||||||
|
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
|
||||||
|
__left = __right = &__node; \
|
||||||
|
\
|
||||||
|
while (1) { \
|
||||||
|
if (__comp < 0) { \
|
||||||
|
__tmp = SPLAY_LEFT((head)->sph_root, field); \
|
||||||
|
if (__tmp == NULL) \
|
||||||
|
break; \
|
||||||
|
if (__comp < 0){ \
|
||||||
|
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
|
||||||
|
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
SPLAY_LINKLEFT(head, __right, field); \
|
||||||
|
} else if (__comp > 0) { \
|
||||||
|
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
|
||||||
|
if (__tmp == NULL) \
|
||||||
|
break; \
|
||||||
|
if (__comp > 0) { \
|
||||||
|
SPLAY_ROTATE_LEFT(head, __tmp, field); \
|
||||||
|
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
SPLAY_LINKRIGHT(head, __left, field); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SPLAY_NEGINF -1
|
||||||
|
#define SPLAY_INF 1
|
||||||
|
|
||||||
|
#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
|
||||||
|
#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
|
||||||
|
#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
|
||||||
|
#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
|
||||||
|
#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
|
||||||
|
: name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
|
||||||
|
#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
|
||||||
|
: name##_SPLAY_MIN_MAX(x, SPLAY_INF))
|
||||||
|
|
||||||
|
#define SPLAY_FOREACH(x, name, head) \
|
||||||
|
for ((x) = SPLAY_MIN(name, head); \
|
||||||
|
(x) != NULL; \
|
||||||
|
(x) = SPLAY_NEXT(name, head, x))
|
||||||
|
|
||||||
|
/* Macros that define a red-black tree */
|
||||||
|
#define RB_HEAD(name, type) \
|
||||||
|
struct name { \
|
||||||
|
struct type *rbh_root; /* root of the tree */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RB_INITIALIZER(root) \
|
||||||
|
{ NULL }
|
||||||
|
|
||||||
|
#define RB_INIT(root) do { \
|
||||||
|
(root)->rbh_root = NULL; \
|
||||||
|
} while (/*CONSTCOND*/ 0)
|
||||||
|
|
||||||
|
#define RB_BLACK 0
|
||||||
|
#define RB_RED 1
|
||||||
|
#define RB_ENTRY(type) \
|
||||||
|
struct { \
|
||||||
|
struct type *rbe_left; /* left element */ \
|
||||||
|
struct type *rbe_right; /* right element */ \
|
||||||
|
struct type *rbe_parent; /* parent element */ \
|
||||||
|
int rbe_color; /* node color */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RB_LEFT(elm, field) (elm)->field.rbe_left
|
||||||
|
#define RB_RIGHT(elm, field) (elm)->field.rbe_right
|
||||||
|
#define RB_PARENT(elm, field) (elm)->field.rbe_parent
|
||||||
|
#define RB_COLOR(elm, field) (elm)->field.rbe_color
|
||||||
|
#define RB_ROOT(head) (head)->rbh_root
|
||||||
|
#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
|
||||||
|
|
||||||
|
#define RB_SET(elm, parent, field) do { \
|
||||||
|
RB_PARENT(elm, field) = parent; \
|
||||||
|
RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
|
||||||
|
RB_COLOR(elm, field) = RB_RED; \
|
||||||
|
} while (/*CONSTCOND*/ 0)
|
||||||
|
|
||||||
|
#define RB_SET_BLACKRED(black, red, field) do { \
|
||||||
|
RB_COLOR(black, field) = RB_BLACK; \
|
||||||
|
RB_COLOR(red, field) = RB_RED; \
|
||||||
|
} while (/*CONSTCOND*/ 0)
|
||||||
|
|
||||||
|
#ifndef RB_AUGMENT
|
||||||
|
#define RB_AUGMENT(x) (void)(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
|
||||||
|
(tmp) = RB_RIGHT(elm, field); \
|
||||||
|
if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \
|
||||||
|
RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
|
||||||
|
} \
|
||||||
|
RB_AUGMENT(elm); \
|
||||||
|
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
|
||||||
|
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
|
||||||
|
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
|
||||||
|
else \
|
||||||
|
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
|
||||||
|
} else \
|
||||||
|
(head)->rbh_root = (tmp); \
|
||||||
|
RB_LEFT(tmp, field) = (elm); \
|
||||||
|
RB_PARENT(elm, field) = (tmp); \
|
||||||
|
RB_AUGMENT(tmp); \
|
||||||
|
if ((RB_PARENT(tmp, field))) \
|
||||||
|
RB_AUGMENT(RB_PARENT(tmp, field)); \
|
||||||
|
} while (/*CONSTCOND*/ 0)
|
||||||
|
|
||||||
|
#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
|
||||||
|
(tmp) = RB_LEFT(elm, field); \
|
||||||
|
if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \
|
||||||
|
RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
|
||||||
|
} \
|
||||||
|
RB_AUGMENT(elm); \
|
||||||
|
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
|
||||||
|
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
|
||||||
|
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
|
||||||
|
else \
|
||||||
|
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
|
||||||
|
} else \
|
||||||
|
(head)->rbh_root = (tmp); \
|
||||||
|
RB_RIGHT(tmp, field) = (elm); \
|
||||||
|
RB_PARENT(elm, field) = (tmp); \
|
||||||
|
RB_AUGMENT(tmp); \
|
||||||
|
if ((RB_PARENT(tmp, field))) \
|
||||||
|
RB_AUGMENT(RB_PARENT(tmp, field)); \
|
||||||
|
} while (/*CONSTCOND*/ 0)
|
||||||
|
|
||||||
|
/* Generates prototypes and inline functions */
|
||||||
|
#define RB_PROTOTYPE(name, type, field, cmp) \
|
||||||
|
RB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
|
||||||
|
#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \
|
||||||
|
RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static)
|
||||||
|
#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
|
||||||
|
attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \
|
||||||
|
attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
|
||||||
|
attr struct type *name##_RB_REMOVE(struct name *, struct type *); \
|
||||||
|
attr struct type *name##_RB_INSERT(struct name *, struct type *); \
|
||||||
|
attr struct type *name##_RB_FIND(struct name *, struct type *); \
|
||||||
|
attr struct type *name##_RB_NFIND(struct name *, struct type *); \
|
||||||
|
attr struct type *name##_RB_NEXT(struct type *); \
|
||||||
|
attr struct type *name##_RB_PREV(struct type *); \
|
||||||
|
attr struct type *name##_RB_MINMAX(struct name *, int); \
|
||||||
|
\
|
||||||
|
|
||||||
|
/* Main rb operation.
|
||||||
|
* Moves node close to the key of elm to top
|
||||||
|
*/
|
||||||
|
#define RB_GENERATE(name, type, field, cmp) \
|
||||||
|
RB_GENERATE_INTERNAL(name, type, field, cmp,)
|
||||||
|
#define RB_GENERATE_STATIC(name, type, field, cmp) \
|
||||||
|
RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static)
|
||||||
|
#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
|
||||||
|
attr void \
|
||||||
|
name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
|
||||||
|
{ \
|
||||||
|
struct type *parent, *gparent, *tmp; \
|
||||||
|
while ((parent = RB_PARENT(elm, field)) != NULL && \
|
||||||
|
RB_COLOR(parent, field) == RB_RED) { \
|
||||||
|
gparent = RB_PARENT(parent, field); \
|
||||||
|
if (parent == RB_LEFT(gparent, field)) { \
|
||||||
|
tmp = RB_RIGHT(gparent, field); \
|
||||||
|
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
|
||||||
|
RB_COLOR(tmp, field) = RB_BLACK; \
|
||||||
|
RB_SET_BLACKRED(parent, gparent, field);\
|
||||||
|
elm = gparent; \
|
||||||
|
continue; \
|
||||||
|
} \
|
||||||
|
if (RB_RIGHT(parent, field) == elm) { \
|
||||||
|
RB_ROTATE_LEFT(head, parent, tmp, field);\
|
||||||
|
tmp = parent; \
|
||||||
|
parent = elm; \
|
||||||
|
elm = tmp; \
|
||||||
|
} \
|
||||||
|
RB_SET_BLACKRED(parent, gparent, field); \
|
||||||
|
RB_ROTATE_RIGHT(head, gparent, tmp, field); \
|
||||||
|
} else { \
|
||||||
|
tmp = RB_LEFT(gparent, field); \
|
||||||
|
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
|
||||||
|
RB_COLOR(tmp, field) = RB_BLACK; \
|
||||||
|
RB_SET_BLACKRED(parent, gparent, field);\
|
||||||
|
elm = gparent; \
|
||||||
|
continue; \
|
||||||
|
} \
|
||||||
|
if (RB_LEFT(parent, field) == elm) { \
|
||||||
|
RB_ROTATE_RIGHT(head, parent, tmp, field);\
|
||||||
|
tmp = parent; \
|
||||||
|
parent = elm; \
|
||||||
|
elm = tmp; \
|
||||||
|
} \
|
||||||
|
RB_SET_BLACKRED(parent, gparent, field); \
|
||||||
|
RB_ROTATE_LEFT(head, gparent, tmp, field); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
RB_COLOR(head->rbh_root, field) = RB_BLACK; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
attr void \
|
||||||
|
name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
|
||||||
|
{ \
|
||||||
|
struct type *tmp; \
|
||||||
|
while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
|
||||||
|
elm != RB_ROOT(head)) { \
|
||||||
|
if (RB_LEFT(parent, field) == elm) { \
|
||||||
|
tmp = RB_RIGHT(parent, field); \
|
||||||
|
if (RB_COLOR(tmp, field) == RB_RED) { \
|
||||||
|
RB_SET_BLACKRED(tmp, parent, field); \
|
||||||
|
RB_ROTATE_LEFT(head, parent, tmp, field);\
|
||||||
|
tmp = RB_RIGHT(parent, field); \
|
||||||
|
} \
|
||||||
|
if ((RB_LEFT(tmp, field) == NULL || \
|
||||||
|
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
|
||||||
|
(RB_RIGHT(tmp, field) == NULL || \
|
||||||
|
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
|
||||||
|
RB_COLOR(tmp, field) = RB_RED; \
|
||||||
|
elm = parent; \
|
||||||
|
parent = RB_PARENT(elm, field); \
|
||||||
|
} else { \
|
||||||
|
if (RB_RIGHT(tmp, field) == NULL || \
|
||||||
|
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\
|
||||||
|
struct type *oleft; \
|
||||||
|
if ((oleft = RB_LEFT(tmp, field)) \
|
||||||
|
!= NULL) \
|
||||||
|
RB_COLOR(oleft, field) = RB_BLACK;\
|
||||||
|
RB_COLOR(tmp, field) = RB_RED; \
|
||||||
|
RB_ROTATE_RIGHT(head, tmp, oleft, field);\
|
||||||
|
tmp = RB_RIGHT(parent, field); \
|
||||||
|
} \
|
||||||
|
RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
|
||||||
|
RB_COLOR(parent, field) = RB_BLACK; \
|
||||||
|
if (RB_RIGHT(tmp, field)) \
|
||||||
|
RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\
|
||||||
|
RB_ROTATE_LEFT(head, parent, tmp, field);\
|
||||||
|
elm = RB_ROOT(head); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} else { \
|
||||||
|
tmp = RB_LEFT(parent, field); \
|
||||||
|
if (RB_COLOR(tmp, field) == RB_RED) { \
|
||||||
|
RB_SET_BLACKRED(tmp, parent, field); \
|
||||||
|
RB_ROTATE_RIGHT(head, parent, tmp, field);\
|
||||||
|
tmp = RB_LEFT(parent, field); \
|
||||||
|
} \
|
||||||
|
if ((RB_LEFT(tmp, field) == NULL || \
|
||||||
|
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
|
||||||
|
(RB_RIGHT(tmp, field) == NULL || \
|
||||||
|
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
|
||||||
|
RB_COLOR(tmp, field) = RB_RED; \
|
||||||
|
elm = parent; \
|
||||||
|
parent = RB_PARENT(elm, field); \
|
||||||
|
} else { \
|
||||||
|
if (RB_LEFT(tmp, field) == NULL || \
|
||||||
|
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\
|
||||||
|
struct type *oright; \
|
||||||
|
if ((oright = RB_RIGHT(tmp, field)) \
|
||||||
|
!= NULL) \
|
||||||
|
RB_COLOR(oright, field) = RB_BLACK;\
|
||||||
|
RB_COLOR(tmp, field) = RB_RED; \
|
||||||
|
RB_ROTATE_LEFT(head, tmp, oright, field);\
|
||||||
|
tmp = RB_LEFT(parent, field); \
|
||||||
|
} \
|
||||||
|
RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
|
||||||
|
RB_COLOR(parent, field) = RB_BLACK; \
|
||||||
|
if (RB_LEFT(tmp, field)) \
|
||||||
|
RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\
|
||||||
|
RB_ROTATE_RIGHT(head, parent, tmp, field);\
|
||||||
|
elm = RB_ROOT(head); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
if (elm) \
|
||||||
|
RB_COLOR(elm, field) = RB_BLACK; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
attr struct type * \
|
||||||
|
name##_RB_REMOVE(struct name *head, struct type *elm) \
|
||||||
|
{ \
|
||||||
|
struct type *child, *parent, *old = elm; \
|
||||||
|
int color; \
|
||||||
|
if (RB_LEFT(elm, field) == NULL) \
|
||||||
|
child = RB_RIGHT(elm, field); \
|
||||||
|
else if (RB_RIGHT(elm, field) == NULL) \
|
||||||
|
child = RB_LEFT(elm, field); \
|
||||||
|
else { \
|
||||||
|
struct type *left; \
|
||||||
|
elm = RB_RIGHT(elm, field); \
|
||||||
|
while ((left = RB_LEFT(elm, field)) != NULL) \
|
||||||
|
elm = left; \
|
||||||
|
child = RB_RIGHT(elm, field); \
|
||||||
|
parent = RB_PARENT(elm, field); \
|
||||||
|
color = RB_COLOR(elm, field); \
|
||||||
|
if (child) \
|
||||||
|
RB_PARENT(child, field) = parent; \
|
||||||
|
if (parent) { \
|
||||||
|
if (RB_LEFT(parent, field) == elm) \
|
||||||
|
RB_LEFT(parent, field) = child; \
|
||||||
|
else \
|
||||||
|
RB_RIGHT(parent, field) = child; \
|
||||||
|
RB_AUGMENT(parent); \
|
||||||
|
} else \
|
||||||
|
RB_ROOT(head) = child; \
|
||||||
|
if (RB_PARENT(elm, field) == old) \
|
||||||
|
parent = elm; \
|
||||||
|
(elm)->field = (old)->field; \
|
||||||
|
if (RB_PARENT(old, field)) { \
|
||||||
|
if (RB_LEFT(RB_PARENT(old, field), field) == old)\
|
||||||
|
RB_LEFT(RB_PARENT(old, field), field) = elm;\
|
||||||
|
else \
|
||||||
|
RB_RIGHT(RB_PARENT(old, field), field) = elm;\
|
||||||
|
RB_AUGMENT(RB_PARENT(old, field)); \
|
||||||
|
} else \
|
||||||
|
RB_ROOT(head) = elm; \
|
||||||
|
RB_PARENT(RB_LEFT(old, field), field) = elm; \
|
||||||
|
if (RB_RIGHT(old, field)) \
|
||||||
|
RB_PARENT(RB_RIGHT(old, field), field) = elm; \
|
||||||
|
if (parent) { \
|
||||||
|
left = parent; \
|
||||||
|
do { \
|
||||||
|
RB_AUGMENT(left); \
|
||||||
|
} while ((left = RB_PARENT(left, field)) != NULL); \
|
||||||
|
} \
|
||||||
|
goto color; \
|
||||||
|
} \
|
||||||
|
parent = RB_PARENT(elm, field); \
|
||||||
|
color = RB_COLOR(elm, field); \
|
||||||
|
if (child) \
|
||||||
|
RB_PARENT(child, field) = parent; \
|
||||||
|
if (parent) { \
|
||||||
|
if (RB_LEFT(parent, field) == elm) \
|
||||||
|
RB_LEFT(parent, field) = child; \
|
||||||
|
else \
|
||||||
|
RB_RIGHT(parent, field) = child; \
|
||||||
|
RB_AUGMENT(parent); \
|
||||||
|
} else \
|
||||||
|
RB_ROOT(head) = child; \
|
||||||
|
color: \
|
||||||
|
if (color == RB_BLACK) \
|
||||||
|
name##_RB_REMOVE_COLOR(head, parent, child); \
|
||||||
|
return (old); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Inserts a node into the RB tree */ \
|
||||||
|
attr struct type * \
|
||||||
|
name##_RB_INSERT(struct name *head, struct type *elm) \
|
||||||
|
{ \
|
||||||
|
struct type *tmp; \
|
||||||
|
struct type *parent = NULL; \
|
||||||
|
int comp = 0; \
|
||||||
|
tmp = RB_ROOT(head); \
|
||||||
|
while (tmp) { \
|
||||||
|
parent = tmp; \
|
||||||
|
comp = (cmp)(elm, parent); \
|
||||||
|
if (comp < 0) \
|
||||||
|
tmp = RB_LEFT(tmp, field); \
|
||||||
|
else if (comp > 0) \
|
||||||
|
tmp = RB_RIGHT(tmp, field); \
|
||||||
|
else \
|
||||||
|
return (tmp); \
|
||||||
|
} \
|
||||||
|
RB_SET(elm, parent, field); \
|
||||||
|
if (parent != NULL) { \
|
||||||
|
if (comp < 0) \
|
||||||
|
RB_LEFT(parent, field) = elm; \
|
||||||
|
else \
|
||||||
|
RB_RIGHT(parent, field) = elm; \
|
||||||
|
RB_AUGMENT(parent); \
|
||||||
|
} else \
|
||||||
|
RB_ROOT(head) = elm; \
|
||||||
|
name##_RB_INSERT_COLOR(head, elm); \
|
||||||
|
return (NULL); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Finds the node with the same key as elm */ \
|
||||||
|
attr struct type * \
|
||||||
|
name##_RB_FIND(struct name *head, struct type *elm) \
|
||||||
|
{ \
|
||||||
|
struct type *tmp = RB_ROOT(head); \
|
||||||
|
int comp; \
|
||||||
|
while (tmp) { \
|
||||||
|
comp = cmp(elm, tmp); \
|
||||||
|
if (comp < 0) \
|
||||||
|
tmp = RB_LEFT(tmp, field); \
|
||||||
|
else if (comp > 0) \
|
||||||
|
tmp = RB_RIGHT(tmp, field); \
|
||||||
|
else \
|
||||||
|
return (tmp); \
|
||||||
|
} \
|
||||||
|
return (NULL); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Finds the first node greater than or equal to the search key */ \
|
||||||
|
attr struct type * \
|
||||||
|
name##_RB_NFIND(struct name *head, struct type *elm) \
|
||||||
|
{ \
|
||||||
|
struct type *tmp = RB_ROOT(head); \
|
||||||
|
struct type *res = NULL; \
|
||||||
|
int comp; \
|
||||||
|
while (tmp) { \
|
||||||
|
comp = cmp(elm, tmp); \
|
||||||
|
if (comp < 0) { \
|
||||||
|
res = tmp; \
|
||||||
|
tmp = RB_LEFT(tmp, field); \
|
||||||
|
} \
|
||||||
|
else if (comp > 0) \
|
||||||
|
tmp = RB_RIGHT(tmp, field); \
|
||||||
|
else \
|
||||||
|
return (tmp); \
|
||||||
|
} \
|
||||||
|
return (res); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* ARGSUSED */ \
|
||||||
|
attr struct type * \
|
||||||
|
name##_RB_NEXT(struct type *elm) \
|
||||||
|
{ \
|
||||||
|
if (RB_RIGHT(elm, field)) { \
|
||||||
|
elm = RB_RIGHT(elm, field); \
|
||||||
|
while (RB_LEFT(elm, field)) \
|
||||||
|
elm = RB_LEFT(elm, field); \
|
||||||
|
} else { \
|
||||||
|
if (RB_PARENT(elm, field) && \
|
||||||
|
(elm == RB_LEFT(RB_PARENT(elm, field), field))) \
|
||||||
|
elm = RB_PARENT(elm, field); \
|
||||||
|
else { \
|
||||||
|
while (RB_PARENT(elm, field) && \
|
||||||
|
(elm == RB_RIGHT(RB_PARENT(elm, field), field)))\
|
||||||
|
elm = RB_PARENT(elm, field); \
|
||||||
|
elm = RB_PARENT(elm, field); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
return (elm); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* ARGSUSED */ \
|
||||||
|
attr struct type * \
|
||||||
|
name##_RB_PREV(struct type *elm) \
|
||||||
|
{ \
|
||||||
|
if (RB_LEFT(elm, field)) { \
|
||||||
|
elm = RB_LEFT(elm, field); \
|
||||||
|
while (RB_RIGHT(elm, field)) \
|
||||||
|
elm = RB_RIGHT(elm, field); \
|
||||||
|
} else { \
|
||||||
|
if (RB_PARENT(elm, field) && \
|
||||||
|
(elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
|
||||||
|
elm = RB_PARENT(elm, field); \
|
||||||
|
else { \
|
||||||
|
while (RB_PARENT(elm, field) && \
|
||||||
|
(elm == RB_LEFT(RB_PARENT(elm, field), field)))\
|
||||||
|
elm = RB_PARENT(elm, field); \
|
||||||
|
elm = RB_PARENT(elm, field); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
return (elm); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
attr struct type * \
|
||||||
|
name##_RB_MINMAX(struct name *head, int val) \
|
||||||
|
{ \
|
||||||
|
struct type *tmp = RB_ROOT(head); \
|
||||||
|
struct type *parent = NULL; \
|
||||||
|
while (tmp) { \
|
||||||
|
parent = tmp; \
|
||||||
|
if (val < 0) \
|
||||||
|
tmp = RB_LEFT(tmp, field); \
|
||||||
|
else \
|
||||||
|
tmp = RB_RIGHT(tmp, field); \
|
||||||
|
} \
|
||||||
|
return (parent); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RB_NEGINF -1
|
||||||
|
#define RB_INF 1
|
||||||
|
|
||||||
|
#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
|
||||||
|
#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
|
||||||
|
#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
|
||||||
|
#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y)
|
||||||
|
#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
|
||||||
|
#define RB_PREV(name, x, y) name##_RB_PREV(y)
|
||||||
|
#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
|
||||||
|
#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
|
||||||
|
|
||||||
|
#define RB_FOREACH(x, name, head) \
|
||||||
|
for ((x) = RB_MIN(name, head); \
|
||||||
|
(x) != NULL; \
|
||||||
|
(x) = name##_RB_NEXT(x))
|
||||||
|
|
||||||
|
#define RB_FOREACH_REVERSE(x, name, head) \
|
||||||
|
for ((x) = RB_MAX(name, head); \
|
||||||
|
(x) != NULL; \
|
||||||
|
(x) = name##_RB_PREV(x))
|
||||||
|
|
||||||
|
#endif /* _SYS_TREE_H_ */
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#include <execinfo.h>
|
||||||
|
|
||||||
|
#define MAX_BACKTRACE_SYMBOLS 96
|
||||||
|
|
||||||
|
void uc_backtrace_fd(int fd)
|
||||||
|
{
|
||||||
|
void *buffer[MAX_BACKTRACE_SYMBOLS];
|
||||||
|
int ptrs;
|
||||||
|
|
||||||
|
ptrs = backtrace(buffer, MAX_BACKTRACE_SYMBOLS);
|
||||||
|
backtrace_symbols_fd(buffer, ptrs, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef UC_BACKTRACE_H_
|
||||||
|
#define UC_BACKTRACE_H_
|
||||||
|
|
||||||
|
#define UC_BACTRACE_STDERR uc_backtrace_fd(3)
|
||||||
|
|
||||||
|
void uc_backtrace_fd(int fd);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include "ucore_string.h"
|
||||||
|
|
||||||
|
static const uint8_t basecode[128] =
|
||||||
|
{
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 62, 0xff, 0xff, 0xff, 63,
|
||||||
|
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||||
|
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||||
|
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||||
|
};
|
||||||
|
|
||||||
|
#define deccode(c) ((c > 127) ? 0xff : basecode[(c)])
|
||||||
|
|
||||||
|
size_t
|
||||||
|
uc_base64_dec(const unsigned char *data, size_t len, unsigned char *result)
|
||||||
|
{
|
||||||
|
size_t i = 0, j = 0, pad;
|
||||||
|
uint8_t c[4];
|
||||||
|
|
||||||
|
while ((i + 3) < len) {
|
||||||
|
|
||||||
|
pad = 0;
|
||||||
|
c[0] = deccode(data[i ]); pad += (c[0] == 0xff);
|
||||||
|
c[1] = deccode(data[i+1]); pad += (c[1] == 0xff);
|
||||||
|
c[2] = deccode(data[i+2]); pad += (c[2] == 0xff);
|
||||||
|
c[3] = deccode(data[i+3]); pad += (c[3] == 0xff);
|
||||||
|
switch (pad) {
|
||||||
|
case 1:
|
||||||
|
result[j++] = (c[0] << 2) | ((c[1] & 0x30) >> 4);
|
||||||
|
result[j++] = ((c[1] & 0x0f) << 4) | ((c[2] & 0x3c) >> 2);
|
||||||
|
result[j] = (c[2] & 0x03) << 6;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
result[j++] = (c[0] << 2) | ((c[1] & 0x30) >> 4);
|
||||||
|
result[j] = (c[1] & 0x0f) << 4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result[j++] = (c[0] << 2) | ((c[1] & 0x30) >> 4);
|
||||||
|
result[j++] = ((c[1] & 0x0f) << 4) | ((c[2] & 0x3c) >> 2);
|
||||||
|
result[j++] = ((c[2] & 0x03) << 6) | (c[3] & 0x3f);
|
||||||
|
}
|
||||||
|
|
||||||
|
i += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "ucore_string.h"
|
||||||
|
|
||||||
|
static const char basecode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
|
#define PAD '='
|
||||||
|
|
||||||
|
size_t
|
||||||
|
uc_base64_enc(const unsigned char *data,size_t len,unsigned char *result)
|
||||||
|
{
|
||||||
|
|
||||||
|
size_t i = 0, j = 0;
|
||||||
|
size_t pad;
|
||||||
|
|
||||||
|
|
||||||
|
while (i < len) {
|
||||||
|
pad = 3 - (len - i);
|
||||||
|
switch(pad) {
|
||||||
|
case 2:
|
||||||
|
result[j] = basecode[data[i]>>2];
|
||||||
|
result[j+1] = basecode[(data[i] & 0x03) << 4];
|
||||||
|
result[j+2] = PAD;
|
||||||
|
result[j+3] = PAD;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
result[j ] = basecode[data[i]>>2];
|
||||||
|
result[j+1] = basecode[((data[i] & 0x03) << 4) | ((data[i+1] & 0xf0) >> 4)];
|
||||||
|
result[j+2] = basecode[(data[i+1] & 0x0f) << 2];
|
||||||
|
result[j+3] = PAD;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result[j ] = basecode[data[i]>>2];
|
||||||
|
result[j+1] = basecode[((data[i] & 0x03) << 4) | ((data[i+1] & 0xf0) >> 4)];
|
||||||
|
result[j+2] = basecode[((data[i+1] & 0x0f) << 2) | ((data[i+2] & 0xc0) >> 6)];
|
||||||
|
result[j+3] = basecode[data[i+2] & 0x3f];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
j += 4;
|
||||||
|
i += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
return j;
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
#include <ctype.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "ucore_string.h"
|
||||||
|
|
||||||
|
size_t
|
||||||
|
uc_ascii2bcd(const char *ascii, unsigned char *bcdout, unsigned char filler)
|
||||||
|
{
|
||||||
|
unsigned char *bcdp = bcdout;
|
||||||
|
int shift = 0;
|
||||||
|
|
||||||
|
*bcdp = 0;
|
||||||
|
|
||||||
|
for(; *ascii; ascii++) {
|
||||||
|
if(*ascii < '0' || *ascii > '9') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
*bcdp |= (*ascii - '0') << shift;
|
||||||
|
|
||||||
|
if(shift) {
|
||||||
|
bcdp++;
|
||||||
|
*bcdp = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
shift = 4 - shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(shift) {
|
||||||
|
*bcdp |= (filler & 0xf) << 4;
|
||||||
|
bcdp++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bcdp - bcdout;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char hex[] = "0123456789ABCDEF";
|
||||||
|
size_t
|
||||||
|
uc_bcd2ascii(const unsigned char *bcd, size_t bcdlen, char *asciiout)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
size_t idx = 0;
|
||||||
|
|
||||||
|
for(i = 0; i < bcdlen; i++) {
|
||||||
|
asciiout[idx] = hex[bcd[i] & 0xf];
|
||||||
|
idx++;
|
||||||
|
asciiout[idx] = hex[(bcd[i] & 0xf0) >> 4];
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
asciiout[idx] = 0;
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include "ucore_bitvec.h"
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define likely(expr) __builtin_expect((expr), 1)
|
||||||
|
#define unlikely(expr) __builtin_expect((expr), 0)
|
||||||
|
#else
|
||||||
|
#define likely(expr) (expr)
|
||||||
|
#define unlikely(expr) (expr)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline int bit_index(int b)
|
||||||
|
{
|
||||||
|
return b / (sizeof(unsigned long) * CHAR_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bit_offset(int b)
|
||||||
|
{
|
||||||
|
return b % (sizeof(unsigned long) * CHAR_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct bitvec *bitvec_new(size_t nbits)
|
||||||
|
{
|
||||||
|
struct bitvec *v = malloc(sizeof *v);
|
||||||
|
|
||||||
|
if(v == NULL)
|
||||||
|
return NULL;
|
||||||
|
v->vec_len = BITVEC_VEC_LEN(nbits);
|
||||||
|
v->vec = malloc(v->vec_len * sizeof(unsigned long));
|
||||||
|
if(v->vec == NULL) {
|
||||||
|
free(v);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_all(v);
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitvec_free(struct bitvec *v)
|
||||||
|
{
|
||||||
|
if(v) {
|
||||||
|
free(v->vec);
|
||||||
|
free(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void clear_bit(struct bitvec *v,int b)
|
||||||
|
{
|
||||||
|
v->vec[bit_index(b)] &= ~(1UL << (bit_offset(b)));
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_bit(const struct bitvec *v,int b)
|
||||||
|
{
|
||||||
|
return !!(v->vec[bit_index(b)] & (1UL << bit_offset(b)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_bit(struct bitvec *v,int b)
|
||||||
|
{
|
||||||
|
v->vec[bit_index(b)] |= 1UL << (bit_offset(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_bit_s(struct bitvec *v,int b)
|
||||||
|
{
|
||||||
|
size_t idx = (size_t)bit_index(b);
|
||||||
|
assert(b >= 0);
|
||||||
|
assert(v->vec_len > (size_t)idx);
|
||||||
|
|
||||||
|
if(likely(idx < v->vec_len))
|
||||||
|
v->vec[idx] |= 1UL << (bit_offset(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_bit_s(struct bitvec *v,int b)
|
||||||
|
{
|
||||||
|
size_t idx = (size_t)bit_index(b);
|
||||||
|
|
||||||
|
assert(b >= 0);
|
||||||
|
assert(v->vec_len > (size_t)idx);
|
||||||
|
|
||||||
|
if(likely(idx < v->vec_len))
|
||||||
|
v->vec[idx] &= ~(1UL << (bit_offset(b)));
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_bit_s(const struct bitvec *v,int b)
|
||||||
|
{
|
||||||
|
size_t idx = (size_t)bit_index(b);
|
||||||
|
|
||||||
|
assert(b >= 0);
|
||||||
|
assert(v->vec_len > (size_t)idx);
|
||||||
|
|
||||||
|
if(likely(idx < v->vec_len))
|
||||||
|
return !!(v->vec[idx] & (1UL << bit_offset(b)));
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_bits_from_array(struct bitvec *v,char *array,size_t array_len)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for(i = 0; i < array_len; i++) {
|
||||||
|
size_t idx = (size_t)bit_index(array_len);
|
||||||
|
if(unlikely(idx >= v->vec_len))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(array[i])
|
||||||
|
set_bit(v,i);
|
||||||
|
else
|
||||||
|
clear_bit(v,i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_all(struct bitvec *v)
|
||||||
|
{
|
||||||
|
memset(v->vec,0, v->vec_len * sizeof(unsigned long));
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_all(struct bitvec *v)
|
||||||
|
{
|
||||||
|
memset(v->vec,0xff,v->vec_len * sizeof(unsigned long));
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
#ifndef BITEVEC_H_
|
||||||
|
#define BITEVEC_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct bitvec {
|
||||||
|
//storage for the bits
|
||||||
|
unsigned long *vec;
|
||||||
|
//length of the above vec. (Not the number of bits !)
|
||||||
|
size_t vec_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates the length required for a bitvec to store nbit bits.
|
||||||
|
*/
|
||||||
|
#define BITVEC_VEC_LEN(nbits) ((nbits/(sizeof(unsigned long)*CHAR_BIT)) + (nbits % (sizeof(unsigned long)*CHAR_BIT) == 0 ? 0 : 1))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use as :
|
||||||
|
* unsigned long v[10];
|
||||||
|
* struct bitvec v = BITVEC_STATIC_INIT(v);
|
||||||
|
*/
|
||||||
|
#define BITVEC_STATIC_INIT(vec_data)\
|
||||||
|
{\
|
||||||
|
vec_data,\
|
||||||
|
sizeof vec_data/sizeof vec_data[0]}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a newly malloced bitvec, capable of storing at least nbits bits
|
||||||
|
* All bits are initially zero.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct bitvec *bitvec_new(size_t nbits);
|
||||||
|
|
||||||
|
/** free a bitvec previously allocated by bitvec_new
|
||||||
|
*/
|
||||||
|
void bitvec_free(struct bitvec *v);
|
||||||
|
|
||||||
|
//Note that accessing a bit beyond the nbits originally initialized
|
||||||
|
//for the given bitvec is undedefined
|
||||||
|
|
||||||
|
/** Sets bit no. b */
|
||||||
|
void set_bit(struct bitvec *v,int b);
|
||||||
|
|
||||||
|
/** Clears bit no. b*/
|
||||||
|
void clear_bit(struct bitvec *v,int b);
|
||||||
|
|
||||||
|
/** Gets the current value (0 or 1) of bit no. b*/
|
||||||
|
int get_bit(const struct bitvec *v,int b);
|
||||||
|
|
||||||
|
/** Sets all bits to zero */
|
||||||
|
void clear_all(struct bitvec *v);
|
||||||
|
|
||||||
|
/** Sets all bits to one */
|
||||||
|
void set_all(struct bitvec *v);
|
||||||
|
|
||||||
|
/** Initialize bits from a array of ints, each array element maps to one bit.
|
||||||
|
* The bits are initialized from the int array so zero maps to zero and non-zero maps to one.
|
||||||
|
* e..g to set the 5 first bits, to 01110:
|
||||||
|
* int a[] = {0,1,1,1,0};
|
||||||
|
* set_bits_from_array(v,a,5);
|
||||||
|
* */
|
||||||
|
void set_bits_from_array(struct bitvec *v,char *array,size_t array_len);
|
||||||
|
|
||||||
|
// The _s ("secure") versions does boundary checking and assert() if they
|
||||||
|
// try to access a bit out of bounds.
|
||||||
|
|
||||||
|
void set_bit_s(struct bitvec *v,int b);
|
||||||
|
|
||||||
|
void clear_bit_s(struct bitvec *v,int b);
|
||||||
|
|
||||||
|
int get_bit_s(const struct bitvec *v,int b);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "ucore_buffer.h"
|
||||||
|
|
||||||
|
GBuf*
|
||||||
|
uc_new_gbuf(size_t initsz)
|
||||||
|
{
|
||||||
|
GBuf *p;
|
||||||
|
p = malloc(sizeof *p);
|
||||||
|
if(p == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
p->used = 0;
|
||||||
|
p->len = initsz;
|
||||||
|
p->buf = NULL;
|
||||||
|
p->ref_cnt = 1;
|
||||||
|
|
||||||
|
if(initsz != 0 && (p->buf = malloc(initsz)) == NULL) {
|
||||||
|
free(p);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
uc_gbuf_ref(GBuf *buf)
|
||||||
|
{
|
||||||
|
buf->ref_cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
uc_gbuf_unref(GBuf *buf)
|
||||||
|
{
|
||||||
|
buf->ref_cnt--;
|
||||||
|
|
||||||
|
if(buf->ref_cnt == 0) {
|
||||||
|
free(buf->buf);
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
uc_gbuf_append(GBuf *buf,void *data,size_t len)
|
||||||
|
{
|
||||||
|
unsigned char *d = data;
|
||||||
|
unsigned char *gbuf;
|
||||||
|
|
||||||
|
if(buf->len - buf->used < len)
|
||||||
|
if(uc_grow_gbuf(buf, len + len/2))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
gbuf = buf->buf;
|
||||||
|
memcpy(gbuf + buf->used,d,len);
|
||||||
|
buf->used += len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
uc_grow_gbuf(GBuf *buf, size_t addlen)
|
||||||
|
{
|
||||||
|
void *tmp;
|
||||||
|
size_t newsz;
|
||||||
|
|
||||||
|
newsz = buf->len + addlen;
|
||||||
|
|
||||||
|
tmp = realloc(buf->buf,newsz);
|
||||||
|
if(tmp == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
buf->buf = tmp;
|
||||||
|
buf->len = newsz;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#ifndef UCORE_BUFFER_H_
|
||||||
|
#define UCORE_BUFFER_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct GBuf GBuf;
|
||||||
|
struct GBuf {
|
||||||
|
size_t len;
|
||||||
|
size_t used;
|
||||||
|
size_t ref_cnt;
|
||||||
|
void *buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
GBuf*
|
||||||
|
uc_new_gbuf(size_t initsz);
|
||||||
|
|
||||||
|
void
|
||||||
|
uc_gbuf_ref(GBuf *buf);
|
||||||
|
|
||||||
|
void
|
||||||
|
uc_gbuf_unref(GBuf *buf);
|
||||||
|
|
||||||
|
int
|
||||||
|
uc_gbuf_append(GBuf *buf,void *data,size_t len);
|
||||||
|
|
||||||
|
int
|
||||||
|
uc_grow_gbuf(GBuf *buf, size_t addlen);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
#include "ucore_hash.h"
|
||||||
|
|
||||||
|
static const uint32_t crc32_table[256] = {
|
||||||
|
0x0,0x4C11DB7,0x9823B6E,0xD4326D9,0x130476DC,0x17C56B6B,0x1A864DB2,0x1E475005,0x2608EDB8,0x22C9F00F,0x2F8AD6D6,
|
||||||
|
0x2B4BCB61,0x350C9B64,0x31CD86D3,0x3C8EA00A,0x384FBDBD,0x4C11DB70,0x48D0C6C7,0x4593E01E,0x4152FDA9,0x5F15ADAC,
|
||||||
|
0x5BD4B01B,0x569796C2,0x52568B75,0x6A1936C8,0x6ED82B7F,0x639B0DA6,0x675A1011,0x791D4014,0x7DDC5DA3,0x709F7B7A,
|
||||||
|
0x745E66CD,0x9823B6E0,0x9CE2AB57,0x91A18D8E,0x95609039,0x8B27C03C,0x8FE6DD8B,0x82A5FB52,0x8664E6E5,0xBE2B5B58,
|
||||||
|
0xBAEA46EF,0xB7A96036,0xB3687D81,0xAD2F2D84,0xA9EE3033,0xA4AD16EA,0xA06C0B5D,0xD4326D90,0xD0F37027,0xDDB056FE,
|
||||||
|
0xD9714B49,0xC7361B4C,0xC3F706FB,0xCEB42022,0xCA753D95,0xF23A8028,0xF6FB9D9F,0xFBB8BB46,0xFF79A6F1,0xE13EF6F4,
|
||||||
|
0xE5FFEB43,0xE8BCCD9A,0xEC7DD02D,0x34867077,0x30476DC0,0x3D044B19,0x39C556AE,0x278206AB,0x23431B1C,0x2E003DC5,
|
||||||
|
0x2AC12072,0x128E9DCF,0x164F8078,0x1B0CA6A1,0x1FCDBB16,0x18AEB13,0x54BF6A4,0x808D07D,0xCC9CDCA,0x7897AB07,
|
||||||
|
0x7C56B6B0,0x71159069,0x75D48DDE,0x6B93DDDB,0x6F52C06C,0x6211E6B5,0x66D0FB02,0x5E9F46BF,0x5A5E5B08,0x571D7DD1,
|
||||||
|
0x53DC6066,0x4D9B3063,0x495A2DD4,0x44190B0D,0x40D816BA,0xACA5C697,0xA864DB20,0xA527FDF9,0xA1E6E04E,0xBFA1B04B,
|
||||||
|
0xBB60ADFC,0xB6238B25,0xB2E29692,0x8AAD2B2F,0x8E6C3698,0x832F1041,0x87EE0DF6,0x99A95DF3,0x9D684044,0x902B669D,
|
||||||
|
0x94EA7B2A,0xE0B41DE7,0xE4750050,0xE9362689,0xEDF73B3E,0xF3B06B3B,0xF771768C,0xFA325055,0xFEF34DE2,0xC6BCF05F,
|
||||||
|
0xC27DEDE8,0xCF3ECB31,0xCBFFD686,0xD5B88683,0xD1799B34,0xDC3ABDED,0xD8FBA05A,0x690CE0EE,0x6DCDFD59,0x608EDB80,
|
||||||
|
0x644FC637,0x7A089632,0x7EC98B85,0x738AAD5C,0x774BB0EB,0x4F040D56,0x4BC510E1,0x46863638,0x42472B8F,0x5C007B8A,
|
||||||
|
0x58C1663D,0x558240E4,0x51435D53,0x251D3B9E,0x21DC2629,0x2C9F00F0,0x285E1D47,0x36194D42,0x32D850F5,0x3F9B762C,
|
||||||
|
0x3B5A6B9B,0x315D626,0x7D4CB91,0xA97ED48,0xE56F0FF,0x1011A0FA,0x14D0BD4D,0x19939B94,0x1D528623,0xF12F560E,
|
||||||
|
0xF5EE4BB9,0xF8AD6D60,0xFC6C70D7,0xE22B20D2,0xE6EA3D65,0xEBA91BBC,0xEF68060B,0xD727BBB6,0xD3E6A601,0xDEA580D8,
|
||||||
|
0xDA649D6F,0xC423CD6A,0xC0E2D0DD,0xCDA1F604,0xC960EBB3,0xBD3E8D7E,0xB9FF90C9,0xB4BCB610,0xB07DABA7,0xAE3AFBA2,
|
||||||
|
0xAAFBE615,0xA7B8C0CC,0xA379DD7B,0x9B3660C6,0x9FF77D71,0x92B45BA8,0x9675461F,0x8832161A,0x8CF30BAD,0x81B02D74,
|
||||||
|
0x857130C3,0x5D8A9099,0x594B8D2E,0x5408ABF7,0x50C9B640,0x4E8EE645,0x4A4FFBF2,0x470CDD2B,0x43CDC09C,0x7B827D21,
|
||||||
|
0x7F436096,0x7200464F,0x76C15BF8,0x68860BFD,0x6C47164A,0x61043093,0x65C52D24,0x119B4BE9,0x155A565E,0x18197087,
|
||||||
|
0x1CD86D30,0x29F3D35,0x65E2082,0xB1D065B,0xFDC1BEC,0x3793A651,0x3352BBE6,0x3E119D3F,0x3AD08088,0x2497D08D,
|
||||||
|
0x2056CD3A,0x2D15EBE3,0x29D4F654,0xC5A92679,0xC1683BCE,0xCC2B1D17,0xC8EA00A0,0xD6AD50A5,0xD26C4D12,0xDF2F6BCB,
|
||||||
|
0xDBEE767C,0xE3A1CBC1,0xE760D676,0xEA23F0AF,0xEEE2ED18,0xF0A5BD1D,0xF464A0AA,0xF9278673,0xFDE69BC4,0x89B8FD09,
|
||||||
|
0x8D79E0BE,0x803AC667,0x84FBDBD0,0x9ABC8BD5,0x9E7D9662,0x933EB0BB,0x97FFAD0C,0xAFB010B1,0xAB710D06,0xA6322BDF,
|
||||||
|
0xA2F33668,0xBCB4666D,0xB8757BDA,0xB5365D03,0xB1F740B4};
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
uc_crc32(const uint8_t *buf, size_t len)
|
||||||
|
{
|
||||||
|
const uint8_t *p;
|
||||||
|
uint32_t crc;
|
||||||
|
|
||||||
|
crc = 0xffffffff; /* preload shift register, per CRC-32 spec */
|
||||||
|
for (p = buf; len > 0; ++p, --len)
|
||||||
|
crc = (crc << 8) ^ crc32_table[(crc >> 24) ^ *p];
|
||||||
|
return ~crc; /* transmit complement, per CRC-32 spec */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the above table is built with this:
|
||||||
|
#define CRC32_POLY 0x04c11db7 // AUTODIN II, Ethernet, & FDDI
|
||||||
|
|
||||||
|
init_crc32()
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
unsigned long c;
|
||||||
|
|
||||||
|
for (i = 0; i < 256; ++i) {
|
||||||
|
for (c = i << 24, j = 8; j > 0; --j)
|
||||||
|
c = c & 0x80000000 ? (c << 1) ^ CRC32_POLY : (c << 1);
|
||||||
|
crc32_table[i] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#include <stdio.h>
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
init_crc32();
|
||||||
|
for(i = 0; i < 256; i++) {
|
||||||
|
printf("0x%X,",crc32_table[i]);
|
||||||
|
if(i%10 == 0)
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
int
|
||||||
|
uc_day_of_week(int day, int month, int year)
|
||||||
|
{
|
||||||
|
int cent;
|
||||||
|
|
||||||
|
/* adjust months so February is the last one */
|
||||||
|
month -= 2;
|
||||||
|
if (month < 1) {
|
||||||
|
month += 12;
|
||||||
|
--year;
|
||||||
|
}
|
||||||
|
/* split by century */
|
||||||
|
cent = year / 100;
|
||||||
|
year %= 100;
|
||||||
|
return ((26 * month - 2) / 10 + day + year
|
||||||
|
+ year / 4 + cent / 4 + 5 * cent) % 7;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#include "ucore_hash.h"
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
uc_djbhash(const char *str)
|
||||||
|
{
|
||||||
|
uint32_t hash = 5381;
|
||||||
|
int c;
|
||||||
|
while ((c = *str++))
|
||||||
|
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#include "ucore_hash.h"
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
uc_elfhash(const char *str, uint32_t len)
|
||||||
|
{
|
||||||
|
uint32_t hash = 0;
|
||||||
|
uint32_t x = 0;
|
||||||
|
uint32_t i = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < len; str++, i++) {
|
||||||
|
hash = (hash << 4) + (*str);
|
||||||
|
if ((x = hash & 0xF0000000L) != 0) {
|
||||||
|
hash ^= (x >> 24);
|
||||||
|
hash &= ~x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#include "ucore_math.h"
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
uc_gcd_32(uint32_t a, uint32_t b)
|
||||||
|
{
|
||||||
|
while(b != 0) {
|
||||||
|
uint32_t t = b;
|
||||||
|
b = a%b;
|
||||||
|
a = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#include "ucore_math.h"
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
uc_gcd_64(uint64_t a, uint64_t b)
|
||||||
|
{
|
||||||
|
while(b != 0) {
|
||||||
|
uint64_t t = b;
|
||||||
|
b = a%b;
|
||||||
|
a = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include "ucore_string.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
getfields(char *str, char **args, int max, int mflag, const char *set)
|
||||||
|
{
|
||||||
|
char r;
|
||||||
|
int intok, narg;
|
||||||
|
|
||||||
|
if(max <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
narg = 0;
|
||||||
|
args[narg] = str;
|
||||||
|
if(!mflag)
|
||||||
|
narg++;
|
||||||
|
intok = 0;
|
||||||
|
for(;; str++) {
|
||||||
|
r = *str;
|
||||||
|
if(r == 0)
|
||||||
|
break;
|
||||||
|
if(strchr(set, r)) {
|
||||||
|
if(narg >= max)
|
||||||
|
break;
|
||||||
|
*str = 0;
|
||||||
|
intok = 0;
|
||||||
|
args[narg] = str + 1;
|
||||||
|
if(!mflag)
|
||||||
|
narg++;
|
||||||
|
} else {
|
||||||
|
if(!intok && mflag)
|
||||||
|
narg++;
|
||||||
|
intok = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return narg;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#ifndef UCORE_HASH_H_
|
||||||
|
#define UCORE_HASH_H_
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
uc_crc32(const uint8_t *buf, size_t len);
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
uc_djbhash(const char *str);
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
uc_elfhash(const char *str, unsigned int len);
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
uc_hash64shift(uint64_t key);
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
uc_hashuint(uint32_t a);
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
uc_murmurmash2(const void *key, int len, uint32_t seed );
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
uc_pjwhash(const char *str,size_t len);
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
sax_hash(void *key, size_t len);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include "ucore_hash.h"
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
uc_hash64shift(uint64_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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#include "ucore_hash.h"
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
uc_hashint(uint32_t a)
|
||||||
|
{
|
||||||
|
a = (a ^ 61) ^ (a >> 16);
|
||||||
|
a = a + (a << 3);
|
||||||
|
a = a ^ (a >> 4);
|
||||||
|
a = a * 0x27d4eb2d;
|
||||||
|
a = a ^ (a >> 15);
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include "ucore_heapsort.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
uc_sift(unsigned char *base, size_t start, size_t count, size_t width,
|
||||||
|
uc_hs_cmp cmp)
|
||||||
|
{
|
||||||
|
size_t root = start, child;
|
||||||
|
|
||||||
|
while ((root * 2 + 1) < count) {
|
||||||
|
child = root * 2 + 1;
|
||||||
|
if (child < (count - 1)
|
||||||
|
&& cmp(&base[child * width], &base[(child + 1) * width]) < 0)
|
||||||
|
child++;
|
||||||
|
|
||||||
|
if (cmp(&base[root * width], &base[child * width]) < 0) {
|
||||||
|
memcpy(base + root * width, base + child * width, width);
|
||||||
|
root = child;
|
||||||
|
} else
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
uc_heapsort(void *base_, size_t count, size_t width,
|
||||||
|
uc_hs_cmp cmp)
|
||||||
|
{
|
||||||
|
int start = count / 2 - 1, end = count - 1;
|
||||||
|
unsigned char *base = base_;
|
||||||
|
|
||||||
|
while (start >= 0) {
|
||||||
|
uc_sift(base, start, count, width, cmp);
|
||||||
|
start--;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (end > 0) {
|
||||||
|
memcpy(base + end * width, base, width);
|
||||||
|
uc_sift(base, 0, end, width, cmp);
|
||||||
|
end--;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef UCORE_HEAPSORT_H_
|
||||||
|
#define UCORE_HEAPSORT_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
///compare function. Needs only to return < 0 if
|
||||||
|
//the first element is less than the second
|
||||||
|
typedef int (*uc_hs_cmp)(const void *, const void *);
|
||||||
|
|
||||||
|
void
|
||||||
|
uc_heapsort(void *base, size_t count, size_t width,
|
||||||
|
uc_hs_cmp cmp);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "ucore_string.h"
|
||||||
|
|
||||||
|
static const char hx_chars[] = "0123456789ABCDEF" ;
|
||||||
|
|
||||||
|
char*
|
||||||
|
uc_hex_encode(const uint8_t *in, size_t len, char *out)
|
||||||
|
{
|
||||||
|
unsigned int i, t, hn, ln;
|
||||||
|
|
||||||
|
for (i = 0, t = 0; i < len; ++i,t+=2) {
|
||||||
|
|
||||||
|
hn = (in[i] & 0xF0) >> 4 ;
|
||||||
|
ln = in[i] & 0x0F ;
|
||||||
|
|
||||||
|
out[t] = hx_chars[hn];
|
||||||
|
out[t+1] = hx_chars[ln];
|
||||||
|
}
|
||||||
|
|
||||||
|
out[t] = 0;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
uc_hex_encode_delim(const uint8_t *in, size_t inlen, char *out, int outlen, char *delim)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
char *outp = out;
|
||||||
|
|
||||||
|
out[0] = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < inlen && outlen > 0; i++) {
|
||||||
|
int rc = snprintf(outp, outlen, "%02X%s", in[i], delim);
|
||||||
|
if(rc <= 0)
|
||||||
|
break;
|
||||||
|
outp += rc;
|
||||||
|
outlen -= rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return outp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ASCII only */
|
||||||
|
static inline int char_to_bin(char c)
|
||||||
|
{
|
||||||
|
if(c >='0' && c <='9')
|
||||||
|
return c - '0';
|
||||||
|
else if(c >= 'A' && c <= 'F')
|
||||||
|
return c - 'A' + 10;
|
||||||
|
else if(c >= 'a' && c <= 'f')
|
||||||
|
return c - 'a' + 10;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t*
|
||||||
|
uc_hex_decode(const char *in, size_t maxlen,uint8_t *out)
|
||||||
|
{
|
||||||
|
size_t i, t;
|
||||||
|
|
||||||
|
for (t = 0,i = 0; i + 1 < maxlen && in[i] && in[i + 1]; i+=2 , ++t) {
|
||||||
|
int hn, ln;
|
||||||
|
hn = char_to_bin(in[i]);
|
||||||
|
ln = char_to_bin(in[i + 1]);
|
||||||
|
if(hn == -1 || ln == -1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
out[t] = (hn << 4 ) | ln;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &out[t];
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include "ucore_string.h"
|
||||||
|
|
||||||
|
char *
|
||||||
|
uc_human_bytesz(uint64_t bytes, char *result, size_t result_len)
|
||||||
|
{
|
||||||
|
if(bytes < 1000) {
|
||||||
|
snprintf(result, result_len, "%" PRIu64 " b", bytes);
|
||||||
|
} else if (bytes < 1000000) {
|
||||||
|
snprintf(result, result_len, "%.2f kB", bytes/1000.0);
|
||||||
|
} else if (bytes < 1000000000ULL) {
|
||||||
|
snprintf(result, result_len, "%.2f MB", bytes/1000000.0);
|
||||||
|
} else if (bytes < 1000000000000ULL) {
|
||||||
|
snprintf(result, result_len, "%.2f GB", bytes/1000000000.0);
|
||||||
|
} else if (bytes < 1000000000000000ULL) {
|
||||||
|
snprintf(result, result_len, "%.2f TB", bytes/1000000000000.0);
|
||||||
|
} else {
|
||||||
|
snprintf(result, result_len, "%.2f PB", bytes/1000000000000000.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,334 @@
|
|||||||
|
#include <pthread.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include "ucore_logging.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct uc_log_destination {
|
||||||
|
SLIST_ENTRY(uc_log_destination) entry;
|
||||||
|
enum UC_LOG_DESTINATION dest_type;
|
||||||
|
int log_level;
|
||||||
|
int log_location;
|
||||||
|
union {
|
||||||
|
//for syslog
|
||||||
|
struct {
|
||||||
|
const char *ident;
|
||||||
|
int facility;
|
||||||
|
} syslog;
|
||||||
|
//for stderr and files
|
||||||
|
struct {
|
||||||
|
FILE* file;
|
||||||
|
char *file_name; //NULL for stderr destinaton
|
||||||
|
} file;
|
||||||
|
} type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct uc_log_args {
|
||||||
|
struct uc_log_destination *dest;
|
||||||
|
const struct uc_log_module *module;
|
||||||
|
int log_level;
|
||||||
|
const char *file;
|
||||||
|
int line;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//Global lock for the logging system, as logging could be performed from any thread. All operations must grab
|
||||||
|
//this lock before accessing any the global data.
|
||||||
|
static pthread_mutex_t log_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
static struct uc_log_modules modules;
|
||||||
|
|
||||||
|
static const struct uc_log_module unknown_module = {
|
||||||
|
.id = -1,
|
||||||
|
.short_name = "UNKNOWN",
|
||||||
|
.long_name = "Unknown log module",
|
||||||
|
.log_level = UC_LL_DEBUG,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static SLIST_HEAD(, uc_log_destination) destinations;
|
||||||
|
|
||||||
|
inline const char *uc_ll_2_str(enum UC_LOG_LEVEL l)
|
||||||
|
{
|
||||||
|
switch(l) {
|
||||||
|
case UC_LL_NONE:
|
||||||
|
return "NONE";
|
||||||
|
case UC_LL_DEBUG:
|
||||||
|
return "DEBUG";
|
||||||
|
case UC_LL_INFO:
|
||||||
|
return "INFO";
|
||||||
|
case UC_LL_WARNING:
|
||||||
|
return "WARNING";
|
||||||
|
case UC_LL_ERROR:
|
||||||
|
return "ERROR";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int uc_ll_2_syslog(enum UC_LOG_LEVEL l)
|
||||||
|
{
|
||||||
|
switch(l) {
|
||||||
|
case UC_LL_NONE:
|
||||||
|
case UC_LL_DEBUG:
|
||||||
|
return LOG_DEBUG;
|
||||||
|
case UC_LL_INFO:
|
||||||
|
return LOG_INFO;
|
||||||
|
case UC_LL_WARNING:
|
||||||
|
return LOG_WARNING;
|
||||||
|
case UC_LL_ERROR:
|
||||||
|
return LOG_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LOG_INFO;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct uc_log_destination *uc_log_new_stderr(int log_level, int log_location)
|
||||||
|
{
|
||||||
|
struct uc_log_destination *dest = calloc(1, sizeof *dest);
|
||||||
|
|
||||||
|
if(dest == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
dest->dest_type = UC_LDEST_STDERR;
|
||||||
|
dest->type.file.file = stderr;
|
||||||
|
dest->log_level = log_level;;
|
||||||
|
dest->log_location = log_location;
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct uc_log_destination *uc_log_new_syslog(const char *ident, int facility, int log_level, int log_location)
|
||||||
|
{
|
||||||
|
struct uc_log_destination *dest = calloc(1, sizeof *dest);
|
||||||
|
|
||||||
|
if(dest == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
openlog(ident, LOG_NDELAY | LOG_PID, facility);
|
||||||
|
|
||||||
|
dest->dest_type = UC_LDEST_SYSLOG;
|
||||||
|
dest->type.syslog.ident = ident;
|
||||||
|
dest->type.syslog.facility = facility;
|
||||||
|
dest->log_level = log_level;;
|
||||||
|
dest->log_location = log_location;
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct uc_log_destination *uc_log_new_file(const char *filename, int log_level, int log_location)
|
||||||
|
{
|
||||||
|
struct uc_log_destination *dest = calloc(1, sizeof *dest);
|
||||||
|
FILE *f;
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
if(dest == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
name = strdup(filename);
|
||||||
|
if(name == NULL) {
|
||||||
|
free(dest);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
f = fopen(filename, "a");
|
||||||
|
if(f == NULL) {
|
||||||
|
free(name);
|
||||||
|
free(dest);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest->dest_type = UC_LDEST_FILE;
|
||||||
|
dest->type.file.file = f;
|
||||||
|
dest->type.file.file_name = name;
|
||||||
|
dest->log_level = log_level;;
|
||||||
|
dest->log_location = log_location;
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uc_log_add_destination(struct uc_log_destination *dest)
|
||||||
|
{
|
||||||
|
struct uc_log_destination *it;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&log_lock);
|
||||||
|
|
||||||
|
//make sure the destination isn't added twice.
|
||||||
|
SLIST_FOREACH(it, &destinations, entry) {
|
||||||
|
if(dest == it)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//add if it isn't already in the list
|
||||||
|
if(it == NULL) {
|
||||||
|
SLIST_INSERT_HEAD(&destinations, dest, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&log_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uc_log_remove_destination(struct uc_log_destination *dest)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&log_lock);
|
||||||
|
|
||||||
|
SLIST_REMOVE(&destinations, dest, uc_log_destination, entry);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&log_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
int uc_log_reopen_files(void)
|
||||||
|
{
|
||||||
|
struct uc_log_destination *dest;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&log_lock);
|
||||||
|
|
||||||
|
SLIST_FOREACH(dest, &destinations, entry) {
|
||||||
|
|
||||||
|
if(dest->dest_type == UC_LDEST_FILE) {
|
||||||
|
|
||||||
|
if(dest->type.file.file != NULL) {
|
||||||
|
fclose(dest->type.file.file);
|
||||||
|
dest->type.file.file = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dest->type.file.file_name != NULL) {
|
||||||
|
dest->type.file.file = fopen(dest->type.file.file_name, "a");
|
||||||
|
|
||||||
|
if(dest->type.file.file == NULL)
|
||||||
|
rc = errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&log_lock);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uc_log_init(struct uc_log_modules *user_modules)
|
||||||
|
{
|
||||||
|
modules = *user_modules;
|
||||||
|
}
|
||||||
|
|
||||||
|
int uc_log_module_set_loglevel(int module, enum UC_LOG_LEVEL level)
|
||||||
|
{
|
||||||
|
int rc = -1;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&log_lock);
|
||||||
|
|
||||||
|
for(i = 0; i < modules.cnt; i++) {
|
||||||
|
if(modules.mods[i].id == module) {
|
||||||
|
modules.mods[i].log_level = level;
|
||||||
|
rc = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&log_lock);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void uc_vlog_internal(const struct uc_log_args *args, const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
struct uc_log_destination *dest = args->dest;
|
||||||
|
|
||||||
|
if(dest->dest_type != UC_LDEST_SYSLOG && dest->type.file.file != NULL) {
|
||||||
|
char time_buf[48];
|
||||||
|
time_t now;
|
||||||
|
struct tm tmbuf;
|
||||||
|
|
||||||
|
now = time(NULL);
|
||||||
|
localtime_r(&now, &tmbuf);
|
||||||
|
strftime(time_buf, sizeof time_buf, "%d %b %Y %H:%M:%S %Z", &tmbuf);
|
||||||
|
|
||||||
|
if(dest->log_location) {
|
||||||
|
fprintf(dest->type.file.file, "[%s] %s %s:%d [%s] : ", uc_ll_2_str(args->log_level),
|
||||||
|
time_buf, args->file, args->line, args->module->short_name);
|
||||||
|
} else {
|
||||||
|
fprintf(dest->type.file.file, "[%s] %s [%s]: ",
|
||||||
|
uc_ll_2_str(args->log_level), time_buf, args->module->short_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
vfprintf(dest->type.file.file, fmt, ap);
|
||||||
|
|
||||||
|
fflush(dest->type.file.file); //strictly not needed for stderr
|
||||||
|
// though stderr could be redirected to a file
|
||||||
|
|
||||||
|
} else if(dest->dest_type == UC_LDEST_SYSLOG) {
|
||||||
|
int pri = uc_ll_2_syslog(args->log_level);
|
||||||
|
|
||||||
|
//go via a buffer as we must do just 1 syslog call
|
||||||
|
char buf[4096];
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
if(dest->log_location) {
|
||||||
|
len = snprintf(buf, sizeof buf, "%s:%d ", args->file, args->line);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
len += snprintf(&buf[len], sizeof buf - (size_t)len, "[%s] ", args->module->short_name);
|
||||||
|
|
||||||
|
vsnprintf(&buf[len], sizeof buf - (size_t)len, fmt, ap);
|
||||||
|
|
||||||
|
syslog(pri, "%s", buf);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void uc_logf(int log_level, int module, const char *file, int line, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
struct uc_log_destination *dest;
|
||||||
|
const struct uc_log_module *log_module;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&log_lock);
|
||||||
|
|
||||||
|
//Find the module doign the logging, or use the unknown module -
|
||||||
|
//the latter would indicate a bug somewhere in the application as it should
|
||||||
|
//always specify a known module
|
||||||
|
if(module >= 0 && module < modules.cnt)
|
||||||
|
log_module = &modules.mods[module];
|
||||||
|
else
|
||||||
|
log_module = &unknown_module;
|
||||||
|
|
||||||
|
//Check if the module should not be logged
|
||||||
|
if(log_level < log_module->log_level)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
//do logging for each destination
|
||||||
|
SLIST_FOREACH(dest, &destinations, entry) {
|
||||||
|
va_list apc;
|
||||||
|
|
||||||
|
if(log_level >= dest->log_level) {
|
||||||
|
const struct uc_log_args args = {
|
||||||
|
.dest = dest,
|
||||||
|
.module = log_module,
|
||||||
|
.log_level = log_level,
|
||||||
|
.file = file,
|
||||||
|
.line = line,
|
||||||
|
};
|
||||||
|
|
||||||
|
//log func will mess with the va_list,
|
||||||
|
//so make a copy
|
||||||
|
va_copy(apc, ap);
|
||||||
|
uc_vlog_internal(&args, fmt, apc);
|
||||||
|
va_end(apc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
pthread_mutex_unlock(&log_lock);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
#ifndef UCORE_LOGGING_H_
|
||||||
|
#define UCORE_LOGGING_H_
|
||||||
|
|
||||||
|
enum UC_LOG_LEVEL {
|
||||||
|
UC_LL_NONE = 0,
|
||||||
|
UC_LL_DEBUG = 1,
|
||||||
|
UC_LL_INFO = 3,
|
||||||
|
UC_LL_WARNING = 5,
|
||||||
|
UC_LL_ERROR = 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum UC_LOG_DESTINATION {
|
||||||
|
UC_LDEST_SYSLOG,
|
||||||
|
UC_LDEST_STDERR,
|
||||||
|
UC_LDEST_FILE,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct uc_log_module {
|
||||||
|
int id;
|
||||||
|
const char *short_name;
|
||||||
|
const char *long_name;
|
||||||
|
int log_level;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct uc_log_modules {
|
||||||
|
struct uc_log_module *mods;
|
||||||
|
int cnt;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct uc_log_destination;
|
||||||
|
|
||||||
|
|
||||||
|
const char *uc_ll_2_str(enum UC_LOG_LEVEL l);
|
||||||
|
|
||||||
|
struct uc_log_destination *uc_log_new_stderr(int log_level, int log_location);
|
||||||
|
|
||||||
|
struct uc_log_destination *uc_log_new_syslog(const char *ident, int facility, int log_level, int log_location);
|
||||||
|
|
||||||
|
struct uc_log_destination *uc_log_new_file(const char *filename, int log_level, int log_location);
|
||||||
|
|
||||||
|
void uc_log_add_destination(struct uc_log_destination *dest);
|
||||||
|
|
||||||
|
void uc_log_remove_destination(struct uc_log_destination *dest);
|
||||||
|
|
||||||
|
int uc_log_module_set_loglevel(int module, enum UC_LOG_LEVEL level);
|
||||||
|
|
||||||
|
int uc_log_reopen_files(void);
|
||||||
|
|
||||||
|
void uc_log_init(struct uc_log_modules *user_modules);
|
||||||
|
|
||||||
|
void uc_logf(int log_level, int module, const char *file, int line, const char *fmt, ...) __attribute__((format(printf, 5, 6)));
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
# define UC_DEBUGF(mod, fmt, ...) uc_logf(UC_LL_DEBUG, mod, __FILE__, __LINE__, fmt, ## __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
# define UC_DEBUGF(mod, fmt, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define UC_LOGF(lvl, mod, fmt, ...) uc_logf(lvl, mod, __FILE__, __LINE__, fmt, ## __VA_ARGS__)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#ifndef UCORE_MATH_H_
|
||||||
|
#define UCORE_MATH_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
uc_gcd_32(uint32_t a, uint32_t b);
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
uc_gcd_64(uint64_t a, uint64_t b);
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
uc_phi_32(uint32_t N);
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
uc_phi_64(uint64_t N);
|
||||||
|
|
||||||
|
static inline uint32_t
|
||||||
|
uc_nextpow2(uint32_t x)
|
||||||
|
{
|
||||||
|
x--;
|
||||||
|
x |= x >> 1;
|
||||||
|
x |= x >> 2;
|
||||||
|
x |= x >> 4;
|
||||||
|
x |= x >> 8;
|
||||||
|
x |= x >> 16;
|
||||||
|
x++;
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/*Copyright (c) 2004 Nils O. Selåsdal <NOS {on} Utel {dot} no> */
|
||||||
|
/*Straight forward attempt at a Mersenne Twister PRNG */
|
||||||
|
|
||||||
|
#include "ucore_mersenne_twister.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*Beware , pollution. But the names are from the spec */
|
||||||
|
enum {
|
||||||
|
N = MT_RAND_N,
|
||||||
|
w = 32,
|
||||||
|
M = 387,
|
||||||
|
R = 19,
|
||||||
|
U = 0x80000000,
|
||||||
|
LL= 0x7FFFFFFF,
|
||||||
|
a = 0x9908B0DF,
|
||||||
|
s = 7,
|
||||||
|
t = 15,
|
||||||
|
b = 0x9D2C5680,
|
||||||
|
c = 0xEFC60000,
|
||||||
|
l = 18,
|
||||||
|
u = 11,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void mtsrand(int seed, MTRand *r)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
for(j = 0 ; j < N ; j++) {
|
||||||
|
r->x[j] = seed * ((j+1)<< 3)|0x1;
|
||||||
|
}
|
||||||
|
r->i = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int mtrand(MTRand *r)
|
||||||
|
{
|
||||||
|
unsigned int y;
|
||||||
|
unsigned int ch[] = {0, a};
|
||||||
|
|
||||||
|
y = r->x[r->i] & U;
|
||||||
|
y |= r->x[r->i % N];
|
||||||
|
y &= LL;
|
||||||
|
|
||||||
|
r->x[r->i] = r->x[(r->i + M ) %N];
|
||||||
|
r->x[r->i] ^= y >> 1;
|
||||||
|
|
||||||
|
r->x[r->i] ^= ch[y&0x1];
|
||||||
|
|
||||||
|
y = r->x[r->i];
|
||||||
|
y ^= y >> u;
|
||||||
|
y ^= (y << s) & b;
|
||||||
|
y ^= (y << t) & c;
|
||||||
|
y ^= y >> l;
|
||||||
|
|
||||||
|
r->i = (r->i + 1) % N;
|
||||||
|
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
#ifdef TEST_MT
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
int main(int argc,char *argv[])
|
||||||
|
{
|
||||||
|
MTRand r;
|
||||||
|
mtsrand(time(NULL),&r);
|
||||||
|
for(;;){
|
||||||
|
unsigned int _y = mtrand(&r);
|
||||||
|
|
||||||
|
if(_y < 100)
|
||||||
|
printf("%u \n",_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#ifndef UCORE_MERSENNE_TWISTER_H
|
||||||
|
#define UCORE_MERSENNE_TWISTER_H
|
||||||
|
|
||||||
|
|
||||||
|
/** Context used for the PRNG*/
|
||||||
|
#define MT_RAND_N 624
|
||||||
|
typedef struct {
|
||||||
|
unsigned int x[MT_RAND_N];
|
||||||
|
int i;
|
||||||
|
} MTRand;
|
||||||
|
|
||||||
|
/** Initialize a Mersenne Twister PRNG context.
|
||||||
|
* @seed Starter seed for the PRNG
|
||||||
|
* @r context for the PRNG
|
||||||
|
*/
|
||||||
|
void mtsrand(int seed, MTRand *r);
|
||||||
|
|
||||||
|
/** Generate a new random number.
|
||||||
|
* Generated range is 0 to UINT_MAX
|
||||||
|
*
|
||||||
|
* @r context for the PRNG
|
||||||
|
* @return A pseudo random number
|
||||||
|
*/
|
||||||
|
unsigned int mtrand(MTRand *r);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
#include "ucore_hash.h"
|
||||||
|
|
||||||
|
// 'm' and 'r' are mixing constants generated offline.
|
||||||
|
// They're not really 'magic', they just happen to work well.
|
||||||
|
#define m 0x5bd1e995
|
||||||
|
#define r 24
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
uc_murmurmash2(const void *key, int len, uint32_t seed )
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
// Initialize the hash to a 'random' value
|
||||||
|
|
||||||
|
uint32_t h = seed ^ len;
|
||||||
|
|
||||||
|
// Mix 4 bytes at a time into the hash
|
||||||
|
|
||||||
|
const unsigned char * data = (const unsigned char *)key;
|
||||||
|
|
||||||
|
while(len >= 4)
|
||||||
|
{
|
||||||
|
uint32_t k = *(uint32_t *)data;
|
||||||
|
|
||||||
|
k *= m;
|
||||||
|
k ^= k >> r;
|
||||||
|
k *= m;
|
||||||
|
|
||||||
|
h *= m;
|
||||||
|
h ^= k;
|
||||||
|
|
||||||
|
data += 4;
|
||||||
|
len -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the last few bytes of the input array
|
||||||
|
|
||||||
|
switch(len)
|
||||||
|
{
|
||||||
|
case 3: h ^= data[2] << 16;
|
||||||
|
case 2: h ^= data[1] << 8;
|
||||||
|
case 1: h ^= data[0];
|
||||||
|
h *= m;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Do a few final mixes of the hash to ensure the last few
|
||||||
|
// bytes are well-incorporated.
|
||||||
|
|
||||||
|
h ^= h >> 13;
|
||||||
|
h *= m;
|
||||||
|
h ^= h >> 15;
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,257 @@
|
|||||||
|
#ifndef UCORE_PACK_H_
|
||||||
|
#define UCORE_PACK_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# define UC_INLINE inline __attribute__((always_inline))
|
||||||
|
#else
|
||||||
|
# define UC_INLINE inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Functions for serializing/de-serializing integers to and from
|
||||||
|
* byte arrays.
|
||||||
|
* These functions are independant of the host endian. Only
|
||||||
|
* thing to care about is the endian format of the data in
|
||||||
|
* the byte array.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/** Serialize a uint16_t to a byte array in little endian format.
|
||||||
|
* @v The value to serialize
|
||||||
|
* @r The byte array to place the integer in. Must be at least of size 2.
|
||||||
|
*/
|
||||||
|
static UC_INLINE void uc_pack_16_le(uint16_t v, uint8_t *r)
|
||||||
|
{
|
||||||
|
r[0] = v;
|
||||||
|
r[1] = v >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** De-serialize a uint16_t from a byte array in little endian format.
|
||||||
|
* @r The byte array to containing the integer in. Must be at least of size 2.
|
||||||
|
* @return The deserialized integer from the byte array.
|
||||||
|
*/
|
||||||
|
static UC_INLINE uint16_t uc_unpack_16_le(const uint8_t *r)
|
||||||
|
{
|
||||||
|
uint32_t v;
|
||||||
|
|
||||||
|
v = r[0];
|
||||||
|
v |= r[1] << 8;
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Serialize a uint32_t to a 3 byte(24 bits) array in little endian format.
|
||||||
|
* Only the bottom 24 bits of the uint32_t are used.
|
||||||
|
*
|
||||||
|
* @v The value to serialize
|
||||||
|
* @r The byte array to place the integer in. Must be at least of size 3.
|
||||||
|
*/
|
||||||
|
static UC_INLINE void uc_pack_24_le(uint32_t v, uint8_t *r)
|
||||||
|
{
|
||||||
|
r[0] = v;
|
||||||
|
r[1] = v >> 8;
|
||||||
|
r[2] = v >> 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** De-serialize a uint32_t from a 3 byte (24 bit) byte array in little endian format.
|
||||||
|
* @r The byte array to containing the integer in. Must be at least of size 3.
|
||||||
|
* @return The deserialized integer from the byte array.
|
||||||
|
*/
|
||||||
|
static UC_INLINE uint32_t uc_unpack_24_le(const uint8_t *r)
|
||||||
|
{
|
||||||
|
uint32_t v;
|
||||||
|
|
||||||
|
v = r[0];
|
||||||
|
v |= r[1] << 8;
|
||||||
|
v |= r[2] << 16;
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Serialize a uint32_t to a byte array in little endian format.
|
||||||
|
* @v The value to serialize
|
||||||
|
* @r The byte array to place the integer in. Must be at least of size 4.
|
||||||
|
*/
|
||||||
|
static UC_INLINE void uc_pack_32_le(uint32_t v, uint8_t *r)
|
||||||
|
{
|
||||||
|
r[0] = v;
|
||||||
|
r[1] = v >> 8;
|
||||||
|
r[2] = v >> 16;
|
||||||
|
r[3] = v >> 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** De-serialize a uint32_t from a byte array in little endian format.
|
||||||
|
* @r The byte array to containing the integer in. Must be at least of size 4.
|
||||||
|
* @return The deserialized integer from the byte array.
|
||||||
|
*/
|
||||||
|
static UC_INLINE uint32_t uc_unpack_32_le(const uint8_t *r)
|
||||||
|
{
|
||||||
|
uint32_t v;
|
||||||
|
|
||||||
|
v = r[0];
|
||||||
|
v |= r[1] << 8;
|
||||||
|
v |= r[2] << 16;
|
||||||
|
v |= r[3] << 24;
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Serialize a uint64_t to a byte array in little endian format.
|
||||||
|
* @v The value to serialize
|
||||||
|
* @r The byte array to place the integer in. Must be at least of size 8
|
||||||
|
*/
|
||||||
|
static UC_INLINE void uc_pack_64_le(uint64_t v, uint8_t *r)
|
||||||
|
{
|
||||||
|
r[0] = v;
|
||||||
|
r[1] = v >> 8;
|
||||||
|
r[2] = v >> 16;
|
||||||
|
r[3] = v >> 24;
|
||||||
|
r[4] = v >> 32ULL;
|
||||||
|
r[5] = v >> 40ULL;
|
||||||
|
r[6] = v >> 48ULL;
|
||||||
|
r[7] = v >> 56ULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** De-serialize a uint64_t from a byte array in little endian format.
|
||||||
|
* @r The byte array to containing the integer in. Must be at least of size 8.
|
||||||
|
* @return The deserialized integer from the byte array
|
||||||
|
*/
|
||||||
|
static UC_INLINE uint64_t uc_unpack_64_le(const uint8_t *r)
|
||||||
|
{
|
||||||
|
uint64_t v;
|
||||||
|
|
||||||
|
v = r[0];
|
||||||
|
v |= r[1] << 8;
|
||||||
|
v |= r[2] << 16;
|
||||||
|
v |= (uint32_t)r[3] << 24;
|
||||||
|
v |= (uint64_t)r[4] << 32ULL;
|
||||||
|
v |= (uint64_t)r[5] << 40ULL;
|
||||||
|
v |= (uint64_t)r[6] << 48ULL;
|
||||||
|
v |= (uint64_t)r[7] << 56ULL;
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Serialize a uint16_t to a byte array in big endian format.
|
||||||
|
* @v The value to serialize
|
||||||
|
* @r The byte array to place the integer in. Must be at least of size 2.
|
||||||
|
*/
|
||||||
|
static UC_INLINE void uc_pack_16_be(uint32_t v, uint8_t *r)
|
||||||
|
{
|
||||||
|
r[0] = v >> 8;
|
||||||
|
r[1] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** De-serialize a uint16_t from a byte array in big endian format.
|
||||||
|
* @r The byte array to containing the integer in. Must be at least of size 2.
|
||||||
|
* @return The deserialized integer from the byte array
|
||||||
|
*/
|
||||||
|
static UC_INLINE uint16_t uc_unpack_16_be(const uint8_t *r)
|
||||||
|
{
|
||||||
|
uint16_t v;
|
||||||
|
|
||||||
|
v = r[0] << 8;
|
||||||
|
v |= r[1];
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Serialize a uint32_t to a 3 byte(24 bits) array in big endian format.
|
||||||
|
* Only the bottom 24 bits of the uint32_t are used.
|
||||||
|
*
|
||||||
|
* @v The value to serialize
|
||||||
|
* @r The byte array to place the integer in. Must be at least of size 3.
|
||||||
|
*/
|
||||||
|
static UC_INLINE void uc_pack_24_be(uint32_t v, uint8_t *r)
|
||||||
|
{
|
||||||
|
r[0] = v >> 16;
|
||||||
|
r[1] = v >> 8;
|
||||||
|
r[2] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** De-serialize a uint32_t from a 3 byte (24 bit) byte array in big endian format.
|
||||||
|
* @r The byte array to containing the integer in. Must be at least of size 3.
|
||||||
|
* @return The deserialized integer from the byte array.
|
||||||
|
*/
|
||||||
|
static UC_INLINE uint32_t uc_unpack_24_be(const uint8_t *r)
|
||||||
|
{
|
||||||
|
uint32_t v;
|
||||||
|
|
||||||
|
v = r[0] << 16;
|
||||||
|
v |= r[1] << 8;
|
||||||
|
v |= r[2];
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Serialize a uint32_t to a byte array in big endian format.
|
||||||
|
* @v The value to serialize
|
||||||
|
* @r The byte array to place the integer in. Must be at least of size 4.
|
||||||
|
*/
|
||||||
|
static UC_INLINE void uc_pack_32_be(uint32_t v, uint8_t *r)
|
||||||
|
{
|
||||||
|
r[0] = v >> 24;
|
||||||
|
r[1] = v >> 16;
|
||||||
|
r[2] = v >> 8;
|
||||||
|
r[3] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** De-serialize a uint32_t from a byte array in big endian format.
|
||||||
|
* @r The byte array to containing the integer in. Must be at least of size 4.
|
||||||
|
* @return The deserialized integer from the byte array
|
||||||
|
*/
|
||||||
|
static UC_INLINE uint32_t uc_unpack_32_be(const uint8_t *r)
|
||||||
|
{
|
||||||
|
uint32_t v;
|
||||||
|
|
||||||
|
v = r[0] << 24;
|
||||||
|
v |= r[1] << 16;
|
||||||
|
v |= r[2] << 8;
|
||||||
|
v |= r[3];
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Serialize a uint16_t to a byte array in big endian format.
|
||||||
|
* @v The value to serialize
|
||||||
|
* @r The byte array to place the integer in. Must be at least of size 8
|
||||||
|
*/
|
||||||
|
static UC_INLINE void uc_pack_64_be(uint64_t v, uint8_t *r)
|
||||||
|
{
|
||||||
|
r[0] = v >> 56ULL;
|
||||||
|
r[1] = v >> 48ULL;
|
||||||
|
r[2] = v >> 40ULL;
|
||||||
|
r[3] = v >> 32ULL;
|
||||||
|
r[4] = v >> 24;
|
||||||
|
r[5] = v >> 16;
|
||||||
|
r[6] = v >> 8;
|
||||||
|
r[7] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** De-serialize a uint64_t from a byte array in big endian format.
|
||||||
|
* @r The byte array to containing the integer in. Must be at least of size 4.
|
||||||
|
* @return The deserialized integer from the byte array
|
||||||
|
*/
|
||||||
|
static UC_INLINE uint64_t uc_unpack_64_be(const uint8_t *r)
|
||||||
|
{
|
||||||
|
uint64_t v;
|
||||||
|
|
||||||
|
v = (uint64_t)r[0] << 56ULL;
|
||||||
|
v |= (uint64_t)r[1] << 48ULL;
|
||||||
|
v |= (uint64_t)r[2] << 40ULL;
|
||||||
|
v |= (uint64_t)r[3] << 32ULL;
|
||||||
|
v |= (uint32_t)r[4] << 24;
|
||||||
|
v |= r[5] << 16;
|
||||||
|
v |= r[6] << 8;
|
||||||
|
v |= r[7];
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#undef UC_INLINE
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#include "ucore_math.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Euler's Totient Function is denoted by the Greek letter phi, and is defined as follows:
|
||||||
|
phi(N) = how many numbers between 1 and N - 1 which are relatively prime to N.
|
||||||
|
*/
|
||||||
|
uint32_t
|
||||||
|
uc_phi_32(uint32_t N)
|
||||||
|
{
|
||||||
|
uint32_t phi = 1;
|
||||||
|
uint32_t i;
|
||||||
|
for (i = 2 ; i < N ; ++i){
|
||||||
|
if (uc_gcd_32(i, N) == 1){
|
||||||
|
++phi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return phi;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#include "ucore_math.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Euler's Totient Function is denoted by the Greek letter phi, and is defined as follows:
|
||||||
|
phi(N) = how many numbers between 1 and N - 1 which are relatively prime to N.
|
||||||
|
*/
|
||||||
|
uint64_t
|
||||||
|
uc_phi_64(uint64_t N)
|
||||||
|
{
|
||||||
|
uint64_t phi = 1;
|
||||||
|
uint64_t i;
|
||||||
|
for (i = 2 ; i < N ; ++i){
|
||||||
|
if (uc_gcd_64(i, N) == 1){
|
||||||
|
++phi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return phi;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#include "ucore_hash.h"
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
uc_pjwhash(const char *str,size_t len)
|
||||||
|
{
|
||||||
|
|
||||||
|
unsigned h = 0, g;
|
||||||
|
|
||||||
|
while (len--) {
|
||||||
|
h = (h << 4) + *str++;
|
||||||
|
if ((g = h & 0xf0000000)) {
|
||||||
|
h ^= (g >> 24);
|
||||||
|
h ^= g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,336 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
#include "ucore_rbtree.h"
|
||||||
|
//modified from generated code of tree.h
|
||||||
|
|
||||||
|
static void
|
||||||
|
rotateleft(RBTree *root, RBNode *node)
|
||||||
|
{
|
||||||
|
RBNode *right = node->right;
|
||||||
|
|
||||||
|
node->right = right->left;
|
||||||
|
if (right->left)
|
||||||
|
right->left->parent = node;
|
||||||
|
right->left = node;
|
||||||
|
|
||||||
|
right->parent = node->parent;
|
||||||
|
if (node->parent) {
|
||||||
|
if (node == node->parent->left)
|
||||||
|
node->parent->left = right;
|
||||||
|
else
|
||||||
|
node->parent->right = right;
|
||||||
|
} else
|
||||||
|
root->node = right;
|
||||||
|
node->parent = right;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rotateright(RBTree *root, RBNode *node)
|
||||||
|
{
|
||||||
|
RBNode *left = node->left;
|
||||||
|
|
||||||
|
node->left = left->right;
|
||||||
|
if (left->right)
|
||||||
|
left->right->parent = node;
|
||||||
|
left->right = node;
|
||||||
|
|
||||||
|
left->parent = node->parent;
|
||||||
|
if (node->parent) {
|
||||||
|
if (node == node->parent->right)
|
||||||
|
node->parent->right = left;
|
||||||
|
else
|
||||||
|
node->parent->left = left;
|
||||||
|
} else
|
||||||
|
root->node = left;
|
||||||
|
node->parent = left;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rb_insertcolor(RBTree *root, RBNode *node)
|
||||||
|
{
|
||||||
|
RBNode *parent, *gparent;
|
||||||
|
|
||||||
|
while ((parent = node->parent) && parent->color == Red) {
|
||||||
|
gparent = parent->parent;
|
||||||
|
|
||||||
|
if (parent == gparent->left) {
|
||||||
|
RBNode *uncle = gparent->right;
|
||||||
|
if (uncle && uncle->color == Red) {
|
||||||
|
uncle->color = Black;
|
||||||
|
parent->color = Black;
|
||||||
|
gparent->color = Red;
|
||||||
|
node = gparent;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent->right == node) {
|
||||||
|
RBNode *tmp;
|
||||||
|
rotateleft(root, parent);
|
||||||
|
tmp = parent;
|
||||||
|
parent = node;
|
||||||
|
node = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent->color = Black;
|
||||||
|
gparent->color = Red;
|
||||||
|
rotateright(root, gparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
RBNode *uncle = gparent->left;
|
||||||
|
if (uncle && uncle->color == Red) {
|
||||||
|
uncle->color = Black;
|
||||||
|
parent->color = Black;
|
||||||
|
gparent->color = Red;
|
||||||
|
node = gparent;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent->left == node) {
|
||||||
|
RBNode *tmp;
|
||||||
|
rotateright(root, parent);
|
||||||
|
tmp = parent;
|
||||||
|
parent = node;
|
||||||
|
node = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent->color = Black;
|
||||||
|
gparent->color = Red;
|
||||||
|
rotateleft(root, gparent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
root->node->color = Black;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
removecolor(RBTree *root, RBNode *node, RBNode *parent)
|
||||||
|
{
|
||||||
|
RBNode *other;
|
||||||
|
|
||||||
|
while ((!node || node->color == Black) && node != root->node) {
|
||||||
|
if (parent->left == node) {
|
||||||
|
other = parent->right;
|
||||||
|
if (other->color == Red) {
|
||||||
|
other->color = Black;
|
||||||
|
parent->color = Red;
|
||||||
|
rotateleft(root, parent);
|
||||||
|
other = parent->right;
|
||||||
|
}
|
||||||
|
if ((!other->left || other->left->color == Black)
|
||||||
|
&& (!other->right
|
||||||
|
|| other->right->color == Black)) {
|
||||||
|
other->color = Red;
|
||||||
|
node = parent;
|
||||||
|
parent = node->parent;
|
||||||
|
} else {
|
||||||
|
if (!other->right
|
||||||
|
|| other->right->color == Black) {
|
||||||
|
RBNode *o_left;
|
||||||
|
if ((o_left = other->left))
|
||||||
|
o_left->color = Black;
|
||||||
|
other->color = Red;
|
||||||
|
rotateright(root, other);
|
||||||
|
other = parent->right;
|
||||||
|
}
|
||||||
|
other->color = parent->color;
|
||||||
|
parent->color = Black;
|
||||||
|
if (other->right)
|
||||||
|
other->right->color = Black;
|
||||||
|
rotateleft(root, parent);
|
||||||
|
node = root->node;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
other = parent->left;
|
||||||
|
if (other->color == Red) {
|
||||||
|
other->color = Black;
|
||||||
|
parent->color = Red;
|
||||||
|
rotateright(root, parent);
|
||||||
|
other = parent->left;
|
||||||
|
}
|
||||||
|
if ((!other->left || other->left->color == Black)
|
||||||
|
&& (!other->right
|
||||||
|
|| other->right->color == Black)) {
|
||||||
|
other->color = Red;
|
||||||
|
node = parent;
|
||||||
|
parent = node->parent;
|
||||||
|
} else {
|
||||||
|
if (!other->left
|
||||||
|
|| other->left->color == Black) {
|
||||||
|
RBNode *o_right;
|
||||||
|
if ((o_right = other->right))
|
||||||
|
o_right->color = Black;
|
||||||
|
other->color = Red;
|
||||||
|
rotateleft(root, other);
|
||||||
|
other = parent->left;
|
||||||
|
}
|
||||||
|
other->color = parent->color;
|
||||||
|
parent->color = Black;
|
||||||
|
if (other->left)
|
||||||
|
other->left->color = Black;
|
||||||
|
rotateright(root, parent);
|
||||||
|
node = root->node;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node)
|
||||||
|
node->color = Black;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
uc_rb_remove(RBTree *root, RBNode *node)
|
||||||
|
{
|
||||||
|
RBNode *child, *parent;
|
||||||
|
int color;
|
||||||
|
|
||||||
|
if (!node->left)
|
||||||
|
child = node->right;
|
||||||
|
else if (!node->right)
|
||||||
|
child = node->left;
|
||||||
|
else {
|
||||||
|
RBNode *old = node, *left;
|
||||||
|
|
||||||
|
node = node->right;
|
||||||
|
while ((left = node->left))
|
||||||
|
node = left;
|
||||||
|
child = node->right;
|
||||||
|
parent = node->parent;
|
||||||
|
color = node->color;
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
child->parent = parent;
|
||||||
|
if (parent) {
|
||||||
|
if (parent->left == node)
|
||||||
|
parent->left = child;
|
||||||
|
else
|
||||||
|
parent->right = child;
|
||||||
|
} else
|
||||||
|
root->node = child;
|
||||||
|
|
||||||
|
if (node->parent == old)
|
||||||
|
parent = node;
|
||||||
|
node->parent = old->parent;
|
||||||
|
node->color = old->color;
|
||||||
|
node->right = old->right;
|
||||||
|
node->left = old->left;
|
||||||
|
|
||||||
|
if (old->parent) {
|
||||||
|
if (old->parent->left == old)
|
||||||
|
old->parent->left = node;
|
||||||
|
else
|
||||||
|
old->parent->right = node;
|
||||||
|
} else
|
||||||
|
root->node = node;
|
||||||
|
|
||||||
|
old->left->parent = node;
|
||||||
|
if (old->right)
|
||||||
|
old->right->parent = node;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent = node->parent;
|
||||||
|
color = node->color;
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
child->parent = parent;
|
||||||
|
if (parent) {
|
||||||
|
if (parent->left == node)
|
||||||
|
parent->left = child;
|
||||||
|
else
|
||||||
|
parent->right = child;
|
||||||
|
} else
|
||||||
|
root->node = child;
|
||||||
|
|
||||||
|
finish:
|
||||||
|
if (color == Black)
|
||||||
|
removecolor(root, child, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
RBNode*
|
||||||
|
uc_rb_find(RBTree *root, const void *val)
|
||||||
|
{
|
||||||
|
RBNode *n = root->node;
|
||||||
|
while (n) {
|
||||||
|
int d = root->compare(val,n->data);
|
||||||
|
if (d < 0)
|
||||||
|
n = n->left;
|
||||||
|
else if (d > 0)
|
||||||
|
n = n->right;
|
||||||
|
else
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
RBNode*
|
||||||
|
uc_rb_insert(RBTree *root, RBNode *child)
|
||||||
|
{
|
||||||
|
RBNode **p = &root->node;
|
||||||
|
RBNode *parent = NULL;
|
||||||
|
int d;
|
||||||
|
while (*p) {
|
||||||
|
parent = *p;
|
||||||
|
d = root->compare(child->data, parent->data);
|
||||||
|
if (d < 0)
|
||||||
|
p = &(*p)->left;
|
||||||
|
else if (d > 0)
|
||||||
|
p = &(*p)->right;
|
||||||
|
else
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
child->parent = parent;
|
||||||
|
child->color = Red;
|
||||||
|
child->left = child->right = NULL;
|
||||||
|
*p = child;
|
||||||
|
rb_insertcolor(root, child);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
RBNode *uc_rb_first(const RBTree *root)
|
||||||
|
{
|
||||||
|
RBNode *n = root->node;
|
||||||
|
if(n == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while(n->left)
|
||||||
|
n = n->left;
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
RBNode *uc_rb_next(RBNode *node)
|
||||||
|
{
|
||||||
|
if(node->right) { //down and left of the right branch
|
||||||
|
node = node->right;
|
||||||
|
|
||||||
|
while(node->left)
|
||||||
|
node = node->left;
|
||||||
|
|
||||||
|
} else { //up until we are not the right node
|
||||||
|
|
||||||
|
while(node->parent && node == node->parent->right)
|
||||||
|
node = node->parent;
|
||||||
|
|
||||||
|
node = node->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
RBNode *uc_rb_last(const RBTree *root)
|
||||||
|
{
|
||||||
|
RBNode *n = root->node;
|
||||||
|
|
||||||
|
if(n == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while(n->right)
|
||||||
|
n = n->right;
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
#ifndef RBTREE_H_
|
||||||
|
#define RBTREE_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum RBColor RBColor;
|
||||||
|
enum RBColor {
|
||||||
|
Red,
|
||||||
|
Black
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct RBNode RBNode;
|
||||||
|
struct RBNode {
|
||||||
|
unsigned char color; //Red/Black
|
||||||
|
RBNode *parent;
|
||||||
|
RBNode *right;
|
||||||
|
RBNode *left;
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct RBTree RBTree;
|
||||||
|
struct RBTree {
|
||||||
|
RBNode *node;
|
||||||
|
int (*compare)(const void *a, const void *b);
|
||||||
|
};
|
||||||
|
|
||||||
|
void uc_rb_remove(RBTree *root, RBNode *node);
|
||||||
|
RBNode *uc_rb_find(RBTree *root, const void *val);
|
||||||
|
RBNode *uc_rb_insert(RBTree *root, RBNode *child);
|
||||||
|
RBNode *uc_rb_first(const RBTree *root);
|
||||||
|
RBNode *uc_rb_next(RBNode *node);
|
||||||
|
RBNode *uc_rb_last(const RBTree *root);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include "ucore_read_file.h"
|
||||||
|
|
||||||
|
#define CHUNK_SZ 1024
|
||||||
|
|
||||||
|
char *
|
||||||
|
uc_read_file(const char *f, size_t *length, size_t max)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
char *s = NULL;
|
||||||
|
char *p;
|
||||||
|
struct stat statb;
|
||||||
|
size_t alloc_sz;
|
||||||
|
|
||||||
|
*length = 0;
|
||||||
|
|
||||||
|
if ((fd = open(f, O_RDONLY)) == -1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (fstat(fd, &statb) == -1) {
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((statb.st_mode & S_IFMT) == S_IFREG) {
|
||||||
|
if((size_t)statb.st_size > max) {
|
||||||
|
errno = EMSGSIZE;
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
alloc_sz = (size_t) statb.st_size + 1; // + 1 to avoid one realloc
|
||||||
|
s = malloc((size_t) alloc_sz + 1); //+1 for nul terminator
|
||||||
|
} else {
|
||||||
|
alloc_sz = CHUNK_SZ;
|
||||||
|
s = malloc(alloc_sz + 1); //+1 for nul terminator
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s == NULL) {
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = s;
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
ssize_t rc = read(fd, p, alloc_sz - (p - s));
|
||||||
|
if(rc == 0) {
|
||||||
|
*p = 0; // nul terminate. all malloc calls adds room for this byte
|
||||||
|
goto out_close;
|
||||||
|
} else if (rc == -1) {
|
||||||
|
goto out_err_free;
|
||||||
|
} else if(*length + rc > max) {
|
||||||
|
errno = EMSGSIZE;
|
||||||
|
goto out_err_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(p + rc == s + alloc_sz) { //reached end of allocated memory, grow it.
|
||||||
|
char *tmp = realloc(s, alloc_sz + CHUNK_SZ + 1);
|
||||||
|
if(tmp == NULL) {
|
||||||
|
goto out_err_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = tmp;
|
||||||
|
p = s + alloc_sz;
|
||||||
|
alloc_sz += CHUNK_SZ;
|
||||||
|
} else {
|
||||||
|
p += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
*length += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_err_free:
|
||||||
|
free(s);
|
||||||
|
s = NULL;
|
||||||
|
out_close:
|
||||||
|
close(fd);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef UCORE_READ_FILE_H_
|
||||||
|
#define UCORE_READ_FILE_H_y
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/** Read the content of a file.
|
||||||
|
* The returned char* is malloced memory and must be freed by the caller.
|
||||||
|
* The content is terminated by a nul byte, regardless of whether the content
|
||||||
|
* is binary or text. The returned length does not include this nul byte.
|
||||||
|
*
|
||||||
|
* @file_name name of the file
|
||||||
|
* @length Returned length of the content read
|
||||||
|
* @max Fail if the read content length is greater than max.
|
||||||
|
* @return The content read from the file, or NULL if something failed
|
||||||
|
* (inspect errno to see why it failed)
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
uc_read_file(const char *file_name, size_t *length, size_t max);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "ucore_salloc.h"
|
||||||
|
|
||||||
|
typedef struct Chunk Chunk;
|
||||||
|
struct Chunk {
|
||||||
|
Chunk *next;
|
||||||
|
size_t firstfree; //index to the first free byte in this chunk
|
||||||
|
union data { //for alignment
|
||||||
|
long long ll;
|
||||||
|
void *p;
|
||||||
|
double d;
|
||||||
|
size_t sz;
|
||||||
|
int i;
|
||||||
|
char data[1];
|
||||||
|
} data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SAlloc {
|
||||||
|
size_t chunksz; //data size of each chunk
|
||||||
|
Chunk *first; //head of the chunk list
|
||||||
|
Chunk *current;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Chunk *
|
||||||
|
add_chunk(SAlloc *p)
|
||||||
|
{
|
||||||
|
Chunk *newchunk;
|
||||||
|
|
||||||
|
newchunk = malloc(sizeof *newchunk + p->chunksz - (sizeof *newchunk - offsetof(Chunk, data.data)));
|
||||||
|
if(newchunk == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if(p->current != NULL)
|
||||||
|
p->current->next = newchunk;
|
||||||
|
|
||||||
|
newchunk->next = NULL;
|
||||||
|
newchunk->firstfree = 0;
|
||||||
|
|
||||||
|
return newchunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Chunk *
|
||||||
|
next_chunk(SAlloc *p)
|
||||||
|
{
|
||||||
|
Chunk *newchunk;
|
||||||
|
|
||||||
|
if(p->current->next) {
|
||||||
|
newchunk = p->current->next;
|
||||||
|
newchunk->firstfree = 0;
|
||||||
|
} else
|
||||||
|
newchunk = add_chunk(p);
|
||||||
|
|
||||||
|
if(newchunk)
|
||||||
|
p->current = newchunk;
|
||||||
|
|
||||||
|
return newchunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
SAlloc *
|
||||||
|
uc_new_salloc(size_t chunksz)
|
||||||
|
{
|
||||||
|
SAlloc *p;
|
||||||
|
Chunk *first;
|
||||||
|
p = malloc(sizeof *p);
|
||||||
|
if(p == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
p->chunksz = chunksz;
|
||||||
|
p->current = NULL;
|
||||||
|
|
||||||
|
if((first = add_chunk(p)) == NULL) {
|
||||||
|
free(p);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->first = p->current = first;
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
uc_reset_salloc(SAlloc *p)
|
||||||
|
{
|
||||||
|
Chunk *tmp;
|
||||||
|
|
||||||
|
for(tmp = p->first; tmp; tmp = tmp->next)
|
||||||
|
tmp->firstfree = 0;
|
||||||
|
|
||||||
|
p->current = p->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
uc_s_alloc(SAlloc *p,size_t sz)
|
||||||
|
{
|
||||||
|
Chunk *chunk;
|
||||||
|
void *newmem;
|
||||||
|
|
||||||
|
chunk = p->current;
|
||||||
|
if(chunk->firstfree + sz > p->chunksz) {
|
||||||
|
if(sz > p->chunksz)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
chunk = next_chunk(p);
|
||||||
|
if(chunk == NULL)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
newmem = &chunk->data.data[chunk->firstfree];
|
||||||
|
chunk->firstfree += sz;
|
||||||
|
|
||||||
|
return newmem;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
uc_s_allocz(SAlloc *p,size_t sz)
|
||||||
|
{
|
||||||
|
void *newmem = uc_s_alloc(p, sz);
|
||||||
|
|
||||||
|
if(newmem != NULL)
|
||||||
|
memset(newmem, 0, sz);
|
||||||
|
|
||||||
|
return newmem;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_chunks(Chunk *chunk)
|
||||||
|
{
|
||||||
|
Chunk *next;
|
||||||
|
|
||||||
|
for(next = NULL; chunk != NULL; chunk = next) {
|
||||||
|
next = chunk->next;
|
||||||
|
free(chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
uc_free_salloc(SAlloc *p)
|
||||||
|
{
|
||||||
|
free_chunks(p->first);
|
||||||
|
free(p);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
#ifndef SALLOC_H_
|
||||||
|
#define SALLOC_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
/** Sequntial memory allocator
|
||||||
|
*
|
||||||
|
* Allocates bigger chunks of memory at a time, to save the amount of malloc call,
|
||||||
|
* and enables you to free all that memory in one sweep.
|
||||||
|
*
|
||||||
|
* This means that once allocated, a piece of memory obtained from the
|
||||||
|
* allocator cannot be free'd individually, only the entire SAlloc can be free'd.
|
||||||
|
*
|
||||||
|
* Memory is allocated using the underlying malloc() in chunk sizes.
|
||||||
|
* Once a particular SAlloc has given out all memory in a chunk, a new chunk
|
||||||
|
* is allocated again, using the underlying malloc().
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Opaque handle to a SAlloc */
|
||||||
|
typedef struct SAlloc SAlloc;
|
||||||
|
|
||||||
|
/** Create a new SAlloc with the given size for each chunk.
|
||||||
|
* e.g. uc_new_salloc(sizeof(struct Foo) * 1000); will immedeatly
|
||||||
|
* allocate memory to hold 1000 struct Foo's. Once all that memory is
|
||||||
|
* handed out from this SAlloc, another piece of memory is allocaterd
|
||||||
|
* for another 1000 struct Foo's.. All these memory pieces are released
|
||||||
|
* when the uc_free_salloc() is called.
|
||||||
|
*
|
||||||
|
* @chunksz Size of each piece of memory block allocated.
|
||||||
|
* @return A new handle for a SAlloc, or NULL.
|
||||||
|
*/
|
||||||
|
SAlloc *uc_new_salloc(size_t chunksz);
|
||||||
|
|
||||||
|
/** Allocate memory from a SAlloc.
|
||||||
|
* @sz size of the memory. This must be <= the chunksz the SAlloc was
|
||||||
|
* created with.
|
||||||
|
* @return The new memory, or NULL if sz > chunksz or an underlying
|
||||||
|
* malloc call fails.
|
||||||
|
*/
|
||||||
|
void * uc_s_alloc(SAlloc *p,size_t sz);
|
||||||
|
|
||||||
|
/** Just like uc_s_alloc, but zero out the memory before returning it.
|
||||||
|
*/
|
||||||
|
void * uc_s_allocz(SAlloc *p,size_t sz);
|
||||||
|
/** Free the SAlloc and all memory associated with this SAlloc.
|
||||||
|
* The SAlloc is not usable any more after this call.
|
||||||
|
*
|
||||||
|
* @p The SAlloc to free.
|
||||||
|
*/
|
||||||
|
void uc_free_salloc(SAlloc *p);
|
||||||
|
|
||||||
|
/** Reset this SAlloc, effectivly releasing all the memory obtained.
|
||||||
|
* The SAlloc is still usable after this call.
|
||||||
|
* The actual memory previously allocated from this SAlloc is cached,
|
||||||
|
* and will be reused by subsequent uc_s_alloc calls.
|
||||||
|
*
|
||||||
|
* @p The SAlloc to reset.
|
||||||
|
*/
|
||||||
|
void uc_reset_salloc(SAlloc *p);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#include "ucore_hash.h"
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
sax_hash(void *key, size_t len)
|
||||||
|
{
|
||||||
|
unsigned char *p = key;
|
||||||
|
unsigned h = 0;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for ( i = 0; i < len; i++ )
|
||||||
|
h ^= ( h << 5 ) + ( h >> 2 ) + p[i];
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
unsigned long
|
||||||
|
sdbmhash(const unsigned char *str)
|
||||||
|
{
|
||||||
|
unsigned long hash = 0;
|
||||||
|
unsigned int c;
|
||||||
|
|
||||||
|
while ((c = *str++))
|
||||||
|
hash = c + (hash << 6) + (hash << 16) - hash;
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef SEQ_H_
|
||||||
|
#define SEQ_H_
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// Check if a is before b, taking care of wrap arounds
|
||||||
|
static inline int seq_before(uint32_t a, uint32_t b)
|
||||||
|
{
|
||||||
|
return (int32_t)(a - b) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if a is before b, taking care of wrap arounds
|
||||||
|
#define seq_after(a, b) before(b, a)
|
||||||
|
|
||||||
|
//check if a is between b or c
|
||||||
|
static inline int seqbetween(uint32_t a, uint32_t b, uint32_t c)
|
||||||
|
{
|
||||||
|
return c - b >= a - b;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "ucore_string.h"
|
||||||
|
|
||||||
|
|
||||||
|
char*
|
||||||
|
uc_sprintb(char *result, unsigned int value)
|
||||||
|
{
|
||||||
|
char *s = result;
|
||||||
|
unsigned mask = ~((unsigned) (~0) >> 1);
|
||||||
|
|
||||||
|
if (s) {
|
||||||
|
while (mask) {
|
||||||
|
*s++ = (mask & value) ? '1' : '0';
|
||||||
|
mask >>= 1;
|
||||||
|
}
|
||||||
|
*s = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "ucore_string.h"
|
||||||
|
|
||||||
|
char*
|
||||||
|
uc_sprintbc(char *result, unsigned char value)
|
||||||
|
{
|
||||||
|
char *s = result;
|
||||||
|
unsigned char mask = ~((unsigned char) (~0) >> 1);
|
||||||
|
|
||||||
|
if (s) {
|
||||||
|
while (mask) {
|
||||||
|
*s++ = (mask & value) ? '1' : '0';
|
||||||
|
mask >>= 1;
|
||||||
|
}
|
||||||
|
*s = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "ucore_string.h"
|
||||||
|
|
||||||
|
char*
|
||||||
|
uc_sprintbll(char *result, unsigned long long value)
|
||||||
|
{
|
||||||
|
char *s = result;
|
||||||
|
unsigned long long mask = ~((unsigned long long) (~0) >> 1);
|
||||||
|
|
||||||
|
if (s) {
|
||||||
|
while (mask) {
|
||||||
|
*s++ = (mask & value) ? '1' : '0';
|
||||||
|
mask >>= 1;
|
||||||
|
}
|
||||||
|
*s = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "ucore_string.h"
|
||||||
|
|
||||||
|
char*
|
||||||
|
uc_sprintbs(char *result, unsigned short value)
|
||||||
|
{
|
||||||
|
char *s = result;
|
||||||
|
unsigned short mask = ~((unsigned short) (~0) >> 1);
|
||||||
|
|
||||||
|
if (s) {
|
||||||
|
while (mask) {
|
||||||
|
*s++ = (mask & value) ? '1' : '0';
|
||||||
|
mask >>= 1;
|
||||||
|
}
|
||||||
|
*s = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
#ifndef UCORE_STRING_H_
|
||||||
|
#define UCORE_STRING_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
size_t
|
||||||
|
uc_base64_enc(const unsigned char *data,size_t len,unsigned char *result);
|
||||||
|
size_t
|
||||||
|
uc_base64_dec(const unsigned char *data, size_t len, unsigned char *result);
|
||||||
|
|
||||||
|
char*
|
||||||
|
uc_hex_encode(const uint8_t *in, size_t len, char *out);
|
||||||
|
uint8_t*
|
||||||
|
uc_hex_decode(const char *in, size_t maxlen,uint8_t *out);
|
||||||
|
char*
|
||||||
|
uc_hex_encode_delim(const uint8_t *in, size_t inlen, char *out, int outlen, char *delim);
|
||||||
|
|
||||||
|
void
|
||||||
|
uc_str_tolower(char *s);
|
||||||
|
void
|
||||||
|
uc_str_toupper(char *s);
|
||||||
|
|
||||||
|
#define UC_BCD_LEN(ascii_len) ((ascii_len) / 2 + ((ascii_len) % 2))
|
||||||
|
#define UC_ASCII_LEN(bcd_len) ((bcd_len) * 2 + 1)
|
||||||
|
|
||||||
|
size_t
|
||||||
|
uc_ascii2bcd(const char *ascii, unsigned char *bcdout, unsigned char filler);
|
||||||
|
size_t
|
||||||
|
uc_bcd2ascii(const unsigned char *bcd, size_t bcdlen, char *asciiout);
|
||||||
|
|
||||||
|
char*
|
||||||
|
uc_sprintb(char *result, unsigned int value);
|
||||||
|
char*
|
||||||
|
uc_sprintbc(char *result, unsigned char value);
|
||||||
|
char*
|
||||||
|
uc_sprintbll(char *result, unsigned long long value);
|
||||||
|
char*
|
||||||
|
uc_sprintbs(char *result, unsigned short value);
|
||||||
|
|
||||||
|
int
|
||||||
|
getfields(char *str, char **args, int max, int mflag, const char *set);
|
||||||
|
|
||||||
|
//ocnvert bytes to a human representable test, (i.e. 12kB, 160 MB 1.78 GB etc.
|
||||||
|
///result should be at least of size 12,
|
||||||
|
///returns the result argument
|
||||||
|
char *
|
||||||
|
uc_human_bytesz(uint64_t bytes, char *result, size_t result_len);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#include <ctype.h>
|
||||||
|
#include "ucore_string.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
uc_str_tolower(char *s)
|
||||||
|
{
|
||||||
|
while (*s) {
|
||||||
|
*s = tolower((unsigned char)*s);
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#include <ctype.h>
|
||||||
|
#include "ucore_string.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
uc_str_toupper(char *s)
|
||||||
|
{
|
||||||
|
while (*s) {
|
||||||
|
*s = toupper((unsigned char)*s);
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include "ucore_timers.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int timers_cmp(const void *a_, const void *b_)
|
||||||
|
{
|
||||||
|
const struct UCTimer *a = a_;
|
||||||
|
const struct UCTimer *b = b_;
|
||||||
|
|
||||||
|
if(timercmp(&a->timeout, &b->timeout, <)) {
|
||||||
|
return -1;
|
||||||
|
} else if (timercmp(&a->timeout, &b->timeout, >)) {
|
||||||
|
return 1;
|
||||||
|
} else { //check sequence number
|
||||||
|
if(a->seq < b->seq) {
|
||||||
|
return -1;
|
||||||
|
} else if(a->seq > b->seq) {
|
||||||
|
return 1;
|
||||||
|
} else { //should never happen
|
||||||
|
//assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//assert(0);
|
||||||
|
return 0; //silence compiler
|
||||||
|
}
|
||||||
|
|
||||||
|
static void uc_timer_real_add(struct UCTimers *timers, struct UCTimer *timer)
|
||||||
|
{
|
||||||
|
uc_timer_remove(timers, timer); //re schedule it if it's already running
|
||||||
|
timer->state = UC_TIMER_ACTIVE;
|
||||||
|
timer->seq = timers->seq++;
|
||||||
|
timer->rb_node.data = timer; //point the data in a RBNode back to the timer that contains it.
|
||||||
|
uc_rb_insert(&timers->timers, &timer->rb_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uc_timers_init(struct UCTimers *t)
|
||||||
|
{
|
||||||
|
t->timers.node = NULL;
|
||||||
|
t->timers.compare = timers_cmp;
|
||||||
|
t->seq = 0;
|
||||||
|
TAILQ_INIT(&t->ready_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uc_timer_add(struct UCTimers *timers, struct UCTimer *timer, int sec, int usec)
|
||||||
|
{
|
||||||
|
struct timeval now;
|
||||||
|
struct timeval tmp;
|
||||||
|
|
||||||
|
assert(timer->callback != NULL);
|
||||||
|
if(timer->callback == NULL) //must be set.
|
||||||
|
return;
|
||||||
|
|
||||||
|
tmp.tv_sec = sec;
|
||||||
|
tmp.tv_usec = usec;
|
||||||
|
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
timeradd(&now, &tmp, &timer->timeout);
|
||||||
|
uc_timer_real_add(timers, timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uc_timer_remove(struct UCTimers *timers, struct UCTimer *timer)
|
||||||
|
{
|
||||||
|
if(timer->state == UC_TIMER_INACTIVE) { //already removed , or never added.
|
||||||
|
//debugging bandaid
|
||||||
|
timer->ready_entry.tqe_next = (struct UCTimer *)104;
|
||||||
|
timer->ready_entry.tqe_prev = (struct UCTimer **)105;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uc_rb_remove(&timers->timers, &timer->rb_node); //remove it, safe for the
|
||||||
|
//callback to re_add it
|
||||||
|
if(timer->state == UC_TIMER_PENDING) {
|
||||||
|
//timer is pending for callback, remove it from the list
|
||||||
|
//so code in uc_timers_run does not touch it.
|
||||||
|
TAILQ_REMOVE(&timers->ready_list, timer, ready_entry);
|
||||||
|
}
|
||||||
|
timer->state = UC_TIMER_INACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int uc_timers_first(const struct UCTimers *timers, struct timeval *first)
|
||||||
|
{
|
||||||
|
const RBNode *n = uc_rb_first(&timers->timers);
|
||||||
|
if(n) {
|
||||||
|
struct UCTimer *timer = n->data;
|
||||||
|
*first = timer->timeout;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t uc_timer_count(const struct UCTimers *timers)
|
||||||
|
{
|
||||||
|
struct RBNode *n;
|
||||||
|
size_t count = 0;
|
||||||
|
|
||||||
|
for(n = uc_rb_first(&timers->timers); n ; n = uc_rb_next(n)) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int uc_timer_running(const struct UCTimer *timer)
|
||||||
|
{
|
||||||
|
return timer->state;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uc_timers_run(struct UCTimers *timers, const struct timeval *now)
|
||||||
|
{
|
||||||
|
RBNode *node;
|
||||||
|
int cnt = 0;
|
||||||
|
|
||||||
|
/* First find all the expired nodes, place them in a linked list.
|
||||||
|
* Callbacks cannot be performed here, as the callback might alter
|
||||||
|
* the rbtree and timers
|
||||||
|
*/
|
||||||
|
assert(TAILQ_EMPTY(&timers->ready_list)); //somethings serious wrong if it isn't already empty
|
||||||
|
TAILQ_INIT(&timers->ready_list);
|
||||||
|
for(node = uc_rb_first(&timers->timers); node ; node = uc_rb_next(node)) {
|
||||||
|
struct UCTimer *t = node->data;
|
||||||
|
//Note, timercmp does not work for >=
|
||||||
|
if(!timercmp(now, &t->timeout, <)) {
|
||||||
|
TAILQ_INSERT_TAIL(&timers->ready_list, t, ready_entry);
|
||||||
|
t->state = UC_TIMER_PENDING; //so uc_timer_remove knows
|
||||||
|
//it have to remove it from the ready_list
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*run through the list and fire callbacks.
|
||||||
|
* It is ok for a callback to remove another
|
||||||
|
* timer that's either running or pending
|
||||||
|
* Need to always pick the first item in the tail queue
|
||||||
|
* since a timer callback could remove/free a timer
|
||||||
|
* we had in the list.
|
||||||
|
* uc_timer_remove will unlink the timer from this list.
|
||||||
|
*/
|
||||||
|
while(!TAILQ_EMPTY(&timers->ready_list)) {
|
||||||
|
struct UCTimer *t = TAILQ_FIRST(&timers->ready_list);
|
||||||
|
|
||||||
|
uc_timer_remove(timers, t);
|
||||||
|
assert(t->callback != NULL);
|
||||||
|
t->callback(timers, t); //fire
|
||||||
|
// callback might have free'd its timer.
|
||||||
|
// Do not touch 't' after this.
|
||||||
|
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
#ifndef UCORE_TIMERS_H_
|
||||||
|
#define UCORE_TIMERS_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include "ucore_rbtree.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct UCTimer;
|
||||||
|
struct UCTimers;
|
||||||
|
|
||||||
|
//timer states
|
||||||
|
enum {
|
||||||
|
//not running
|
||||||
|
UC_TIMER_INACTIVE = 0,
|
||||||
|
//running
|
||||||
|
UC_TIMER_ACTIVE = 1,
|
||||||
|
//running and pending to be fired in this run of uc_timers_run
|
||||||
|
UC_TIMER_PENDING = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*uc_timer_cb)(struct UCTimers *timers, struct UCTimer *timer);
|
||||||
|
struct UCTimer {
|
||||||
|
//internal members
|
||||||
|
RBNode rb_node; //the RBNode will hold a data pointer to the
|
||||||
|
//the UCTimer it's a member of. We might get rid of that member, and use CONTAINER_OF
|
||||||
|
//to find the UCTimer from a RBNode
|
||||||
|
//
|
||||||
|
//absolute time when the timer should be fired
|
||||||
|
struct timeval timeout;
|
||||||
|
size_t seq; //needed to keep timeout unique
|
||||||
|
//as the rbtree can only handle unique values
|
||||||
|
unsigned char state;
|
||||||
|
TAILQ_ENTRY(UCTimer) ready_entry; //entry in ready_list in UCTimers
|
||||||
|
|
||||||
|
//callback function
|
||||||
|
uc_timer_cb callback;
|
||||||
|
|
||||||
|
//user data for the callback
|
||||||
|
void *cookie_ptr;
|
||||||
|
int cookie_int;
|
||||||
|
int cookie_int2;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct UCTimers {
|
||||||
|
RBTree timers;
|
||||||
|
size_t seq; //used to generate unique timers
|
||||||
|
TAILQ_HEAD(, UCTimer) ready_list; //pending timers to be fired while inside uc_timers_run
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void uc_timer_remove(struct UCTimers *timers, struct UCTimer *timer);
|
||||||
|
void uc_timers_init(struct UCTimers *t);
|
||||||
|
void uc_timer_add(struct UCTimers *timers, struct UCTimer *timer, int sec, int usec);
|
||||||
|
void uc_timer_remove(struct UCTimers *timers, struct UCTimer *timer);
|
||||||
|
int uc_timers_first(const struct UCTimers *timers, struct timeval *first);
|
||||||
|
size_t uc_timer_count(const struct UCTimers *timers);
|
||||||
|
int uc_timer_running(const struct UCTimer *timer);
|
||||||
|
int uc_timers_run(struct UCTimers *timers, const struct timeval *now);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
struct timeval *
|
||||||
|
uc_tvadd(struct timeval *dst, const struct timeval *a, const struct timeval *b)
|
||||||
|
{
|
||||||
|
dst->tv_sec = a->tv_sec + b->tv_sec;
|
||||||
|
dst->tv_usec = a->tv_usec + b->tv_usec;
|
||||||
|
|
||||||
|
if (dst->tv_usec >= 1000000)
|
||||||
|
dst->tv_sec++, dst->tv_usec -= 1000000;
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct timeval *
|
||||||
|
uc_tvsub(struct timeval *dst, const struct timeval *a, const struct timeval *b)
|
||||||
|
{
|
||||||
|
dst->tv_sec = a->tv_sec - b->tv_sec;
|
||||||
|
dst->tv_usec = a->tv_usec - b->tv_usec;
|
||||||
|
|
||||||
|
if (dst->tv_usec < 0)
|
||||||
|
dst->tv_sec--, dst->tv_usec += 1000000;
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
uc_tvcmp(const struct timeval *a, const struct timeval *b)
|
||||||
|
{
|
||||||
|
if(a->tv_sec < b->tv_sec)
|
||||||
|
return -1;
|
||||||
|
else if(a->tv_sec > b->tv_sec)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (a->tv_usec < b->tv_usec)
|
||||||
|
return -1;
|
||||||
|
else if (a->tv_usec > b->tv_usec)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct timeval *
|
||||||
|
uc_to2tv(struct timeval *dst, unsigned long ms)
|
||||||
|
{
|
||||||
|
dst->tv_sec = ms / 1000;
|
||||||
|
dst->tv_usec = ms % 1000 * 1000;
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#ifndef UCORE_UTILS_H_
|
||||||
|
#define UCORE_UTILS_H_
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
//Gnerate a compiler error if the compile time
|
||||||
|
//constant expression fails
|
||||||
|
#define STATIC_ASSERT(expr) \
|
||||||
|
do { \
|
||||||
|
enum { assert_static__ = 1/(expr) }; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define TRACEF(fmt, ...)\
|
||||||
|
do { \
|
||||||
|
fprintf(stderr, "%s:%s(%d)" fmt, __FILE__, __FUNCTION__, __LINE,__VA_ARGS__);\
|
||||||
|
} while(0)
|
||||||
|
#else
|
||||||
|
#define TRACEF(fmt, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//MAX of a and b
|
||||||
|
#define UC_MAX(a,b) \
|
||||||
|
({ __typeof__ (a) _a = (a); \
|
||||||
|
__typeof__ (b) _b = (b); \
|
||||||
|
_a > _b ? _a : _b; })
|
||||||
|
|
||||||
|
//min of a and b
|
||||||
|
#define UC_MIN(a,b) \
|
||||||
|
({ __typeof__ (a) _a = (a); \
|
||||||
|
__typeof__ (b) _b = (b); \
|
||||||
|
_a < _b ? _a : _b; })
|
||||||
|
|
||||||
|
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a))
|
||||||
|
|
||||||
|
//given 'ptr' as a pointer to a struct 'member',
|
||||||
|
//find the struct that ptr is the member of, where
|
||||||
|
//'type' is the type of the containing struct
|
||||||
|
//e.g.
|
||||||
|
//struct foo {
|
||||||
|
// int i;
|
||||||
|
// struct bar zap;
|
||||||
|
//};
|
||||||
|
// ...
|
||||||
|
//struct bar *p = ..; //the local p is a pointer to
|
||||||
|
//a 'zap' member inside a struct foo.
|
||||||
|
//give us the struct foo*:
|
||||||
|
//struct foo *f = CONTAINER_OF(p, struct foo, zap);
|
||||||
|
#define CONTAINER_OF(ptr, type, member) ({ \
|
||||||
|
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||||
|
(type *)( (char *)__mptr - offsetof(type, member) ); })
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
const int ucore_version_major = @version_major@;
|
||||||
|
const int ucore_version_minor = @version_minor@;
|
||||||
|
const int ucore_version_patch = @version_patch@;
|
||||||
|
|
||||||
|
const char ucore_version_str[] = "@version_major@.@version_minor@.@version_patch@.@version_revision@";
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#ifndef UCORE_VERSION_H_
|
||||||
|
#define UCORE_VERSION_H_
|
||||||
|
|
||||||
|
extern const int ucore_version_major;
|
||||||
|
extern const int ucore_version_minor;
|
||||||
|
extern const int ucore_version_patch;
|
||||||
|
|
||||||
|
extern const char ucore_version_str[];
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import os
|
||||||
|
Import('env', 'build_type', 'prefix', 'version_info', 'test_xml')
|
||||||
|
|
||||||
|
test_env = env.Clone()
|
||||||
|
test_env.Append(LIBPATH = ['#build/src']);
|
||||||
|
test_env.Append(CPPPATH = ['#src'])
|
||||||
|
test_env.Append(LIBS = ['ucore_' + build_type, 'check'])
|
||||||
|
|
||||||
|
tests = test_env.Glob('test_*.c')
|
||||||
|
|
||||||
|
test_executable = 'test_runner'
|
||||||
|
#run test_runner --xml to produce an xml result file
|
||||||
|
if test_xml:
|
||||||
|
test_executable += ' --xml'
|
||||||
|
|
||||||
|
prog = test_env.Program('test_runner', tests)
|
||||||
|
cmd = test_env.Command(target='test_phony' ,
|
||||||
|
source = None,
|
||||||
|
action= test_env.Dir('.').abspath + '/' + test_executable)
|
||||||
|
test_env.Depends(cmd, prog)
|
||||||
|
test_env.AlwaysBuild(cmd)
|
||||||
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "iomux.h"
|
||||||
|
|
||||||
|
extern struct IOMuxFD s_fd;
|
||||||
|
|
||||||
|
void stdin_read_cb(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event)
|
||||||
|
{
|
||||||
|
char buf[64];
|
||||||
|
ssize_t len = read(fd->fd, buf, sizeof buf);
|
||||||
|
printf("Read %d bytes\n", len);
|
||||||
|
iomux_unregister_fd(mux, fd);
|
||||||
|
if(len > 0) {
|
||||||
|
s_fd.what = MUX_EV_READ;
|
||||||
|
iomux_register_fd(mux, &s_fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct IOMuxFD s_fd = {
|
||||||
|
.fd = 0,
|
||||||
|
.what = MUX_EV_READ,
|
||||||
|
.callback = stdin_read_cb,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct IOMux *mux = iomux_create(IOMUX_TYPE_DEFAULT);
|
||||||
|
iomux_register_fd(mux, &s_fd);
|
||||||
|
iomux_run(mux);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include "iomux.h"
|
||||||
|
|
||||||
|
extern struct IOMuxFD s_fd;
|
||||||
|
|
||||||
|
void stdin_read_cb(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event)
|
||||||
|
{
|
||||||
|
char buf[4096];
|
||||||
|
ssize_t len = read(fd->fd, buf, sizeof buf);
|
||||||
|
if(len <= 0) {
|
||||||
|
perror("read");
|
||||||
|
fprintf(stderr,"Unregister stdin fd %d\n", fd->fd);
|
||||||
|
iomux_unregister_fd(mux, fd);
|
||||||
|
close(fd->fd);
|
||||||
|
close(fd->cookie_int);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
write(fd->cookie_int, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pipe_read_cb(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event)
|
||||||
|
{
|
||||||
|
char buf[4095];
|
||||||
|
ssize_t len = read(fd->fd, buf, sizeof buf);
|
||||||
|
if(len <= 0) {
|
||||||
|
perror("pipe read");
|
||||||
|
printf("Unregister pipe fd %d [stdout]\n", fd->fd);
|
||||||
|
fprintf(stderr,"Unregister pipe fd %d[stderr]\n", fd->fd);
|
||||||
|
iomux_unregister_fd(mux, fd);
|
||||||
|
close(fd->cookie_int);
|
||||||
|
fclose(fd->cookie_ptr);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
fwrite(buf, 1 , len, fd->cookie_ptr);
|
||||||
|
fflush(fd->cookie_ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *writer(void *arg)
|
||||||
|
{
|
||||||
|
struct IOMux *mux = arg;
|
||||||
|
iomux_run(mux);
|
||||||
|
printf("writer mux returned\n");
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct IOMux *mux1 = iomux_create(IOMUX_TYPE_DEFAULT);
|
||||||
|
struct IOMux *mux2 = iomux_create(IOMUX_TYPE_DEFAULT);
|
||||||
|
int pfd[2];
|
||||||
|
int rc;
|
||||||
|
struct IOMuxFD fd1 = {0};
|
||||||
|
struct IOMuxFD fd2 = {0};
|
||||||
|
pthread_t tid;
|
||||||
|
pipe(pfd);
|
||||||
|
|
||||||
|
fd1.fd = 0;
|
||||||
|
fd1.what = MUX_EV_READ;
|
||||||
|
fd1.cookie_int = pfd[1];
|
||||||
|
fd1.callback = stdin_read_cb;
|
||||||
|
|
||||||
|
fd2.fd = pfd[0];
|
||||||
|
fd2.what = MUX_EV_READ;
|
||||||
|
fd2.cookie_ptr = fopen("out", "wb");
|
||||||
|
fd2.callback = pipe_read_cb;
|
||||||
|
|
||||||
|
|
||||||
|
rc = iomux_register_fd(mux1, &fd1);
|
||||||
|
if(rc != 0)
|
||||||
|
printf("Cannot register fd1: %s\n", strerror(rc));
|
||||||
|
rc = iomux_register_fd(mux2, &fd2);
|
||||||
|
if(rc != 0)
|
||||||
|
printf("Cannot register fdw: %s\n", strerror(rc));
|
||||||
|
pthread_create(&tid,NULL,writer,mux2);
|
||||||
|
iomux_run(mux1);
|
||||||
|
printf("reader mux returned\n");
|
||||||
|
pthread_join(tid, NULL);
|
||||||
|
iomux_delete(mux1);
|
||||||
|
iomux_delete(mux2);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include "iomux.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define BUFLEN (4098*66)
|
||||||
|
|
||||||
|
struct Copy {
|
||||||
|
struct IOMuxFD in;
|
||||||
|
struct IOMuxFD out;
|
||||||
|
|
||||||
|
char buffer[BUFLEN];
|
||||||
|
size_t w_idx;
|
||||||
|
size_t r_idx;
|
||||||
|
int out_running;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void in_cb(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event)
|
||||||
|
{
|
||||||
|
struct Copy *copy_ctx = fd->cookie_ptr;
|
||||||
|
size_t left = BUFLEN - copy_ctx->w_idx;
|
||||||
|
ssize_t rc;
|
||||||
|
left /= 2;
|
||||||
|
if(left == 0)
|
||||||
|
left++;
|
||||||
|
|
||||||
|
|
||||||
|
rc = read(fd->fd, ©_ctx->buffer[copy_ctx->w_idx], left);
|
||||||
|
if(rc <= 0) {
|
||||||
|
if(rc == -1 && errno == EAGAIN) {
|
||||||
|
return;
|
||||||
|
} else if(rc == -1) {
|
||||||
|
perror("read");
|
||||||
|
}
|
||||||
|
iomux_unregister_fd(mux, fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_ctx->w_idx += rc;
|
||||||
|
|
||||||
|
if(!copy_ctx->out_running) {
|
||||||
|
copy_ctx->out.what = MUX_EV_WRITE;
|
||||||
|
iomux_register_fd(mux, ©_ctx->out);
|
||||||
|
copy_ctx->out_running = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(copy_ctx->w_idx == BUFLEN) {
|
||||||
|
iomux_unregister_fd(mux, fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void out_cb(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event)
|
||||||
|
{
|
||||||
|
struct Copy *copy_ctx = fd->cookie_ptr;
|
||||||
|
ssize_t rc;
|
||||||
|
size_t len = copy_ctx->w_idx - copy_ctx->r_idx;
|
||||||
|
|
||||||
|
rc = write(1, ©_ctx->buffer[copy_ctx->r_idx], len);
|
||||||
|
if(rc <= 0) {
|
||||||
|
if(rc == -1 && errno == EAGAIN) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
perror("write");
|
||||||
|
iomux_unregister_fd(mux, ©_ctx->in);
|
||||||
|
}
|
||||||
|
iomux_unregister_fd(mux, fd);
|
||||||
|
copy_ctx->out_running = 0;
|
||||||
|
} else {
|
||||||
|
copy_ctx->r_idx += rc;
|
||||||
|
if(copy_ctx->r_idx == copy_ctx->w_idx) {
|
||||||
|
iomux_unregister_fd(mux, fd);
|
||||||
|
copy_ctx->out_running = 0;
|
||||||
|
if(copy_ctx->w_idx == BUFLEN) {
|
||||||
|
copy_ctx->w_idx = 0;
|
||||||
|
copy_ctx->r_idx = 0;
|
||||||
|
iomux_register_fd(mux, ©_ctx->in);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int set_nonblocking(int fd)
|
||||||
|
{
|
||||||
|
int flags = fcntl(fd,F_GETFL,NULL);
|
||||||
|
if(flags < 0 ) {
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
return fcntl(fd,F_SETFL,flags | O_NONBLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void timer_cb(struct UCTimers *timers, struct UCTimer *timer)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Timer %d fired\n", timer->cookie_int);
|
||||||
|
struct UCTimer *t = calloc(1, sizeof *t);
|
||||||
|
t->callback = timer_cb;
|
||||||
|
t->cookie_int = timer->cookie_int + 1;
|
||||||
|
uc_timer_add(timers, t, 5,5);
|
||||||
|
t = calloc(1, sizeof *t);
|
||||||
|
t->callback = timer_cb;
|
||||||
|
t->cookie_int = timer->cookie_int + 2;
|
||||||
|
uc_timer_add(timers, t, 5,4);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct Copy copy_ctx = {
|
||||||
|
.in = {
|
||||||
|
.fd = 0,
|
||||||
|
.what = MUX_EV_READ,
|
||||||
|
.callback = in_cb,
|
||||||
|
.cookie_ptr = ©_ctx,
|
||||||
|
},
|
||||||
|
.out = {
|
||||||
|
.fd = 1,
|
||||||
|
.callback = out_cb,
|
||||||
|
.cookie_ptr = ©_ctx,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct UCTimer timer = {
|
||||||
|
.callback = timer_cb,
|
||||||
|
};
|
||||||
|
set_nonblocking(0);
|
||||||
|
set_nonblocking(1);
|
||||||
|
|
||||||
|
struct IOMux *mux = iomux_create(IOMUX_TYPE_EPOLL);
|
||||||
|
iomux_register_fd(mux, ©_ctx.in);
|
||||||
|
uc_timer_add(iomux_get_timers(mux), &timer, 5, 0);
|
||||||
|
|
||||||
|
iomux_run(mux);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
#include "ucore_logging.h"
|
||||||
|
#include "ucore_utils.h"
|
||||||
|
#include <syslog.h>
|
||||||
|
enum {
|
||||||
|
MAIN,
|
||||||
|
CC,
|
||||||
|
HO
|
||||||
|
};
|
||||||
|
struct uc_log_module module_arr[] = {
|
||||||
|
{
|
||||||
|
MAIN,
|
||||||
|
"MAIN",
|
||||||
|
"Main module",
|
||||||
|
UC_LL_WARNING
|
||||||
|
},
|
||||||
|
{
|
||||||
|
CC,
|
||||||
|
"CC",
|
||||||
|
"Call Control module",
|
||||||
|
UC_LL_DEBUG,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
HO,
|
||||||
|
"HO",
|
||||||
|
"Handover module",
|
||||||
|
UC_LL_DEBUG
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct uc_log_modules modules = {
|
||||||
|
.mods = module_arr,
|
||||||
|
.cnt = ARRAY_SIZE(module_arr),
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct uc_log_destination *dest = uc_log_new_stderr(UC_LL_INFO, 0);
|
||||||
|
uc_log_init(&modules);
|
||||||
|
uc_log_add_destination(dest);
|
||||||
|
dest = uc_log_new_file("test.log", UC_LL_INFO, 1);
|
||||||
|
uc_log_add_destination(dest);
|
||||||
|
dest = uc_log_new_syslog("log.test", LOG_DAEMON, UC_LL_INFO, 0);
|
||||||
|
uc_log_add_destination(dest);
|
||||||
|
UC_LOGF( UC_LL_INFO, CC, "Test cc info %d\n", 2);
|
||||||
|
UC_LOGF( UC_LL_WARNING, HO, "Test HO warning%d\n", 2);
|
||||||
|
UC_LOGF( UC_LL_INFO, MAIN, "Test MAIN info \n" );
|
||||||
|
UC_LOGF( UC_LL_WARNING, MAIN, "Test MAIN warning\n" );
|
||||||
|
uc_log_module_set_loglevel(MAIN, UC_LL_INFO);
|
||||||
|
UC_LOGF( UC_LL_INFO, MAIN, "Test MAIN warning 2\n" );
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include "ucore_salloc.h"
|
||||||
|
|
||||||
|
// Intended to be run under valgrind. Should show no errors
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char *argv)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
SAlloc *s = uc_new_salloc(36 * 100);
|
||||||
|
for(i = 0; i < 100; i++) {
|
||||||
|
void *p = uc_s_alloc(s, 36);
|
||||||
|
memset(p,7,36);
|
||||||
|
}
|
||||||
|
|
||||||
|
uc_free_salloc(s);
|
||||||
|
|
||||||
|
s = uc_new_salloc(85 * 100);
|
||||||
|
for(i = 0; i < 100 * 3; i++) {
|
||||||
|
void *p = uc_s_alloc(s, 85);
|
||||||
|
memset(p,7,85);
|
||||||
|
}
|
||||||
|
|
||||||
|
uc_free_salloc(s);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include "ucore_seq.h"
|
||||||
|
|
||||||
|
|
||||||
|
void check_before(uint32_t a, uint32_t b)
|
||||||
|
{
|
||||||
|
printf("%lu before %lu = %d\n", a ,b, seq_before(a, b));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
check_before(0, 1);
|
||||||
|
check_before(1, 0);
|
||||||
|
check_before(0, 0xffffffff);
|
||||||
|
check_before(0, 0xffff);
|
||||||
|
check_before(0, 0x1ffff);
|
||||||
|
check_before(0xffff, 0xffffffff);
|
||||||
|
check_before(0x7fffffffU - 1, 0xffffffff);
|
||||||
|
check_before(0x7fffffffU + 1, 0xffffffff);
|
||||||
|
check_before(0x7fffffffU + 1, 0x7fffffffU);
|
||||||
|
check_before(0x7fffffffU - 1, 0x7fffffffU);
|
||||||
|
check_before(0x7fffffffU, 0x7fffffffU - 1);
|
||||||
|
check_before(0x7fffffffU, 0x7fffffffU + 1);
|
||||||
|
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
+151
@@ -0,0 +1,151 @@
|
|||||||
|
#include <check.h>
|
||||||
|
#include "ucore_string.h"
|
||||||
|
|
||||||
|
|
||||||
|
START_TEST (test_2bcd_1234567890)
|
||||||
|
char ascii[] = "1234567890";
|
||||||
|
unsigned char bcd[5];
|
||||||
|
size_t len = uc_ascii2bcd(ascii, bcd, 0);
|
||||||
|
|
||||||
|
fail_if(len != 5, "len is %zu", len);
|
||||||
|
fail_if(bcd[0] != 0x21,"was 0x%x",bcd[0]);
|
||||||
|
fail_if(bcd[1] != 0x43,"was 0x%x",bcd[1]);
|
||||||
|
fail_if(bcd[2] != 0x65,"was 0x%x",bcd[2]);
|
||||||
|
fail_if(bcd[3] != 0x87,"was 0x%x",bcd[3]);
|
||||||
|
fail_if(bcd[4] != 0x09,"was 0x%x",bcd[4]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_2bcd_empty)
|
||||||
|
char ascii[] = "";
|
||||||
|
unsigned char bcd[1];
|
||||||
|
size_t len = uc_ascii2bcd(ascii, bcd, 3);
|
||||||
|
|
||||||
|
fail_if(len != 0, "len is %zu", len);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_2bcd_1_filler)
|
||||||
|
char ascii[] = "1";
|
||||||
|
unsigned char bcd[1];
|
||||||
|
size_t len = uc_ascii2bcd(ascii, bcd, 0xa);
|
||||||
|
|
||||||
|
fail_if(len != 1, "len is %zu", len);
|
||||||
|
fail_if(bcd[0] != 0xa1,"was 0x%x",bcd[0]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_2bcd_2_filler)
|
||||||
|
char ascii[] = "123";
|
||||||
|
unsigned char bcd[2];
|
||||||
|
size_t len = uc_ascii2bcd(ascii, bcd, 0xf);
|
||||||
|
|
||||||
|
fail_if(len != 2, "len is %zu", len);
|
||||||
|
fail_if(bcd[0] != 0x21,"was 0x%x",bcd[0]);
|
||||||
|
fail_if(bcd[1] != 0xf3,"was 0x%x",bcd[1]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_2bcd_3_filler)
|
||||||
|
|
||||||
|
char ascii[] = "123";
|
||||||
|
unsigned char bcd[2];
|
||||||
|
size_t len = uc_ascii2bcd(ascii, bcd, 0x0);
|
||||||
|
|
||||||
|
fail_if(len != 2, "len is %zu", len);
|
||||||
|
fail_if(bcd[0] != 0x21,"was 0x%x",bcd[0]);
|
||||||
|
fail_if(bcd[1] != 0x03,"was 0x%x",bcd[1]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_2bcd_non_digits)
|
||||||
|
|
||||||
|
char ascii[] = "a,b{ }=";
|
||||||
|
unsigned char bcd[10];
|
||||||
|
size_t len = uc_ascii2bcd(ascii, bcd, 0x0);
|
||||||
|
|
||||||
|
fail_if(len != 0, "len is %zu", len);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_2bcd_phoneno)
|
||||||
|
|
||||||
|
char ascii[] = "0047-3233-4";
|
||||||
|
unsigned char bcd[24];
|
||||||
|
size_t len = uc_ascii2bcd(ascii, bcd, 0xf);
|
||||||
|
|
||||||
|
fail_if(len != 5, "len is %zu", len);
|
||||||
|
fail_if(bcd[0] != 0x00,"was 0x%x",bcd[0]);
|
||||||
|
fail_if(bcd[1] != 0x74,"was 0x%x",bcd[1]);
|
||||||
|
fail_if(bcd[2] != 0x23,"was 0x%x",bcd[1]);
|
||||||
|
fail_if(bcd[3] != 0x33,"was 0x%x",bcd[1]);
|
||||||
|
fail_if(bcd[4] != 0xf4,"was 0x%x",bcd[1]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_2bcd_binary)
|
||||||
|
|
||||||
|
char ascii[] = {0x32,0x01,0xAF,0xFF,0x00};
|
||||||
|
unsigned char bcd[24];
|
||||||
|
size_t len = uc_ascii2bcd(ascii, bcd, 0xf);
|
||||||
|
|
||||||
|
fail_if(len != 1, "len is %zu", len);
|
||||||
|
fail_if(bcd[0] != 0xf2,"0 was 0x%x",bcd[0]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_2hex_1)
|
||||||
|
|
||||||
|
unsigned char bcd[] = {0x21, 0x43 };
|
||||||
|
char ascii[sizeof bcd * 2 + 1];
|
||||||
|
size_t len = uc_bcd2ascii(bcd, sizeof bcd, ascii);
|
||||||
|
|
||||||
|
fail_if(len != 4, "len is %zu", len);
|
||||||
|
fail_if(ascii[0] != '1',"0 was %c",ascii[0]);
|
||||||
|
fail_if(ascii[1] != '2',"1 was %c",ascii[1]);
|
||||||
|
fail_if(ascii[2] != '3',"2 was %c",ascii[2]);
|
||||||
|
fail_if(ascii[3] != '4',"3 was %c",ascii[3]);
|
||||||
|
fail_if(ascii[4] != 0, "4 was %c",ascii[4]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_2hex_2)
|
||||||
|
|
||||||
|
unsigned char bcd[] = {0xF0, 0xFF, 0x00};
|
||||||
|
char ascii[sizeof bcd * 2 + 1];
|
||||||
|
size_t len = uc_bcd2ascii(bcd, sizeof bcd, ascii);
|
||||||
|
|
||||||
|
fail_if(len != 6, "len is %zu", len);
|
||||||
|
fail_if(ascii[0] != '0',"0 was %c",ascii[0]);
|
||||||
|
fail_if(ascii[1] != 'F',"1 was %c",ascii[1]);
|
||||||
|
fail_if(ascii[2] != 'F',"2 was %c",ascii[2]);
|
||||||
|
fail_if(ascii[3] != 'F',"3 was %c",ascii[3]);
|
||||||
|
fail_if(ascii[4] != '0', "4 was %c",ascii[4]);
|
||||||
|
fail_if(ascii[5] != '0', "5 was %c",ascii[5]);
|
||||||
|
fail_if(ascii[6] != 0, "6 was %c",ascii[6]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_2hex_empty)
|
||||||
|
|
||||||
|
unsigned char bcd[] = {0xF0, 0xFF, 0x00};
|
||||||
|
char ascii[sizeof bcd * 2 + 1];
|
||||||
|
ascii[0] = 0xFF;
|
||||||
|
size_t len = uc_bcd2ascii(bcd, 0, ascii);
|
||||||
|
|
||||||
|
fail_if(len != 0, "len is %zu", len);
|
||||||
|
fail_if(ascii[0] != 0, "0 was %c",ascii[0]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
Suite *bcd_suite(void)
|
||||||
|
{
|
||||||
|
Suite *s = suite_create("bcd");
|
||||||
|
TCase *tc = tcase_create("bcd tests");
|
||||||
|
tcase_add_test(tc, test_2bcd_1234567890);
|
||||||
|
tcase_add_test(tc, test_2bcd_empty);
|
||||||
|
tcase_add_test(tc, test_2bcd_1_filler);
|
||||||
|
tcase_add_test(tc, test_2bcd_2_filler);
|
||||||
|
tcase_add_test(tc, test_2bcd_3_filler);
|
||||||
|
tcase_add_test(tc, test_2bcd_non_digits);
|
||||||
|
tcase_add_test(tc, test_2bcd_phoneno);
|
||||||
|
tcase_add_test(tc, test_2bcd_binary);
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_2hex_1);
|
||||||
|
tcase_add_test(tc, test_2hex_2);
|
||||||
|
tcase_add_test(tc, test_2hex_empty);
|
||||||
|
|
||||||
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
#include <check.h>
|
||||||
|
#include "ucore_bitvec.h"
|
||||||
|
|
||||||
|
|
||||||
|
START_TEST (test_bitvec_1)
|
||||||
|
unsigned long s[3] = {0};
|
||||||
|
struct bitvec v = BITVEC_STATIC_INIT(s);
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for(i = 0; i < sizeof s * 8; i++)
|
||||||
|
fail_if(get_bit(&v, i), "bit %zu is not 0", i);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_bitvec_2)
|
||||||
|
unsigned long s[3] = {0};
|
||||||
|
struct bitvec v = BITVEC_STATIC_INIT(s);
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for(i = 0; i < sizeof s * 8; i++)
|
||||||
|
set_bit(&v, i);
|
||||||
|
|
||||||
|
for(i = 0; i < sizeof s * 8; i++)
|
||||||
|
fail_if(get_bit(&v, i) != 1 , "bit %zu is not 1", i);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_bitvec_clearbit)
|
||||||
|
unsigned long s[3] = {-1, -1, -1};
|
||||||
|
struct bitvec v = BITVEC_STATIC_INIT(s);
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for(i = 0; i < sizeof(unsigned long) * 8; i++)
|
||||||
|
fail_if(get_bit(&v, i) != 1 , "bit %zu is not 1", i);
|
||||||
|
|
||||||
|
for(i = 0; i < sizeof(unsigned long) * 8; i++)
|
||||||
|
clear_bit(&v, i);
|
||||||
|
|
||||||
|
for(i = 0; i < sizeof(unsigned long) * 8; i++)
|
||||||
|
fail_if(get_bit(&v, i) != 0 , "bit %zu is not 0", i);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_bitvec_set_bits_from_array)
|
||||||
|
struct bitvec *v = bitvec_new(5);
|
||||||
|
char a[] = {1, 0,1 ,0, 1};
|
||||||
|
|
||||||
|
set_bits_from_array(v,a , 5);
|
||||||
|
fail_if(get_bit(v, 0) != 1 , "bit 0 is wrong");
|
||||||
|
fail_if(get_bit(v, 1) != 0 , "bit 1 is wrong");
|
||||||
|
fail_if(get_bit(v, 2) != 1 , "bit 2 is wrong");
|
||||||
|
fail_if(get_bit(v, 3) != 0 , "bit 3 is wrong");
|
||||||
|
fail_if(get_bit(v, 4) != 1 , "bit 4 is wrong");
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
|
START_TEST (test_bitvec_setall_clearall)
|
||||||
|
struct bitvec *v = bitvec_new(511);
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
set_all(v);
|
||||||
|
|
||||||
|
for(i = 0; i < 511; i++)
|
||||||
|
fail_if(get_bit(v, i) != 1 , "bit %zu is not 1", i);
|
||||||
|
|
||||||
|
clear_all(v);
|
||||||
|
|
||||||
|
for(i = 0; i < sizeof(unsigned long) * 8; i++)
|
||||||
|
fail_if(get_bit(v, i) != 0 , "bit %zu is not 0", i);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
Suite *bitvec_suite(void)
|
||||||
|
{
|
||||||
|
Suite *s = suite_create("bitvec");
|
||||||
|
TCase *tc = tcase_create("bitvec tests");
|
||||||
|
tcase_add_test(tc, test_bitvec_1);
|
||||||
|
tcase_add_test(tc, test_bitvec_2);
|
||||||
|
tcase_add_test(tc, test_bitvec_set_bits_from_array);
|
||||||
|
tcase_add_test(tc, test_bitvec_clearbit);
|
||||||
|
tcase_add_test(tc, test_bitvec_setall_clearall);
|
||||||
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#include <check.h>
|
||||||
|
#include "ucore_utils.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct Inner {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Outer {
|
||||||
|
int tag1;
|
||||||
|
int tag2;
|
||||||
|
struct Inner inner;
|
||||||
|
int tag3;
|
||||||
|
};
|
||||||
|
|
||||||
|
START_TEST (test_container_of)
|
||||||
|
struct Outer outer = {
|
||||||
|
.tag1 = 1,
|
||||||
|
.tag2 = 2,
|
||||||
|
.inner = {
|
||||||
|
.x = 1234,
|
||||||
|
.y = 5678
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Inner *innerp = &outer.inner;
|
||||||
|
struct Outer *outerp = CONTAINER_OF(innerp, struct Outer, inner);
|
||||||
|
|
||||||
|
fail_if(outerp != &outer);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
Suite *container_of_suite(void)
|
||||||
|
{
|
||||||
|
Suite *s = suite_create("container_of");
|
||||||
|
TCase *tc = tcase_create("container_of tests");
|
||||||
|
tcase_add_test(tc, test_container_of);
|
||||||
|
|
||||||
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
+193
@@ -0,0 +1,193 @@
|
|||||||
|
#include <check.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "ucore_string.h"
|
||||||
|
|
||||||
|
|
||||||
|
START_TEST (test_uc_hex_encode_1)
|
||||||
|
uint8_t binary[] = {0xff};
|
||||||
|
char hex[3] = "";
|
||||||
|
|
||||||
|
uc_hex_encode(binary, 1, hex);
|
||||||
|
|
||||||
|
fail_if(strcmp(hex,"FF") != 0);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_uc_hex_encode_2)
|
||||||
|
uint8_t binary[] = {127, 128, 129};
|
||||||
|
char hex[4] = "";
|
||||||
|
|
||||||
|
uc_hex_encode(binary, sizeof binary, hex);
|
||||||
|
|
||||||
|
fail_if(strcmp(hex,"7F8081") != 0, "was %s", hex);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_uc_hex_encode_3)
|
||||||
|
uint8_t binary[] = {0, 1, 9, 11};
|
||||||
|
char hex[5] = "";
|
||||||
|
|
||||||
|
uc_hex_encode(binary, sizeof binary, hex);
|
||||||
|
|
||||||
|
fail_if(strcmp(hex,"0001090B") != 0, "was %s", hex);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_uc_hex_encode_zero_len)
|
||||||
|
uint8_t binary[1] = {0xff};
|
||||||
|
char hex[3] = "aa";
|
||||||
|
|
||||||
|
uc_hex_encode(binary, 0, hex);
|
||||||
|
|
||||||
|
fail_if(hex[0] != 0);
|
||||||
|
fail_if(hex[1] != 'a');
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_uc_hex_decode_1)
|
||||||
|
char hex[] = "1F";
|
||||||
|
uint8_t binary[2] = {0x11,0x22};
|
||||||
|
uint8_t *res;
|
||||||
|
|
||||||
|
res = uc_hex_decode(hex, 2, binary);
|
||||||
|
|
||||||
|
fail_if(binary[0] != 0x1f);
|
||||||
|
fail_if(binary[1] != 0x22);
|
||||||
|
fail_if(res != binary + 1, "binary %p, res %p", &binary[0], res);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_uc_hex_decode_2)
|
||||||
|
char hex[] = "00FF80";
|
||||||
|
uint8_t binary[4] = {0x11, 0x11, 0x11};
|
||||||
|
uint8_t *res;
|
||||||
|
|
||||||
|
res = uc_hex_decode(hex, 6, binary);
|
||||||
|
|
||||||
|
fail_if(binary[0] != 0x00);
|
||||||
|
fail_if(binary[1] != 0xFF);
|
||||||
|
fail_if(binary[2] != 0x80);
|
||||||
|
fail_if(res != binary + 3, "binary %p, res %p", &binary[0], res);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_uc_hex_decode_zero_length)
|
||||||
|
char hex[] = "00FF80";
|
||||||
|
uint8_t binary[4] = {0x11, 0x11, 0x11};
|
||||||
|
uint8_t *res;
|
||||||
|
|
||||||
|
res = uc_hex_decode(hex, 0, binary);
|
||||||
|
|
||||||
|
fail_if(binary[0] != 0x11);
|
||||||
|
fail_if(binary[1] != 0x11);
|
||||||
|
fail_if(binary[2] != 0x11);
|
||||||
|
fail_if(res != binary);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_uc_hex_decode_empty_string)
|
||||||
|
char hex[] = "";
|
||||||
|
uint8_t binary[4] = {0x11, 0x11, 0x11};
|
||||||
|
uint8_t *res;
|
||||||
|
|
||||||
|
res = uc_hex_decode(hex, 2, binary);
|
||||||
|
|
||||||
|
fail_if(binary[0] != 0x11);
|
||||||
|
fail_if(binary[1] != 0x11);
|
||||||
|
fail_if(binary[2] != 0x11);
|
||||||
|
fail_if(res != binary);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_uc_hex_decode_odd_length)
|
||||||
|
char hex[] = "33FF80";
|
||||||
|
uint8_t binary[4] = {0x11, 0x11, 0x11};
|
||||||
|
uint8_t *res;
|
||||||
|
|
||||||
|
res = uc_hex_decode(hex, 3, binary);
|
||||||
|
|
||||||
|
fail_if(binary[0] != 0x33);
|
||||||
|
fail_if(binary[1] != 0x11);
|
||||||
|
fail_if(binary[2] != 0x11);
|
||||||
|
fail_if(res != &binary[1]);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_uc_hex_decode_invalid)
|
||||||
|
char hex[] = "TEST ";
|
||||||
|
uint8_t binary[4] = {0x11, 0x11, 0x11};
|
||||||
|
uint8_t *res;
|
||||||
|
|
||||||
|
res = uc_hex_decode(hex, 3, binary);
|
||||||
|
|
||||||
|
fail_if(binary[0] != 0x11);
|
||||||
|
fail_if(binary[1] != 0x11);
|
||||||
|
fail_if(binary[2] != 0x11);
|
||||||
|
fail_if(res != NULL);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_uc_hex_encode_delim_1)
|
||||||
|
uint8_t binary[4] = {0xFF, 0x00, 0x7F, 0x0A};
|
||||||
|
char hex[17] = "";
|
||||||
|
char *res;
|
||||||
|
|
||||||
|
res = uc_hex_encode_delim(binary, sizeof binary, hex, sizeof hex, " ");
|
||||||
|
|
||||||
|
fail_if(strcmp(hex, "FF 00 7F 0A ") != 0, "hex was '%s'", hex);
|
||||||
|
fail_if(res != hex + 12);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_uc_hex_encode_delim_2)
|
||||||
|
uint8_t binary[] = {0xFF, 0x00};
|
||||||
|
char hex[8] = "";
|
||||||
|
char *res;
|
||||||
|
|
||||||
|
res = uc_hex_encode_delim(binary, sizeof binary, hex, sizeof hex, " \n");
|
||||||
|
|
||||||
|
fail_if(strcmp(hex, "FF \n00 ") != 0, "hex was '%s'", hex);
|
||||||
|
fail_if(res != hex + 8);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_uc_hex_encode_delim_zero_len)
|
||||||
|
uint8_t binary[] = {0xFF, 0x00};
|
||||||
|
char hex[8] = "......";
|
||||||
|
char *res;
|
||||||
|
|
||||||
|
res = uc_hex_encode_delim(binary, 0, hex, sizeof hex, " \n");
|
||||||
|
|
||||||
|
fail_if(strcmp(hex, "") != 0, "hex was '%s'", hex);
|
||||||
|
fail_if(res != hex);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
|
Suite *hex_suite(void)
|
||||||
|
{
|
||||||
|
Suite *s = suite_create("hex");
|
||||||
|
TCase *tc = tcase_create("hex tests");
|
||||||
|
tcase_add_test(tc, test_uc_hex_encode_1);
|
||||||
|
tcase_add_test(tc, test_uc_hex_encode_2);
|
||||||
|
tcase_add_test(tc, test_uc_hex_encode_3);
|
||||||
|
tcase_add_test(tc, test_uc_hex_encode_zero_len);
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_uc_hex_encode_delim_1);
|
||||||
|
tcase_add_test(tc, test_uc_hex_encode_delim_2);
|
||||||
|
tcase_add_test(tc, test_uc_hex_encode_delim_zero_len);
|
||||||
|
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_uc_hex_decode_1);
|
||||||
|
tcase_add_test(tc, test_uc_hex_decode_2);
|
||||||
|
tcase_add_test(tc, test_uc_hex_decode_zero_length);
|
||||||
|
tcase_add_test(tc, test_uc_hex_decode_odd_length);
|
||||||
|
tcase_add_test(tc, test_uc_hex_decode_invalid);
|
||||||
|
tcase_add_test(tc, test_uc_hex_decode_empty_string);
|
||||||
|
|
||||||
|
|
||||||
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,403 @@
|
|||||||
|
#include <check.h>
|
||||||
|
#include "ucore_pack.h"
|
||||||
|
|
||||||
|
|
||||||
|
START_TEST (test_pack16_le_1)
|
||||||
|
uint16_t v = 0x1234;
|
||||||
|
uint8_t r[2];
|
||||||
|
|
||||||
|
uc_pack_16_le(v,r);
|
||||||
|
|
||||||
|
fail_if(r[0] != 0x34,"was 0x%x",r[0]);
|
||||||
|
fail_if(r[1] != 0x12,"was 0x%x",r[1]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_pack16_le_2)
|
||||||
|
uint16_t v = 0xFEEF;
|
||||||
|
uint8_t r[2];
|
||||||
|
|
||||||
|
uc_pack_16_le(v,r);
|
||||||
|
|
||||||
|
fail_if(r[0] != 0xEF,"was 0x%x",r[0]);
|
||||||
|
fail_if(r[1] != 0xFE,"was 0x%x",r[1]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_pack16_be_1)
|
||||||
|
uint16_t v = 0x1234;
|
||||||
|
uint8_t r[2];
|
||||||
|
|
||||||
|
uc_pack_16_be(v,r);
|
||||||
|
|
||||||
|
fail_if(r[0] != 0x12,"was 0x%x",r[0]);
|
||||||
|
fail_if(r[1] != 0x34,"was 0x%x",r[1]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_pack16_be_2)
|
||||||
|
uint16_t v = 0xFEEF;
|
||||||
|
uint8_t r[2];
|
||||||
|
|
||||||
|
uc_pack_16_be(v, r);
|
||||||
|
|
||||||
|
fail_if(r[0] != 0xFE,"was 0x%x",r[0]);
|
||||||
|
fail_if(r[1] != 0xEF,"was 0x%x",r[1]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_unpack16_le_1)
|
||||||
|
uint16_t v;
|
||||||
|
uint8_t r[2] = {0x12, 0x34};
|
||||||
|
|
||||||
|
v = uc_unpack_16_le(r);
|
||||||
|
|
||||||
|
fail_if(v != 0x3412,"was 0x%x",v);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_unpack16_le_2)
|
||||||
|
uint16_t v;
|
||||||
|
uint8_t r[2] = {0xFE, 0xEF};
|
||||||
|
|
||||||
|
v = uc_unpack_16_le(r);
|
||||||
|
|
||||||
|
fail_if(v != 0xEFFE,"was 0x%x",v);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_unpack16_be_1)
|
||||||
|
uint16_t v;
|
||||||
|
uint8_t r[2] = {0x12, 0x34};
|
||||||
|
|
||||||
|
v = uc_unpack_16_be(r);
|
||||||
|
|
||||||
|
fail_if(v != 0x1234,"was 0x%x",v);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_unpack16_be_2)
|
||||||
|
uint16_t v;
|
||||||
|
uint8_t r[2] = {0xFE, 0xEF};
|
||||||
|
|
||||||
|
v = uc_unpack_16_be(r);
|
||||||
|
|
||||||
|
fail_if(v != 0xFEEF,"was 0x%x",v);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_pack24_le_1)
|
||||||
|
uint32_t v = 0x123456;
|
||||||
|
uint8_t r[3];
|
||||||
|
|
||||||
|
uc_pack_24_le(v,r);
|
||||||
|
|
||||||
|
fail_if(r[0] != 0x56,"was 0x%x",r[0]);
|
||||||
|
fail_if(r[1] != 0x34,"was 0x%x",r[1]);
|
||||||
|
fail_if(r[2] != 0x12,"was 0x%x",r[2]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_pack24_le_2)
|
||||||
|
uint32_t v = 0xF8F7F6;
|
||||||
|
uint8_t r[3];
|
||||||
|
|
||||||
|
uc_pack_24_le(v,r);
|
||||||
|
|
||||||
|
fail_if(r[0] != 0xF6,"was 0x%x",r[0]);
|
||||||
|
fail_if(r[1] != 0xF7,"was 0x%x",r[1]);
|
||||||
|
fail_if(r[2] != 0xF8,"was 0x%x",r[2]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_pack24_be_1)
|
||||||
|
uint32_t v = 0x123456;
|
||||||
|
uint8_t r[3];
|
||||||
|
|
||||||
|
uc_pack_24_be(v,r);
|
||||||
|
|
||||||
|
fail_if(r[0] != 0x12,"was 0x%x",r[0]);
|
||||||
|
fail_if(r[1] != 0x34,"was 0x%x",r[1]);
|
||||||
|
fail_if(r[2] != 0x56,"was 0x%x",r[2]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_pack24_be_2)
|
||||||
|
uint32_t v = 0xF8F7F6;
|
||||||
|
uint8_t r[3];
|
||||||
|
|
||||||
|
uc_pack_24_be(v,r);
|
||||||
|
|
||||||
|
fail_if(r[0] != 0xF8,"was 0x%x",r[0]);
|
||||||
|
fail_if(r[1] != 0xF7,"was 0x%x",r[1]);
|
||||||
|
fail_if(r[2] != 0xF6,"was 0x%x",r[2]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_pack32_le_1)
|
||||||
|
uint32_t v = 0x12345678;
|
||||||
|
uint8_t r[4];
|
||||||
|
|
||||||
|
uc_pack_32_le(v,r);
|
||||||
|
|
||||||
|
fail_if(r[0] != 0x78,"was 0x%x",r[0]);
|
||||||
|
fail_if(r[1] != 0x56,"was 0x%x",r[1]);
|
||||||
|
fail_if(r[2] != 0x34,"was 0x%x",r[2]);
|
||||||
|
fail_if(r[3] != 0x12,"was 0x%x",r[3]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_pack32_le_2)
|
||||||
|
uint32_t v = 0xF8F7F6F4;
|
||||||
|
uint8_t r[4];
|
||||||
|
|
||||||
|
uc_pack_32_le(v,r);
|
||||||
|
|
||||||
|
fail_if(r[0] != 0xF4,"was 0x%x",r[0]);
|
||||||
|
fail_if(r[1] != 0xF6,"was 0x%x",r[1]);
|
||||||
|
fail_if(r[2] != 0xF7,"was 0x%x",r[2]);
|
||||||
|
fail_if(r[3] != 0xF8,"was 0x%x",r[3]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_pack32_be_1)
|
||||||
|
uint32_t v = 0x12345678;
|
||||||
|
uint8_t r[4];
|
||||||
|
|
||||||
|
uc_pack_32_be(v,r);
|
||||||
|
|
||||||
|
fail_if(r[3] != 0x78,"was 0x%x",r[3]);
|
||||||
|
fail_if(r[2] != 0x56,"was 0x%x",r[2]);
|
||||||
|
fail_if(r[1] != 0x34,"was 0x%x",r[1]);
|
||||||
|
fail_if(r[0] != 0x12,"was 0x%x",r[0]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_pack32_be_2)
|
||||||
|
uint32_t v = 0xF8F7F6F4;
|
||||||
|
uint8_t r[4];
|
||||||
|
|
||||||
|
uc_pack_32_be(v,r);
|
||||||
|
|
||||||
|
fail_if(r[3] != 0xF4,"was 0x%x",r[3]);
|
||||||
|
fail_if(r[2] != 0xF6,"was 0x%x",r[2]);
|
||||||
|
fail_if(r[1] != 0xF7,"was 0x%x",r[1]);
|
||||||
|
fail_if(r[0] != 0xF8,"was 0x%x",r[0]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_unpack24_le_1)
|
||||||
|
uint32_t v;
|
||||||
|
uint8_t r[3] = {0x12, 0x34, 0x56 };
|
||||||
|
|
||||||
|
v = uc_unpack_24_le(r);
|
||||||
|
|
||||||
|
fail_if(v != 0x563412,"was 0x%x",v);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_unpack24_le_2)
|
||||||
|
uint32_t v;
|
||||||
|
uint8_t r[4] = {0xF8, 0xF7, 0xF6};
|
||||||
|
|
||||||
|
v = uc_unpack_24_le(r);
|
||||||
|
|
||||||
|
fail_if(v != 0xF6F7F8,"was 0x%x",v);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_unpack24_be_1)
|
||||||
|
uint32_t v;
|
||||||
|
uint8_t r[3] = {0x12, 0x34, 0x56 };
|
||||||
|
|
||||||
|
v = uc_unpack_24_be(r);
|
||||||
|
|
||||||
|
fail_if(v != 0x123456,"was 0x%x",v);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_unpack24_be_2)
|
||||||
|
uint32_t v;
|
||||||
|
uint8_t r[4] = {0xF8, 0xF7, 0xF6};
|
||||||
|
|
||||||
|
v = uc_unpack_24_be(r);
|
||||||
|
|
||||||
|
fail_if(v != 0xF8F7F6,"was 0x%x",v);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_unpack32_le_1)
|
||||||
|
uint32_t v;
|
||||||
|
uint8_t r[4] = {0x12, 0x34, 0x56, 0x78};
|
||||||
|
|
||||||
|
v = uc_unpack_32_le(r);
|
||||||
|
|
||||||
|
fail_if(v != 0x78563412,"was 0x%x",v);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_unpack32_le_2)
|
||||||
|
uint32_t v;
|
||||||
|
uint8_t r[4] = {0xF8, 0xF7, 0xF6, 0xF4 };
|
||||||
|
|
||||||
|
v = uc_unpack_32_le(r);
|
||||||
|
|
||||||
|
fail_if(v != 0xF4F6F7F8,"was 0x%x",v);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_unpack32_be_1)
|
||||||
|
uint32_t v;
|
||||||
|
uint8_t r[4] = {0x12, 0x34, 0x56, 0x78};
|
||||||
|
|
||||||
|
v = uc_unpack_32_be(r);
|
||||||
|
|
||||||
|
fail_if(v != 0x12345678,"was 0x%x",v);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_unpack32_be_2)
|
||||||
|
uint32_t v;
|
||||||
|
uint8_t r[4] = {0xF8, 0xF7, 0xF6, 0xF4 };
|
||||||
|
|
||||||
|
v = uc_unpack_32_be(r);
|
||||||
|
|
||||||
|
fail_if(v != 0xF8F7F6F4,"was 0x%x",v);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_pack64_le_1)
|
||||||
|
uint64_t v = 0x1122334455667788ULL;
|
||||||
|
uint8_t r[8] = {};
|
||||||
|
|
||||||
|
uc_pack_64_le(v, r);
|
||||||
|
|
||||||
|
fail_if(r[0] != 0x88,"was 0x%x",r[0]);
|
||||||
|
fail_if(r[1] != 0x77,"was 0x%x",r[1]);
|
||||||
|
fail_if(r[2] != 0x66,"was 0x%x",r[2]);
|
||||||
|
fail_if(r[3] != 0x55,"was 0x%x",r[3]);
|
||||||
|
fail_if(r[4] != 0x44,"was 0x%x",r[4]);
|
||||||
|
fail_if(r[5] != 0x33,"was 0x%x",r[5]);
|
||||||
|
fail_if(r[6] != 0x22,"was 0x%x",r[6]);
|
||||||
|
fail_if(r[7] != 0x11,"was 0x%x",r[7]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_pack64_le_2)
|
||||||
|
uint64_t v = 0xFFFEFDFCFBFAF9F8ULL;
|
||||||
|
uint8_t r[8] = {};
|
||||||
|
|
||||||
|
uc_pack_64_le(v, r);
|
||||||
|
|
||||||
|
fail_if(r[0] != 0xF8,"was 0x%x",r[0]);
|
||||||
|
fail_if(r[1] != 0xF9,"was 0x%x",r[1]);
|
||||||
|
fail_if(r[2] != 0xFA,"was 0x%x",r[2]);
|
||||||
|
fail_if(r[3] != 0xFB,"was 0x%x",r[3]);
|
||||||
|
fail_if(r[4] != 0xFC,"was 0x%x",r[4]);
|
||||||
|
fail_if(r[5] != 0xFD,"was 0x%x",r[5]);
|
||||||
|
fail_if(r[6] != 0xFE,"was 0x%x",r[6]);
|
||||||
|
fail_if(r[7] != 0xFF,"was 0x%x",r[7]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_unpack64_le_1)
|
||||||
|
uint64_t v;
|
||||||
|
uint8_t r[8] = {0x11 ,0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
|
||||||
|
|
||||||
|
v = uc_unpack_64_le(r);
|
||||||
|
|
||||||
|
fail_if(v != 0x8877665544332211ULL,"was 0x%llx",v);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
|
START_TEST (test_unpack64_le_2)
|
||||||
|
uint64_t v;
|
||||||
|
uint8_t r[8] = {0xFF ,0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8};
|
||||||
|
|
||||||
|
v = uc_unpack_64_le(r);
|
||||||
|
|
||||||
|
fail_if(v != 0xF8F9FAFBFCFDFEFFULL,"was 0x%llx",v);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_pack64_be_1)
|
||||||
|
uint64_t v = 0x1122334455667788ULL;
|
||||||
|
uint8_t r[8] = {};
|
||||||
|
|
||||||
|
uc_pack_64_be(v, r);
|
||||||
|
|
||||||
|
fail_if(r[0] != 0x11,"was 0x%x",r[0]);
|
||||||
|
fail_if(r[1] != 0x22,"was 0x%x",r[1]);
|
||||||
|
fail_if(r[2] != 0x33,"was 0x%x",r[2]);
|
||||||
|
fail_if(r[3] != 0x44,"was 0x%x",r[3]);
|
||||||
|
fail_if(r[4] != 0x55,"was 0x%x",r[4]);
|
||||||
|
fail_if(r[5] != 0x66,"was 0x%x",r[5]);
|
||||||
|
fail_if(r[6] != 0x77,"was 0x%x",r[6]);
|
||||||
|
fail_if(r[7] != 0x88,"was 0x%x",r[7]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_pack64_be_2)
|
||||||
|
uint64_t v = 0xFFFEFDFCFBFAF9F8ULL;
|
||||||
|
uint8_t r[8] = {};
|
||||||
|
|
||||||
|
uc_pack_64_be(v, r);
|
||||||
|
|
||||||
|
fail_if(r[0] != 0xFF,"was 0x%x",r[0]);
|
||||||
|
fail_if(r[1] != 0xFE,"was 0x%x",r[1]);
|
||||||
|
fail_if(r[2] != 0xFD,"was 0x%x",r[2]);
|
||||||
|
fail_if(r[3] != 0xFC,"was 0x%x",r[3]);
|
||||||
|
fail_if(r[4] != 0xFB,"was 0x%x",r[4]);
|
||||||
|
fail_if(r[5] != 0xFA,"was 0x%x",r[5]);
|
||||||
|
fail_if(r[6] != 0xF9,"was 0x%x",r[6]);
|
||||||
|
fail_if(r[7] != 0xF8,"was 0x%x",r[7]);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_unpack64_be_1)
|
||||||
|
uint64_t v;
|
||||||
|
uint8_t r[8] = {0x11 ,0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
|
||||||
|
|
||||||
|
v = uc_unpack_64_be(r);
|
||||||
|
|
||||||
|
fail_if(v != 0x1122334455667788ULL,"was 0x%llx",v);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_unpack64_be_2)
|
||||||
|
uint64_t v;
|
||||||
|
uint8_t r[8] = {0xFF ,0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8};
|
||||||
|
|
||||||
|
v = uc_unpack_64_be(r);
|
||||||
|
|
||||||
|
fail_if(v != 0xFFFEFDFCFBFAF9F8ULL,"was 0x%llx",v);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
Suite *pack_suite(void)
|
||||||
|
{
|
||||||
|
Suite *s = suite_create("pack");
|
||||||
|
TCase *tc = tcase_create("pack tests");
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_pack16_le_1);
|
||||||
|
tcase_add_test(tc, test_pack16_le_2);
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_pack16_be_1);
|
||||||
|
tcase_add_test(tc, test_pack16_be_2);
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_unpack16_le_1);
|
||||||
|
tcase_add_test(tc, test_unpack16_le_2);
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_unpack16_be_1);
|
||||||
|
tcase_add_test(tc, test_unpack16_be_2);
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_pack24_le_1);
|
||||||
|
tcase_add_test(tc, test_pack24_le_2);
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_pack24_be_1);
|
||||||
|
tcase_add_test(tc, test_pack24_be_2);
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_unpack24_le_1);
|
||||||
|
tcase_add_test(tc, test_unpack24_le_2);
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_unpack24_be_1);
|
||||||
|
tcase_add_test(tc, test_unpack24_be_2);
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_pack32_le_1);
|
||||||
|
tcase_add_test(tc, test_pack32_le_2);
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_pack32_be_1);
|
||||||
|
tcase_add_test(tc, test_pack32_be_2);
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_unpack32_le_1);
|
||||||
|
tcase_add_test(tc, test_unpack32_le_2);
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_unpack32_be_1);
|
||||||
|
tcase_add_test(tc, test_unpack32_be_2);
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_pack64_le_1);
|
||||||
|
tcase_add_test(tc, test_pack64_le_2);
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_unpack64_le_1);
|
||||||
|
tcase_add_test(tc, test_unpack64_le_2);
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_pack64_be_1);
|
||||||
|
tcase_add_test(tc, test_pack64_be_2);
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_unpack64_be_1);
|
||||||
|
tcase_add_test(tc, test_unpack64_be_2);
|
||||||
|
|
||||||
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
#include <check.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include "ucore_read_file.h"
|
||||||
|
|
||||||
|
|
||||||
|
START_TEST (test_read_file_non_existing_file)
|
||||||
|
char *content;
|
||||||
|
size_t len;
|
||||||
|
int saved_errno;
|
||||||
|
|
||||||
|
content = uc_read_file("non existing file 123765", &len, 1000000000);
|
||||||
|
saved_errno = errno;
|
||||||
|
|
||||||
|
fail_if(content != NULL);
|
||||||
|
fail_if(saved_errno == 0);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_read_file_simple)
|
||||||
|
char *content;
|
||||||
|
const char *filename = "test_read_file_simple";
|
||||||
|
size_t len;
|
||||||
|
ssize_t rc;
|
||||||
|
|
||||||
|
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664);
|
||||||
|
fail_if(fd == -1);
|
||||||
|
|
||||||
|
rc = write(fd, "hello", 5);
|
||||||
|
fail_if(rc != 5, "rc was %ld", (long)rc);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
content = uc_read_file(filename, &len, 1000000000);
|
||||||
|
unlink(filename);
|
||||||
|
|
||||||
|
fail_if(content == NULL);
|
||||||
|
fail_if(len != 5);
|
||||||
|
fail_if(strlen(content) != 5);
|
||||||
|
fail_if(strcmp("hello", content) != 0);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_read_file_greater_than_max)
|
||||||
|
char *content;
|
||||||
|
const char *filename = "test_read_file_simple";
|
||||||
|
size_t len;
|
||||||
|
ssize_t rc;
|
||||||
|
int saved_errno;
|
||||||
|
|
||||||
|
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664);
|
||||||
|
fail_if(fd == -1);
|
||||||
|
|
||||||
|
rc = write(fd, "hello", 5);
|
||||||
|
fail_if(rc != 5, "rc was %ld", (long)rc);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
content = uc_read_file(filename, &len, 4);
|
||||||
|
saved_errno = errno;
|
||||||
|
unlink(filename);
|
||||||
|
|
||||||
|
fail_if(content != NULL);
|
||||||
|
fail_if(saved_errno != EMSGSIZE, "was %d", saved_errno);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_read_file_boundary)
|
||||||
|
char *content;
|
||||||
|
const char *filename = "test_read_file_boundary";
|
||||||
|
size_t len;
|
||||||
|
ssize_t rc;
|
||||||
|
char buf[1030] = "";
|
||||||
|
strcpy(&buf[1022], "foobar");
|
||||||
|
|
||||||
|
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664);
|
||||||
|
fail_if(fd == -1);
|
||||||
|
|
||||||
|
rc = write(fd, buf, sizeof buf);
|
||||||
|
fail_if(rc != sizeof buf, "rc was %ld", (long)rc);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
content = uc_read_file(filename, &len, 1000000000);
|
||||||
|
unlink(filename);
|
||||||
|
|
||||||
|
fail_if(content == NULL);
|
||||||
|
fail_if(len != sizeof buf);
|
||||||
|
fail_if(strcmp("foobar", &content[1022]) != 0);
|
||||||
|
free(content);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
Suite *read_file_suite(void)
|
||||||
|
{
|
||||||
|
Suite *s = suite_create("read_file");
|
||||||
|
TCase *tc = tcase_create("read_file tests");
|
||||||
|
tcase_add_test(tc, test_read_file_non_existing_file);
|
||||||
|
tcase_add_test(tc, test_read_file_simple);
|
||||||
|
tcase_add_test(tc, test_read_file_greater_than_max);
|
||||||
|
tcase_add_test(tc, test_read_file_boundary);
|
||||||
|
|
||||||
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <check.h>
|
||||||
|
|
||||||
|
extern Suite *bitvec_suite(void);
|
||||||
|
extern Suite *bcd_suite(void);
|
||||||
|
extern Suite *hex_suite(void);
|
||||||
|
extern Suite *container_of_suite(void);
|
||||||
|
extern Suite *read_file_suite(void);
|
||||||
|
extern Suite *pack_suite(void);
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int xml_output = argc > 1 && strcmp(argv[1], "--xml") == 0;
|
||||||
|
|
||||||
|
int number_failed = 0;
|
||||||
|
|
||||||
|
SRunner *sr = srunner_create (NULL);
|
||||||
|
if(xml_output)
|
||||||
|
srunner_set_xml(sr, "result.xml");
|
||||||
|
|
||||||
|
srunner_add_suite(sr, bitvec_suite());
|
||||||
|
srunner_add_suite(sr, bcd_suite());
|
||||||
|
srunner_add_suite(sr, hex_suite());
|
||||||
|
srunner_add_suite(sr, container_of_suite());
|
||||||
|
srunner_add_suite(sr, read_file_suite());
|
||||||
|
srunner_add_suite(sr, pack_suite());
|
||||||
|
|
||||||
|
|
||||||
|
srunner_run_all (sr, CK_VERBOSE);
|
||||||
|
number_failed = srunner_ntests_failed (sr);
|
||||||
|
srunner_free (sr);
|
||||||
|
|
||||||
|
if(number_failed)
|
||||||
|
printf("ERROR: %d tests failed\n", number_failed);
|
||||||
|
|
||||||
|
return (number_failed != 0) ;
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "tree.h"
|
||||||
|
|
||||||
|
struct descriptor {
|
||||||
|
int fd;
|
||||||
|
SPLAY_ENTRY(descriptor) entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
int descriptor_cmp(struct descriptor *a, struct descriptor *b);
|
||||||
|
|
||||||
|
SPLAY_HEAD(descriptors, descriptor);
|
||||||
|
SPLAY_PROTOTYPE(descriptors, descriptor, entry, descriptor_cmp);
|
||||||
|
SPLAY_GENERATE(descriptors, descriptor, entry, descriptor_cmp);
|
||||||
|
|
||||||
|
struct descriptors entries;
|
||||||
|
|
||||||
|
int descriptor_cmp(struct descriptor *a, struct descriptor *b)
|
||||||
|
{
|
||||||
|
if(a->fd < b->fd)
|
||||||
|
return -1;
|
||||||
|
if(a->fd > b->fd)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(int fd)
|
||||||
|
{
|
||||||
|
struct descriptor *des = malloc(sizeof *des);
|
||||||
|
des->fd = fd;
|
||||||
|
SPLAY_INSERT(descriptors, &entries, des);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void find(int fd)
|
||||||
|
{
|
||||||
|
struct descriptor des;
|
||||||
|
struct descriptor *found;
|
||||||
|
|
||||||
|
des.fd = fd;
|
||||||
|
found = SPLAY_FIND(descriptors, &entries, &des);
|
||||||
|
|
||||||
|
if(found == NULL)
|
||||||
|
printf("Not found fd %d\n", fd);
|
||||||
|
else
|
||||||
|
printf("Found fd %d (%d)\n", found->fd, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rem(int fd)
|
||||||
|
{
|
||||||
|
struct descriptor des;
|
||||||
|
|
||||||
|
des.fd = fd;
|
||||||
|
SPLAY_REMOVE(descriptors, &entries, &des);
|
||||||
|
}
|
||||||
|
|
||||||
|
void iter(void){
|
||||||
|
struct descriptor *bd;
|
||||||
|
SPLAY_FOREACH(bd, descriptors, &entries) {
|
||||||
|
printf("foreach fd %d\n", bd->fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rem_iter(void){
|
||||||
|
struct descriptor *bd;
|
||||||
|
|
||||||
|
while (!SPLAY_EMPTY(&entries)) {
|
||||||
|
bd = SPLAY_ROOT(&entries);
|
||||||
|
SPLAY_REMOVE(descriptors, &entries, bd);
|
||||||
|
printf("removed fd %d\n", bd->fd);
|
||||||
|
free(bd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fd_min_max(void)
|
||||||
|
{
|
||||||
|
struct descriptor *min_des, *max_des;
|
||||||
|
|
||||||
|
min_des = SPLAY_MIN(descriptors, &entries);
|
||||||
|
max_des = SPLAY_MAX(descriptors, &entries);
|
||||||
|
|
||||||
|
if(min_des && max_des)
|
||||||
|
printf("min fd = %d max fd = %d\n", min_des->fd, max_des->fd);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
SPLAY_INIT(&entries);
|
||||||
|
add(3);
|
||||||
|
add(4);
|
||||||
|
add(5);
|
||||||
|
add(11);
|
||||||
|
add(64);
|
||||||
|
add(9);
|
||||||
|
add(12);
|
||||||
|
|
||||||
|
find(11);
|
||||||
|
find(13);
|
||||||
|
|
||||||
|
rem(11);
|
||||||
|
find(11);
|
||||||
|
fd_min_max();
|
||||||
|
iter();
|
||||||
|
rem_iter();
|
||||||
|
fd_min_max();
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "ucore_math.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
unsigned int a,N;
|
||||||
|
if(argc < 2) {
|
||||||
|
printf("Usage %s interger1\n",argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
a = atoi(argv[1]);
|
||||||
|
N = uc_phi_32(a);
|
||||||
|
printf("phi of %u is %u\n",a,N);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user