From 2ba224eca2998f56751a6dfe21c7a624dd949dd3 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 2 Oct 2015 12:33:58 -0600 Subject: [PATCH] Add support for bsearch() in C library --- ChangeLog | 3 + configs | 2 +- include/stdlib.h | 16 +++-- libc/stdlib/Make.defs | 2 +- libc/stdlib/lib_bsearch.c | 138 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 154 insertions(+), 7 deletions(-) create mode 100644 libc/stdlib/lib_bsearch.c diff --git a/ChangeLog b/ChangeLog index 0838c1843f..7f35156b3e 100755 --- a/ChangeLog +++ b/ChangeLog @@ -11005,3 +11005,6 @@ must be atomic (2015-09-20). 7.13 2015-xx-xx Gregory Nutt + + * libc/stdlib/lib_bsearch.c and include/stdlib.h: Add the bsearch() + function from NetBSD (2015-10-02). diff --git a/configs b/configs index bb669000c7..5c519b6b0a 160000 --- a/configs +++ b/configs @@ -1 +1 @@ -Subproject commit bb669000c76498d9a0a769948a403784fec897e1 +Subproject commit 5c519b6b0a7a28e785266190874adf297322589d diff --git a/include/stdlib.h b/include/stdlib.h index 12a1b951a9..fffcd83f8a 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -200,6 +200,12 @@ FAR void *memalign(size_t, size_t); FAR void *zalloc(size_t); FAR void *calloc(size_t, size_t); +#ifdef CONFIG_CAN_PASS_STRUCTS +struct mallinfo mallinfo(void); +#else +int mallinfo(struct mallinfo *info); +#endif + /* Arithmetic */ int abs(int j); @@ -226,11 +232,11 @@ int mkstemp(FAR char *path_template); void qsort(FAR void *base, size_t nmemb, size_t size, int (*compar)(FAR const void *, FAR const void *)); -#ifdef CONFIG_CAN_PASS_STRUCTS -struct mallinfo mallinfo(void); -#else -int mallinfo(struct mallinfo *info); -#endif +/* Binary search */ + +FAR void *bsearch(FAR const void *key, FAR const void *base, size_t nel, + size_t width, CODE int (*compar)(FAR const void *, + FAR const void *)); #undef EXTERN #if defined(__cplusplus) diff --git a/libc/stdlib/Make.defs b/libc/stdlib/Make.defs index 5f1b7a06a0..68eb75e68b 100644 --- a/libc/stdlib/Make.defs +++ b/libc/stdlib/Make.defs @@ -37,7 +37,7 @@ CSRCS += lib_abs.c lib_abort.c lib_div.c lib_ldiv.c lib_lldiv.c CSRCS += lib_imaxabs.c lib_itoa.c lib_labs.c lib_llabs.c -CSRCS += lib_rand.c lib_qsort.c +CSRCS += lib_bsearch.c lib_rand.c lib_qsort.c CSRCS += lib_strtol.c lib_strtoll.c lib_strtoul.c lib_strtoull.c CSRCS += lib_strtod.c lib_checkbase.c diff --git a/libc/stdlib/lib_bsearch.c b/libc/stdlib/lib_bsearch.c new file mode 100644 index 0000000000..538bac6a61 --- /dev/null +++ b/libc/stdlib/lib_bsearch.c @@ -0,0 +1,138 @@ +/***************************************************************************** + * libc/stdlib/lib_bsearch.c + * + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *****************************************************************************/ + +/***************************************************************************** + * Included Files + *****************************************************************************/ + +#include +#include + +/***************************************************************************** + * Public Functions + *****************************************************************************/ + +/***************************************************************************** + * Name: bsearch + * + * Description: + * Per OpenGroup.org: + * + * The bsearch() function will search an array of nel objects, the initial + * element of which is pointed to by 'base', for an element that matches + * the object pointed to by 'key'. The size of each element in the array + * is specified by 'width'. If the nel argument has the value zero, the + * comparison function pointed to by 'compar' will not be called and no + * match will be found. + * + * The comparison function pointed to by 'compar' will be called with two + * arguments that point to the 'key' object and to an array element, in + * that order. + * + * The application will ensure that the comparison function pointed to by + * 'compar 'does not alter the contents of the array. The implementation + * may reorder elements of the array between calls to the comparison + * function, but will not alter the contents of any individual element. + * + * The implementation will ensure that the first argument is always a + * pointer to the 'key'. + * + * When the same objects (consisting of width bytes, irrespective of their + * current positions in the array) are passed more than once to the + * comparison function, the results will be consistent with one another. + * That is, the same object will always compare the same way with the key. + * + * The application will ensure that the function returns an integer less + * than, equal to, or greater than 0 if the key object is considered, + * respectively, to be less than, to match, or to be greater than the + * array element. The application will ensure that the array consists of + * all the elements that compare less than, all the elements that compare + * equal to, and all the elements that compare greater than the key + * object, in that order. + * + * Returned Value: + * The bsearch() function will return a pointer to a matching member of + * the array, or a null pointer if no match is found. If two or more + * members compare equal, which member is returned is unspecified. + * + * Notes from the NetBSD version: + * The code below is a bit sneaky. After a comparison fails, we divide + * the work in half by moving either left or right. If 'lim' is odd, + * moving left simply involves halving 'lim': e.g., when 'lim' is 5 we + * look at item 2, so we change 'lim' to 2 so that we will look at items + * 0 & 1. If 'lim' is even, the same applies. If 'lim' is odd, moving + * right again involes halving 'lim', this time moving the base up one + * item past 'ptr': e.g., when 'lim' is 5 we change base to item 3 and + * make 'lim' 2 so that we will look at items 3 and 4. If 'lim' is + * even, however, we have to shrink it by one before halving: e.g., + * when 'lim' is 4, we still looked at item 2, so we have to make 'lim' + * 3, then halve, obtaining 1, so that we will only look at item 3. + * + *****************************************************************************/ + +FAR void *bsearch(FAR const void *key, FAR const void *base, size_t nel, + size_t width, CODE int (*compar)(FAR const void *, + FAR const void *)) +{ + FAR const void *ptr; + size_t lim; + int cmp; + + DEBUGASSERT(key != NULL); + DEBUGASSERT(base != NULL || nel == 0); + DEBUGASSERT(compar != NULL); + + for (lim = nel; lim != 0; lim >>= 1) + { + ptr = base + (lim >> 1) * width; + cmp = (*compar)(key, ptr); + + if (cmp == 0) + { + return (FAR void *)ptr; + } + + if (cmp > 0) + { + /* key > ptr: move right (else move left) */ + + base = (FAR const char *)ptr + width; + lim--; + } + } + + return NULL; +}