1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef __CUTILS_BITOPS_H
18#define __CUTILS_BITOPS_H
19
20#include <stdbool.h>
21#include <string.h>
22#include <strings.h>
23#include <sys/cdefs.h>
24
25__BEGIN_DECLS
26
27/*
28 * Bitmask Operations
29 *
30 * Note this doesn't provide any locking/exclusion, and isn't atomic.
31 * Additionally no bounds checking is done on the bitmask array.
32 *
33 * Example:
34 *
35 * int num_resources;
36 * unsigned int resource_bits[BITS_TO_WORDS(num_resources)];
37 * bitmask_init(resource_bits, num_resources);
38 * ...
39 * int bit = bitmask_ffz(resource_bits, num_resources);
40 * bitmask_set(resource_bits, bit);
41 * ...
42 * if (bitmask_test(resource_bits, bit)) { ... }
43 * ...
44 * bitmask_clear(resource_bits, bit);
45 *
46 */
47
48#define BITS_PER_WORD    (sizeof(unsigned int) * 8)
49#define BITS_TO_WORDS(x) (((x) + BITS_PER_WORD - 1) / BITS_PER_WORD)
50#define BIT_IN_WORD(x)   ((x) % BITS_PER_WORD)
51#define BIT_WORD(x)      ((x) / BITS_PER_WORD)
52#define BIT_MASK(x)      (1 << BIT_IN_WORD(x))
53
54static inline void bitmask_init(unsigned int *bitmask, int num_bits)
55{
56    memset(bitmask, 0, BITS_TO_WORDS(num_bits)*sizeof(unsigned int));
57}
58
59static inline int bitmask_ffz(unsigned int *bitmask, int num_bits)
60{
61    int bit, result;
62    size_t i;
63
64    for (i = 0; i < BITS_TO_WORDS(num_bits); i++) {
65        bit = ffs(~bitmask[i]);
66        if (bit) {
67            // ffs is 1-indexed, return 0-indexed result
68            bit--;
69            result = BITS_PER_WORD * i + bit;
70            if (result >= num_bits)
71                return -1;
72            return result;
73        }
74    }
75    return -1;
76}
77
78static inline int bitmask_weight(unsigned int *bitmask, int num_bits)
79{
80    size_t i;
81    int weight = 0;
82
83    for (i = 0; i < BITS_TO_WORDS(num_bits); i++)
84        weight += __builtin_popcount(bitmask[i]);
85    return weight;
86}
87
88static inline void bitmask_set(unsigned int *bitmask, int bit)
89{
90    bitmask[BIT_WORD(bit)] |= BIT_MASK(bit);
91}
92
93static inline void bitmask_clear(unsigned int *bitmask, int bit)
94{
95    bitmask[BIT_WORD(bit)] &= ~BIT_MASK(bit);
96}
97
98static inline bool bitmask_test(unsigned int *bitmask, int bit)
99{
100    return bitmask[BIT_WORD(bit)] & BIT_MASK(bit);
101}
102
103static inline int popcount(unsigned int x)
104{
105    return __builtin_popcount(x);
106}
107
108static inline int popcountl(unsigned long x)
109{
110    return __builtin_popcountl(x);
111}
112
113static inline int popcountll(unsigned long long x)
114{
115    return __builtin_popcountll(x);
116}
117
118__END_DECLS
119
120#endif /* __CUTILS_BITOPS_H */
121