summaryrefslogblamecommitdiffstats
path: root/libsyscalls_find_named_number.c
blob: fe8bb47f2b08ac827463e40c81db491e1e6bcfb3 (plain) (tree)












































































































































                                                                                                     
/* See LICENSE file for copyright and license details. */
#include "common.h"


#ifdef USE_INTERPOLATION_SEARCH

# ifndef INTERPOLATION_SEARCH_FLOAT
#  define INTERPOLATION_SEARCH_FLOAT long double
# endif


/* convertion to unsigned is a modulo (unsigned maximum + 1) operation */
# define DIFF(TYPE, A, B) ((unsigned TYPE)(A) - (unsigned TYPE)(B))

# define INTERPOL_SEARCH(KEY, BASE, N, READ)\
	do {\
		INTERPOLATION_SEARCH_FLOAT guess_d;\
		unsigned long long int guess;\
		size_t h = (N);\
		\
		if (!h--)\
			return NULL;\
		\
		if ((KEY) <= READ((BASE), 0))\
			return (KEY) == READ((BASE), 0) ? &(BASE)[0] : NULL;\
		if ((KEY) >= READ((BASE), h))\
			return (KEY) == READ((BASE), h) ? &(BASE)[h] : NULL;\
		if (READ((BASE), 0) == READ((BASE), h))\
			return NULL;\
		\
		goto use_double;\
		guess = DIFF(long long int, (KEY), READ((BASE), 0));\
		if (h > ULLONG_MAX / guess)\
			goto use_double;\
		\
		for (;;) {\
			guess = DIFF(long long int, (KEY), READ((BASE), 0));\
			guess *= (unsigned long long int)h;\
			guess /= DIFF(long long int, READ((BASE), h), READ((BASE), 0));\
			\
			if (READ((BASE), guess) < (KEY)) {\
				h -= guess += 1;\
				(BASE) = &(BASE)[guess];\
			} else if (READ((BASE), guess) > (KEY)) {\
				h = guess -= 1;\
			} else {\
				return &(BASE)[guess];\
			}\
			\
			if ((KEY) <= READ((BASE), 0))\
				return (KEY) == READ((BASE), 0) ? &(BASE)[0] : NULL;\
			if ((KEY) >= READ((BASE), h))\
				return (KEY) == READ((BASE), h) ? &(BASE)[h] : NULL;\
			if (READ((BASE), 0) == READ((BASE), h))\
				return NULL;\
		}\
		\
	use_double:\
		for (;;) {\
			guess = DIFF(long long int, (KEY), READ((BASE), 0));\
			guess_d = (INTERPOLATION_SEARCH_FLOAT)guess * (INTERPOLATION_SEARCH_FLOAT)h;\
			guess = DIFF(long long int, READ((BASE), h), READ((BASE), 0));\
			guess_d /= (INTERPOLATION_SEARCH_FLOAT)guess;\
			guess = (unsigned long long int)guess_d;\
			\
			if (READ((BASE), guess) < (KEY)) {\
				h -= guess += 1;\
				(BASE) = &(BASE)[guess];\
			} else if (READ((BASE), guess) > (KEY)) {\
				h = guess -= 1;\
			} else {\
				return &(BASE)[guess];\
			}\
			\
			if ((KEY) <= READ((BASE), 0))\
				return (KEY) == READ((BASE), 0) ? &(BASE)[0] : NULL;\
			if ((KEY) >= READ((BASE), h))\
				return (KEY) == READ((BASE), h) ? &(BASE)[h] : NULL;\
			if (READ((BASE), 0) == READ((BASE), h))\
				return NULL;\
		}\
	} while (0)


#else


PURE_FUNCTION
static int
signed_named_number_cmp(const void *a_, const void *b_)
{
	const struct libsyscalls_named_number *a = a_, *b = b_;
	return a->number.s < b->number.s ? -1 : a->number.s > b->number.s;
}


PURE_FUNCTION
static int
unsigned_named_number_cmp(const void *a_, const void *b_)
{
	const struct libsyscalls_named_number *a = a_, *b = b_;
	return a->number.u < b->number.u ? -1 : a->number.u > b->number.u;
}


#endif


const struct libsyscalls_named_number *
libsyscalls_find_signed_named_number(signed long long int key,
                                     const struct libsyscalls_named_number *base, size_t n)
{
#ifdef USE_INTERPOLATION_SEARCH
# define X(ARR, I) ((ARR)[I].number.s)
	INTERPOL_SEARCH(key, base, n, X);
# undef X
#else
	struct libsyscalls_named_number struct_key = {.number.s = key};
	return bsearch(&struct_key, base, n, sizeof(*base), &signed_named_number_cmp);
#endif
}


const struct libsyscalls_named_number *
libsyscalls_find_unsigned_named_number(unsigned long long int key,
                                       const struct libsyscalls_named_number *base, size_t n)
{
#ifdef USE_INTERPOLATION_SEARCH
# define X(ARR, I) ((ARR)[I].number.u)
	INTERPOL_SEARCH(key, base, n, X);
# undef X
#else
	struct libsyscalls_named_number struct_key = {.number.u = key};
	return bsearch(&struct_key, base, n, sizeof(*base), &unsigned_named_number_cmp);
#endif
}


extern inline const struct libsyscalls_named_number *
libsyscalls_find_named_number(unsigned long long int key, int is_signed,
                              const struct libsyscalls_named_number *base, size_t n);