linux/lib/find_bit.c
<<
>>
Prefs
   1/* bit search implementation
   2 *
   3 * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
   4 * Written by David Howells (dhowells@redhat.com)
   5 *
   6 * Copyright (C) 2008 IBM Corporation
   7 * 'find_last_bit' is written by Rusty Russell <rusty@rustcorp.com.au>
   8 * (Inspired by David Howell's find_next_bit implementation)
   9 *
  10 * Rewritten by Yury Norov <yury.norov@gmail.com> to decrease
  11 * size and improve performance, 2015.
  12 *
  13 * This program is free software; you can redistribute it and/or
  14 * modify it under the terms of the GNU General Public License
  15 * as published by the Free Software Foundation; either version
  16 * 2 of the License, or (at your option) any later version.
  17 */
  18
  19#include <linux/bitops.h>
  20#include <linux/bitmap.h>
  21#include <linux/export.h>
  22#include <linux/kernel.h>
  23#include <linux/minmax.h>
  24
  25#if !defined(find_next_bit) || !defined(find_next_zero_bit) || \
  26                !defined(find_next_and_bit)
  27
  28/*
  29 * This is a common helper function for find_next_bit, find_next_zero_bit, and
  30 * find_next_and_bit. The differences are:
  31 *  - The "invert" argument, which is XORed with each fetched word before
  32 *    searching it for one bits.
  33 *  - The optional "addr2", which is anded with "addr1" if present.
  34 */
  35static inline unsigned long _find_next_bit(const unsigned long *addr1,
  36                const unsigned long *addr2, unsigned long nbits,
  37                unsigned long start, unsigned long invert)
  38{
  39        unsigned long tmp;
  40
  41        if (unlikely(start >= nbits))
  42                return nbits;
  43
  44        tmp = addr1[start / BITS_PER_LONG];
  45        if (addr2)
  46                tmp &= addr2[start / BITS_PER_LONG];
  47        tmp ^= invert;
  48
  49        /* Handle 1st word. */
  50        tmp &= BITMAP_FIRST_WORD_MASK(start);
  51        start = round_down(start, BITS_PER_LONG);
  52
  53        while (!tmp) {
  54                start += BITS_PER_LONG;
  55                if (start >= nbits)
  56                        return nbits;
  57
  58                tmp = addr1[start / BITS_PER_LONG];
  59                if (addr2)
  60                        tmp &= addr2[start / BITS_PER_LONG];
  61                tmp ^= invert;
  62        }
  63
  64        return min(start + __ffs(tmp), nbits);
  65}
  66#endif
  67
  68#ifndef find_next_bit
  69/*
  70 * Find the next set bit in a memory region.
  71 */
  72unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
  73                            unsigned long offset)
  74{
  75        return _find_next_bit(addr, NULL, size, offset, 0UL);
  76}
  77EXPORT_SYMBOL(find_next_bit);
  78#endif
  79
  80#ifndef find_next_zero_bit
  81unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
  82                                 unsigned long offset)
  83{
  84        return _find_next_bit(addr, NULL, size, offset, ~0UL);
  85}
  86EXPORT_SYMBOL(find_next_zero_bit);
  87#endif
  88
  89#if !defined(find_next_and_bit)
  90unsigned long find_next_and_bit(const unsigned long *addr1,
  91                const unsigned long *addr2, unsigned long size,
  92                unsigned long offset)
  93{
  94        return _find_next_bit(addr1, addr2, size, offset, 0UL);
  95}
  96EXPORT_SYMBOL(find_next_and_bit);
  97#endif
  98
  99#ifndef find_first_bit
 100/*
 101 * Find the first set bit in a memory region.
 102 */
 103unsigned long find_first_bit(const unsigned long *addr, unsigned long size)
 104{
 105        unsigned long idx;
 106
 107        for (idx = 0; idx * BITS_PER_LONG < size; idx++) {
 108                if (addr[idx])
 109                        return min(idx * BITS_PER_LONG + __ffs(addr[idx]), size);
 110        }
 111
 112        return size;
 113}
 114EXPORT_SYMBOL(find_first_bit);
 115#endif
 116
 117#ifndef find_first_zero_bit
 118/*
 119 * Find the first cleared bit in a memory region.
 120 */
 121unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size)
 122{
 123        unsigned long idx;
 124
 125        for (idx = 0; idx * BITS_PER_LONG < size; idx++) {
 126                if (addr[idx] != ~0UL)
 127                        return min(idx * BITS_PER_LONG + ffz(addr[idx]), size);
 128        }
 129
 130        return size;
 131}
 132EXPORT_SYMBOL(find_first_zero_bit);
 133#endif
 134
 135#ifndef find_last_bit
 136unsigned long find_last_bit(const unsigned long *addr, unsigned long size)
 137{
 138        if (size) {
 139                unsigned long val = BITMAP_LAST_WORD_MASK(size);
 140                unsigned long idx = (size-1) / BITS_PER_LONG;
 141
 142                do {
 143                        val &= addr[idx];
 144                        if (val)
 145                                return idx * BITS_PER_LONG + __fls(val);
 146
 147                        val = ~0ul;
 148                } while (idx--);
 149        }
 150        return size;
 151}
 152EXPORT_SYMBOL(find_last_bit);
 153#endif
 154
 155#ifdef __BIG_ENDIAN
 156
 157#if !defined(find_next_bit_le) || !defined(find_next_zero_bit_le)
 158static inline unsigned long _find_next_bit_le(const unsigned long *addr1,
 159                const unsigned long *addr2, unsigned long nbits,
 160                unsigned long start, unsigned long invert)
 161{
 162        unsigned long tmp;
 163
 164        if (unlikely(start >= nbits))
 165                return nbits;
 166
 167        tmp = addr1[start / BITS_PER_LONG];
 168        if (addr2)
 169                tmp &= addr2[start / BITS_PER_LONG];
 170        tmp ^= invert;
 171
 172        /* Handle 1st word. */
 173        tmp &= swab(BITMAP_FIRST_WORD_MASK(start));
 174        start = round_down(start, BITS_PER_LONG);
 175
 176        while (!tmp) {
 177                start += BITS_PER_LONG;
 178                if (start >= nbits)
 179                        return nbits;
 180
 181                tmp = addr1[start / BITS_PER_LONG];
 182                if (addr2)
 183                        tmp &= addr2[start / BITS_PER_LONG];
 184                tmp ^= invert;
 185        }
 186
 187        return min(start + __ffs(swab(tmp)), nbits);
 188}
 189#endif
 190
 191#ifndef find_next_zero_bit_le
 192unsigned long find_next_zero_bit_le(const void *addr, unsigned
 193                long size, unsigned long offset)
 194{
 195        return _find_next_bit_le(addr, NULL, size, offset, ~0UL);
 196}
 197EXPORT_SYMBOL(find_next_zero_bit_le);
 198#endif
 199
 200#ifndef find_next_bit_le
 201unsigned long find_next_bit_le(const void *addr, unsigned
 202                long size, unsigned long offset)
 203{
 204        return _find_next_bit_le(addr, NULL, size, offset, 0UL);
 205}
 206EXPORT_SYMBOL(find_next_bit_le);
 207#endif
 208
 209#endif /* __BIG_ENDIAN */
 210
 211unsigned long find_next_clump8(unsigned long *clump, const unsigned long *addr,
 212                               unsigned long size, unsigned long offset)
 213{
 214        offset = find_next_bit(addr, size, offset);
 215        if (offset == size)
 216                return size;
 217
 218        offset = round_down(offset, 8);
 219        *clump = bitmap_get_value8(addr, offset);
 220
 221        return offset;
 222}
 223EXPORT_SYMBOL(find_next_clump8);
 224