mailing list of musl libc
 help / color / mirror / code / Atom feed
From: Szabolcs Nagy <nsz@port70.net>
To: musl@lists.openwall.com
Subject: Re: Completeness status of musl
Date: Sat, 25 Jun 2011 20:31:06 +0200	[thread overview]
Message-ID: <20110625183106.GV27421@port70.net> (raw)
In-Reply-To: <20110608235810.GJ191@brightrain.aerifal.cx>

[-- Attachment #1: Type: text/plain, Size: 1771 bytes --]

* Rich Felker <dalias@aerifal.cx> [2011-06-08 19:58:10 -0400]:
> Moderate-effort new code:
> - XSI search.h functionality

i did this as it seems fairly simple/harmless
unfortunately this api is quite useless in practice
but i tried to write a simple and conformant implementation

hsearch:
    i used open addressing hashtable (with doubling)
    (it is probably a bit bigger than a chained hash)

    i used a simple hash function (its output must be
    size_t so clever 32bit hash functions are not ok)

    standard is not clear if item.key==NULL is allowed
    to be put into the table (i assumed NULL is not allowed
    as it says strcmp is used on the key, so i mark empty
    entries with NULL key)

    standard is not clear if after an out of memory event
    should there be a usable state, so i made it to work
    (if an insert fails the table can still be searched)

    this api does not provide iterator, number of items
    cannot queried and only string keys with strcmp can
    be used

insque,remque:
    doubly linked list management without type safety..

lsearch,lfind:
    complicated api that can be replaced by a for loop

tsearch:
    i provided two different implementations: plain binary
    tree (as used in bsd) and a self balancing avl tree
    (glibc seems to use rb-tree)

    the first one is simple, but walking the tree may use
    large amount of memory (stack memory, as i used
    recursion there)

    the avl tree implementation uses recursive functions
    (max depth of an avl tree with 2^42 nodes is 60)

    implementing (and using) this api is a bit painful
    the functions return node pointers that the user
    cannot really use..

attached code is also available here temporarily:
http://port70.net/~nsz/musl/search/


[-- Attachment #2: search.h --]
[-- Type: text/x-chdr, Size: 1039 bytes --]

#ifndef	_SEARCH_H
#define	_SEARCH_H

// TODO: cplusplus, xopensource,..

#define __NEED_size_t
#include <bits/alltypes.h>

typedef enum { FIND, ENTER } ACTION;
typedef enum { preorder, postorder, endorder, leaf } VISIT;

typedef struct {
	char *key;
	void *data;
} ENTRY;

int hcreate(size_t nel);
void hdestroy(void);
ENTRY *hsearch(ENTRY item, ACTION action);

void insque(void *element, void *pred);
void remque(void *element);

void *lsearch(const void *key, void *base, size_t *nelp, size_t width,
	int (*compar)(const void *, const void *));
void *lfind(const void *key, const void *base, size_t *nelp,
	size_t width, int (*compar)(const void *, const void *));

void *tdelete(const void *restrict key, void **restrict rootp,
	int(*compar)(const void *, const void *));
void *tfind(const void *key, void *const *rootp,
	int(*compar)(const void *, const void *));
void *tsearch(const void *key, void **rootp,
	int (*compar)(const void *, const void *));
void twalk(const void *root, void (*action)(const void *, VISIT, int));

#endif

[-- Attachment #3: hsearch.c --]
[-- Type: text/x-csrc, Size: 1995 bytes --]

#include <stdlib.h>
#include <string.h>
#include <search.h>

/*
open addressing hash table with 2^n table size
quadratic probing is used in case of hash collision
tab indices and hash are size_t
after resize fails with ENOMEM the state of tab is still usable

with the posix api items cannot be iterated and length cannot be queried
*/

#define MINSIZE 8
#define MAXSIZE ((size_t)-1/2 + 1)

struct entry {
	ENTRY item;
	size_t hash;
};

static size_t mask;
static size_t used;
static struct entry *tab;

static size_t keyhash(char *k)
{
	unsigned char *p = (void *)k;
	size_t h = 0;

	while (*p)
		h = 31*h + *p++;
	return h;
}

static int resize(size_t nel)
{
	size_t newsize;
	size_t i, j;
	struct entry *e, *newe;
	struct entry *oldtab = tab;
	struct entry *oldend = tab + mask + 1;

	if (nel > MAXSIZE)
		nel = MAXSIZE;
	for (newsize = MINSIZE; newsize < nel; newsize *= 2);
	tab = calloc(newsize, sizeof *tab);
	if (!tab) {
		tab = oldtab;
		return 0;
	}
	mask = newsize - 1;
	if (!oldtab)
		return 1;
	for (e = oldtab; e < oldend; e++)
		if (e->item.key) {
			for (i=e->hash,j=1; ; i+=j++) {
				newe = tab + (i & mask);
				if (!newe->item.key)
					break;
			}
			*newe = *e;
		}
	free(oldtab);
	return 1;
}

int hcreate(size_t nel)
{
	mask = 0;
	used = 0;
	tab = 0;
	return resize(nel);
}

void hdestroy(void)
{
	free(tab);
	tab = 0;
	mask = 0;
	used = 0;
}

static struct entry *lookup(char *key, size_t hash)
{
	size_t i, j;
	struct entry *e;

	for (i=hash,j=1; ; i+=j++) {
		e = tab + (i & mask);
		if (!e->item.key ||
		    (e->hash==hash && strcmp(e->item.key, key)==0))
			break;
	}
	return e;
}

ENTRY *hsearch(ENTRY item, ACTION action)
{
	size_t hash = keyhash(item.key);
	struct entry *e = lookup(item.key, hash);

	if (e->item.key)
		return &e->item;
	if (action == FIND)
		return 0;
	e->item = item;
	e->hash = hash;
	if (++used > mask - mask/4) {
		if (!resize(2*used)) {
			used--;
			e->item.key = 0;
			return 0;
		}
		e = lookup(item.key, hash);
	}
	return &e->item;
}

[-- Attachment #4: insque.c --]
[-- Type: text/x-csrc, Size: 448 bytes --]

#include <search.h>

struct node {
	struct node *next;
	struct node *prev;
};

void insque(void *element, void *pred)
{
	struct node *e = element;
	struct node *p = pred;

	if (!p) {
		e->next = e->prev = 0;
		return;
	}
	e->next = p->next;
	e->prev = p;
	p->next = e;
	if (e->next)
		e->next->prev = e;
}

void remque(void *element)
{
	struct node *e = element;

	if (e->next)
		e->next->prev = e->prev;
	if (e->prev)
		e->prev->next = e->next;
}

[-- Attachment #5: lsearch.c --]
[-- Type: text/x-csrc, Size: 609 bytes --]

#include <search.h>
#include <string.h>

void *lsearch(const void *key, void *base, size_t *nelp, size_t width,
	int (*compar)(const void *, const void *))
{
	char (*p)[width] = base;
	size_t n = *nelp;
	size_t i;

	for (i = 0; i < n; i++)
		if (compar(p[i], key) == 0)
			return p[i];
	*nelp = n+1;
	return memcpy(p[n], key, width);
}

void *lfind(const void *key, const void *base, size_t *nelp,
	size_t width, int (*compar)(const void *, const void *))
{
	char (*p)[width] = (void *)base;
	size_t n = *nelp;
	size_t i;

	for (i = 0; i < n; i++)
		if (compar(p[i], key) == 0)
			return p[i];
	return 0;
}



[-- Attachment #6: tsearch_avl.c --]
[-- Type: text/x-csrc, Size: 3351 bytes --]

#include <stdlib.h>
#include <search.h>

struct node {
	const void *key;
	struct node *left;
	struct node *right;
	int height;
};

static int delta(struct node *n) {
	return (n->left ? n->left->height:0) - (n->right ? n->right->height:0);
}

static void updateheight(struct node *n) {
	n->height = 0;
	if (n->left && n->left->height > n->height)
		n->height = n->left->height;
	if (n->right && n->right->height > n->height)
		n->height = n->right->height;
	n->height++;
}

static struct node *rotl(struct node *n) {
	struct node *r = n->right;
	n->right = r->left;
	r->left = n;
	updateheight(n);
	updateheight(r);
	return r;
}

static struct node *rotr(struct node *n) {
	struct node *l = n->left;
	n->left = l->right;
	l->right = n;
	updateheight(n);
	updateheight(l);
	return l;
}

static struct node *balance(struct node *n) {
	int d = delta(n);

	if (d < -1) {
		if (delta(n->right) > 0)
			n->right = rotr(n->right);
		return rotl(n);
	} else if (d > 1) {
		if (delta(n->left) < 0)
			n->left = rotl(n->left);
		return rotr(n);
	}
	updateheight(n);
	return n;
}

static struct node *find(struct node *n, const void *k,
	int (*cmp)(const void *, const void *))
{
	int c;

	if (!n)
		return 0;
	c = cmp(k, n->key);
	if (c == 0)
		return n;
	if (c < 0)
		return find(n->left, k, cmp);
	else
		return find(n->right, k, cmp);
}

static struct node *insert(struct node **n, const void *k,
	int (*cmp)(const void *, const void *), int *new)
{
	struct node *r = *n;
	int c;

	if (!r) {
		*n = r = malloc(sizeof **n);
		if (r) {
			r->key = k;
			r->left = r->right = 0;
			r->height = 1;
		}
		*new = 1;
		return r;
	}
	c = cmp(k, r->key);
	if (c == 0)
		return r;
	if (c < 0)
		r = insert(&r->left, k, cmp, new);
	else
		r = insert(&r->right, k, cmp, new);
	if (*new)
		*n = balance(*n);
	return r;
}

static struct node *movr(struct node *n, struct node *r) {
	if (!n)
		return r;
	n->right = movr(n->right, r);
	return balance(n);
}

static struct node *remove(struct node **n, const void *k,
	int (*cmp)(const void *, const void *), struct node *parent)
{
	int c;

	if (!*n)
		return 0;
	c = cmp(k, (*n)->key);
	if (c == 0) {
		struct node *r = *n;
		*n = movr(r->left, r->right);
		free(r);
		return parent;
	}
	if (c < 0)
		parent = remove(&(*n)->left, k, cmp, *n);
	else
		parent = remove(&(*n)->right, k, cmp, *n);
	if (parent)
		*n = balance(*n);
	return parent;
}

void *tdelete(const void *restrict key, void **restrict rootp,
	int(*compar)(const void *, const void *))
{
	/* last argument is arbitrary non-null pointer
	   which is returned when the root node is deleted */
	return remove((void*)rootp, key, compar, *rootp);
}

void *tfind(const void *key, void *const *rootp,
	int(*compar)(const void *, const void *))
{
	return find(*rootp, key, compar);
}

void *tsearch(const void *key, void **rootp,
	int (*compar)(const void *, const void *))
{
	int new = 0;
	return insert((void*)rootp, key, compar, &new);
}

static void walk(const struct node *r, void (*action)(const void *, VISIT, int), int d)
{
	if (r == 0)
		return;
	if (r->left == 0 && r->right == 0)
		action(r, leaf, d);
	else {
		action(r, preorder, d);
		walk(r->left, action, d+1);
		action(r, postorder, d);
		walk(r->right, action, d+1);
		action(r, endorder, d);
	}
}

void twalk(const void *root, void (*action)(const void *, VISIT, int))
{
	walk(root, action, 0);
}

[-- Attachment #7: tsearch_simple.c --]
[-- Type: text/x-csrc, Size: 1780 bytes --]

#include <stdlib.h>
#include <search.h>

struct node {
	const void *key;
	struct node *left;
	struct node *right;
};

static struct node **lookup(const void *key, struct node **r,
	int (*compar)(const void *, const void *))
{
	while (*r) {
		int c = compar(key, (*r)->key);
		if (c < 0)
			r = &(*r)->left;
		else if (c > 0)
			r = &(*r)->right;
		else
			break;
	}
	return r;
}

void *tdelete(const void *restrict key, void **restrict rootp,
	int(*compar)(const void *, const void *))
{
	struct node **r = (void*)rootp;
	struct node *parent = *r; /* arbitrary non-null pointer */
	struct node *a;
	struct node *b;
	int c;

	for (;;) {
		if (!*r)
			return 0;
		c = compar(key, (*r)->key);
		if (c == 0)
			break;
		parent = *r;
		if (c < 0)
			r = &(*r)->left;
		else
			r = &(*r)->right;
	}
	a = (*r)->left;
	b = (*r)->right;
	free(*r);
	if (a) {
		*r = a;
		for (; a->right; a = a->right);
		a->right = b;
	} else
		*r = b;
	return parent;
}

void *tfind(const void *key, void *const *rootp,
	int(*compar)(const void *, const void *))
{
	return *lookup(key, (void*)rootp, compar);
}

void *tsearch(const void *key, void **rootp,
	int (*compar)(const void *, const void *))
{
	struct node **r = lookup(key, (void*)rootp, compar);
	if (*r)
		return *r;
	*r = malloc(sizeof **r);
	if (*r) {
		(*r)->left = (*r)->right = 0;
		(*r)->key = key;
	}
	return *r;
}

static void rec(const struct node *r, void (*action)(const void *, VISIT, int), int d) {
	if (r == 0)
		return;
	if (r->left == 0 && r->right == 0)
		action(r, leaf, d);
	else {
		action(r, preorder, d);
		rec(r->left, action, d+1);
		action(r, postorder, d);
		rec(r->right, action, d+1);
		action(r, endorder, d);
	}
}

void twalk(const void *root, void (*action)(const void *, VISIT, int))
{
	rec(root, action, 0);
}

  parent reply	other threads:[~2011-06-25 18:31 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-05-28 23:41 Help assessing " Rich Felker
2011-05-29 16:19 ` gs
2011-05-29 16:44   ` gs
2011-05-29 17:32     ` gs
2011-05-29 18:08       ` Szabolcs Nagy
2011-05-30 10:30         ` Szabolcs Nagy
2011-05-30 15:47           ` Rich Felker
2011-05-30 17:27             ` Szabolcs Nagy
2011-06-08 23:58               ` Completeness " Rich Felker
2011-06-21  1:46                 ` Szabolcs Nagy
2011-06-23  6:54                   ` Rich Felker
2011-06-23 13:25                     ` Szabolcs Nagy
2011-06-23 14:16                       ` Szabolcs Nagy
2011-06-23 18:50                         ` Szabolcs Nagy
2011-06-24 12:12                           ` Szabolcs Nagy
2011-06-25 18:31                 ` Szabolcs Nagy [this message]
2011-06-26 10:30                   ` Szabolcs Nagy
2011-06-29 21:14                 ` Rich Felker
2011-07-05 15:40                   ` Hiltjo Posthuma
2011-06-18 21:32               ` Help assessing " Szabolcs Nagy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20110625183106.GV27421@port70.net \
    --to=nsz@port70.net \
    --cc=musl@lists.openwall.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).