From: Yury Norov <[email protected]> This file contains implementation for: - find_last_bit; - find_first_zero_bit; - find_first_bit; - find_next_zero_bit; - find_next_bit.
So giving more generic name looks reasonable. Signed-off-by: Yury Norov <[email protected]> --- lib/Makefile | 2 +- lib/find_bit.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/find_next_bit.c | 192 --------------------------------------------------- 3 files changed, 195 insertions(+), 193 deletions(-) create mode 100644 lib/find_bit.c delete mode 100644 lib/find_next_bit.c diff --git a/lib/Makefile b/lib/Makefile index 13990aa..1cc93f4 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -25,7 +25,7 @@ obj-y += lockref.o obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \ gcd.o lcm.o list_sort.o uuid.o flex_array.o iovec.o clz_ctz.o \ - bsearch.o find_next_bit.o llist.o memweight.o kfifo.o \ + bsearch.o find_bit.o llist.o memweight.o kfifo.o \ percpu-refcount.o percpu_ida.o rhashtable.o reciprocal_div.o obj-y += string_helpers.o obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o diff --git a/lib/find_bit.c b/lib/find_bit.c new file mode 100644 index 0000000..236a850 --- /dev/null +++ b/lib/find_bit.c @@ -0,0 +1,194 @@ +/* find_bit.c: generic implementation fore: + * find_last_bit; find_first_zero_bit; find_first_bit; + * find_next_zero_bit; find_next_bit. + * + * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. + * Written by David Howells ([email protected]) + * + * Copyright (C) 2008 IBM Corporation + * 'find_last_bit' is written by Rusty Russell <[email protected]> + * (Inspired by David Howell's find_next_bit implementation) + * + * Rewritten by Yury Norov <[email protected]> to decrease + * size and improve performance, 2015. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/export.h> +#include <linux/kernel.h> + +#define HIGH_BITS_MASK(nr) (ULONG_MAX << (nr)) + +#if !defined(find_next_bit) || !defined(find_next_zero_bit) +static unsigned long _find_next_bit(const unsigned long *addr, + unsigned long nbits, unsigned long start, bool set) +{ + unsigned long tmp = set ? addr[start / BITS_PER_LONG] + : ~addr[start / BITS_PER_LONG]; + + /* Handle 1st word. */ + if (!IS_ALIGNED(start, BITS_PER_LONG)) { + tmp &= HIGH_BITS_MASK(start % BITS_PER_LONG); + start = round_down(start, BITS_PER_LONG); + } + + while (!tmp) { + start += BITS_PER_LONG; + if (start >= nbits) + return nbits; + + tmp = set ? addr[start / BITS_PER_LONG] + : ~addr[start / BITS_PER_LONG]; + } + + return start + __ffs(tmp); +} +#endif + +#ifndef find_next_bit +/* + * Find the next set bit in a memory region. + */ +unsigned long find_next_bit(const unsigned long *addr, unsigned long size, + unsigned long offset) +{ + if (offset >= size) + return size; + + return min(_find_next_bit(addr, size, offset, 1), size); +} +EXPORT_SYMBOL(find_next_bit); +#endif + +#ifndef find_next_zero_bit +unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, + unsigned long offset) +{ + if (offset >= size) + return size; + + return min(_find_next_bit(addr, size, offset, 0), size); +} +EXPORT_SYMBOL(find_next_zero_bit); +#endif + +#ifndef find_first_bit +/* + * Find the first set bit in a memory region. + */ +unsigned long find_first_bit(const unsigned long *addr, unsigned long size) +{ + unsigned long idx; + + for (idx = 0; idx * BITS_PER_LONG < size; idx++) { + if (addr[idx]) + return min(idx * BITS_PER_LONG + __ffs(addr[idx]), size); + } + + return size; +} +EXPORT_SYMBOL(find_first_bit); +#endif + +#ifndef find_first_zero_bit +/* + * Find the first cleared bit in a memory region. + */ +unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size) +{ + unsigned long idx; + + for (idx = 0; idx * BITS_PER_LONG < size; idx++) { + if (addr[idx] != ULONG_MAX) + return min(idx * BITS_PER_LONG + ffz(addr[idx]), size); + } + + return size; +} +EXPORT_SYMBOL(find_first_zero_bit); +#endif + +#ifndef find_last_bit +unsigned long find_last_bit(const unsigned long *addr, unsigned long size) +{ + unsigned long idx = DIV_ROUND_UP(size, BITS_PER_LONG); + + while (idx--) { + if (addr[idx]) + return min(idx * BITS_PER_LONG + __fls(addr[idx]), size); + } + + return size; +} +EXPORT_SYMBOL(find_last_bit); +#endif + +#ifdef __BIG_ENDIAN + +/* include/linux/byteorder does not support "unsigned long" type */ +static inline unsigned long ext2_swab(const unsigned long y) +{ +#if BITS_PER_LONG == 64 + return (unsigned long) __swab64((u64) y); +#elif BITS_PER_LONG == 32 + return (unsigned long) __swab32((u32) y); +#else +#error BITS_PER_LONG not defined +#endif +} + +#if !defined(find_next_bit_le) || !defined(find_next_zero_bit_le) +static unsigned long _find_next_bit_le(const unsigned long *addr, + unsigned long nbits, unsigned long start, bool set) +{ + unsigned long tmp = set ? addr[start / BITS_PER_LONG] + : ~addr[start / BITS_PER_LONG]; + + /* Handle 1st word. */ + if (!IS_ALIGNED(start, BITS_PER_LONG)) { + tmp &= ext2_swab(HIGH_BITS_MASK(start % BITS_PER_LONG)); + start = round_down(start, BITS_PER_LONG); + } + + while (!tmp) { + start += BITS_PER_LONG; + if (start >= nbits) + return nbits; + + tmp = set ? addr[start / BITS_PER_LONG] + : ~addr[start / BITS_PER_LONG]; + } + + return start + __ffs(ext2_swab(tmp)); +} +#endif + +#ifndef find_next_zero_bit_le +unsigned long find_next_zero_bit_le(const void *addr, unsigned + long size, unsigned long offset) +{ + if (offset >= size) + return size; + + return min(_find_next_bit_le(addr, size, offset, 0), size); +} +EXPORT_SYMBOL(find_next_zero_bit_le); +#endif + +#ifndef find_next_bit_le +unsigned long find_next_bit_le(const void *addr, unsigned + long size, unsigned long offset) +{ + if (offset >= size) + return size; + + return min(_find_next_bit_le(addr, size, offset, 1), size); +} +EXPORT_SYMBOL(find_next_bit_le); +#endif + +#endif /* __BIG_ENDIAN */ diff --git a/lib/find_next_bit.c b/lib/find_next_bit.c deleted file mode 100644 index 2087839..0000000 --- a/lib/find_next_bit.c +++ /dev/null @@ -1,192 +0,0 @@ -/* find_next_bit.c: fallback find next bit implementation - * - * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. - * Written by David Howells ([email protected]) - * - * Copyright (C) 2008 IBM Corporation - * 'find_last_bit' is written by Rusty Russell <[email protected]> - * (Inspired by David Howell's find_next_bit implementation) - * - * Rewritten by Yury Norov <[email protected]> to decrease - * size and improve performance, 2015. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include <linux/export.h> -#include <linux/kernel.h> - -#define HIGH_BITS_MASK(nr) (ULONG_MAX << (nr)) - -#if !defined(find_next_bit) || !defined(find_next_zero_bit) -static unsigned long _find_next_bit(const unsigned long *addr, - unsigned long nbits, unsigned long start, bool set) -{ - unsigned long tmp = set ? addr[start / BITS_PER_LONG] - : ~addr[start / BITS_PER_LONG]; - - /* Handle 1st word. */ - if (!IS_ALIGNED(start, BITS_PER_LONG)) { - tmp &= HIGH_BITS_MASK(start % BITS_PER_LONG); - start = round_down(start, BITS_PER_LONG); - } - - while (!tmp) { - start += BITS_PER_LONG; - if (start >= nbits) - return nbits; - - tmp = set ? addr[start / BITS_PER_LONG] - : ~addr[start / BITS_PER_LONG]; - } - - return start + __ffs(tmp); -} -#endif - -#ifndef find_next_bit -/* - * Find the next set bit in a memory region. - */ -unsigned long find_next_bit(const unsigned long *addr, unsigned long size, - unsigned long offset) -{ - if (offset >= size) - return size; - - return min(_find_next_bit(addr, size, offset, 1), size); -} -EXPORT_SYMBOL(find_next_bit); -#endif - -#ifndef find_next_zero_bit -unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, - unsigned long offset) -{ - if (offset >= size) - return size; - - return min(_find_next_bit(addr, size, offset, 0), size); -} -EXPORT_SYMBOL(find_next_zero_bit); -#endif - -#ifndef find_first_bit -/* - * Find the first set bit in a memory region. - */ -unsigned long find_first_bit(const unsigned long *addr, unsigned long size) -{ - unsigned long idx; - - for (idx = 0; idx * BITS_PER_LONG < size; idx++) { - if (addr[idx]) - return min(idx * BITS_PER_LONG + __ffs(addr[idx]), size); - } - - return size; -} -EXPORT_SYMBOL(find_first_bit); -#endif - -#ifndef find_first_zero_bit -/* - * Find the first cleared bit in a memory region. - */ -unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size) -{ - unsigned long idx; - - for (idx = 0; idx * BITS_PER_LONG < size; idx++) { - if (addr[idx] != ULONG_MAX) - return min(idx * BITS_PER_LONG + ffz(addr[idx]), size); - } - - return size; -} -EXPORT_SYMBOL(find_first_zero_bit); -#endif - -#ifndef find_last_bit -unsigned long find_last_bit(const unsigned long *addr, unsigned long size) -{ - unsigned long idx = DIV_ROUND_UP(size, BITS_PER_LONG); - - while (idx--) { - if (addr[idx]) - return min(idx * BITS_PER_LONG + __fls(addr[idx]), size); - } - - return size; -} -EXPORT_SYMBOL(find_last_bit); -#endif - -#ifdef __BIG_ENDIAN - -/* include/linux/byteorder does not support "unsigned long" type */ -static inline unsigned long ext2_swab(const unsigned long y) -{ -#if BITS_PER_LONG == 64 - return (unsigned long) __swab64((u64) y); -#elif BITS_PER_LONG == 32 - return (unsigned long) __swab32((u32) y); -#else -#error BITS_PER_LONG not defined -#endif -} - -#if !defined(find_next_bit_le) || !defined(find_next_zero_bit_le) -static unsigned long _find_next_bit_le(const unsigned long *addr, - unsigned long nbits, unsigned long start, bool set) -{ - unsigned long tmp = set ? addr[start / BITS_PER_LONG] - : ~addr[start / BITS_PER_LONG]; - - /* Handle 1st word. */ - if (!IS_ALIGNED(start, BITS_PER_LONG)) { - tmp &= ext2_swab(HIGH_BITS_MASK(start % BITS_PER_LONG)); - start = round_down(start, BITS_PER_LONG); - } - - while (!tmp) { - start += BITS_PER_LONG; - if (start >= nbits) - return nbits; - - tmp = set ? addr[start / BITS_PER_LONG] - : ~addr[start / BITS_PER_LONG]; - } - - return start + __ffs(ext2_swab(tmp)); -} -#endif - -#ifndef find_next_zero_bit_le -unsigned long find_next_zero_bit_le(const void *addr, unsigned - long size, unsigned long offset) -{ - if (offset >= size) - return size; - - return min(_find_next_bit_le(addr, size, offset, 0), size); -} -EXPORT_SYMBOL(find_next_zero_bit_le); -#endif - -#ifndef find_next_bit_le -unsigned long find_next_bit_le(const void *addr, unsigned - long size, unsigned long offset) -{ - if (offset >= size) - return size; - - return min(_find_next_bit_le(addr, size, offset, 1), size); -} -EXPORT_SYMBOL(find_next_bit_le); -#endif - -#endif /* __BIG_ENDIAN */ -- 2.1.0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/

