source: mainline/kernel/generic/src/adt/bitmap.c@ a35b458

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a35b458 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 8.8 KB
Line 
1/*
2 * Copyright (c) 2006 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup genericadt
30 * @{
31 */
32/**
33 * @file
34 * @brief Implementation of bitmap ADT.
35 *
36 * This file implements bitmap ADT and provides functions for
37 * setting and clearing ranges of bits and for finding ranges
38 * of unset bits.
39 */
40
41#include <adt/bitmap.h>
42#include <align.h>
43#include <assert.h>
44#include <macros.h>
45#include <typedefs.h>
46
47#define ALL_ONES 0xff
48#define ALL_ZEROES 0x00
49
50/** Unchecked version of bitmap_get()
51 *
52 * This version of bitmap_get() does not do any boundary checks.
53 *
54 * @param bitmap Bitmap to access.
55 * @param element Element to access.
56 *
57 * @return Bit value of the element in the bitmap.
58 *
59 */
60static unsigned int bitmap_get_fast(bitmap_t *bitmap, size_t element)
61{
62 size_t byte = element / BITMAP_ELEMENT;
63 uint8_t mask = 1 << (element & BITMAP_REMAINER);
64
65 return !!((bitmap->bits)[byte] & mask);
66}
67
68/** Get bitmap size
69 *
70 * Return the size (in bytes) required for the bitmap.
71 *
72 * @param elements Number bits stored in bitmap.
73 *
74 * @return Size (in bytes) required for the bitmap.
75 *
76 */
77size_t bitmap_size(size_t elements)
78{
79 size_t size = elements / BITMAP_ELEMENT;
80
81 if ((elements % BITMAP_ELEMENT) != 0)
82 size++;
83
84 return size;
85}
86
87/** Initialize bitmap.
88 *
89 * No portion of the bitmap is set or cleared by this function.
90 *
91 * @param bitmap Bitmap structure.
92 * @param elements Number of bits stored in bitmap.
93 * @param data Address of the memory used to hold the map.
94 * The optional 2nd level bitmap follows the 1st
95 * level bitmap.
96 *
97 */
98void bitmap_initialize(bitmap_t *bitmap, size_t elements, void *data)
99{
100 bitmap->elements = elements;
101 bitmap->bits = (uint8_t *) data;
102 bitmap->next_fit = 0;
103}
104
105/** Set range of bits.
106 *
107 * @param bitmap Bitmap structure.
108 * @param start Starting bit.
109 * @param count Number of bits to set.
110 *
111 */
112void bitmap_set_range(bitmap_t *bitmap, size_t start, size_t count)
113{
114 assert(start + count <= bitmap->elements);
115
116 if (count == 0)
117 return;
118
119 size_t start_byte = start / BITMAP_ELEMENT;
120 size_t aligned_start = ALIGN_UP(start, BITMAP_ELEMENT);
121
122 /* Leading unaligned bits */
123 size_t lub = min(aligned_start - start, count);
124
125 /* Aligned middle bits */
126 size_t amb = (count > lub) ? (count - lub) : 0;
127
128 /* Trailing aligned bits */
129 size_t tab = amb % BITMAP_ELEMENT;
130
131 if (start + count < aligned_start) {
132 /* Set bits in the middle of byte. */
133 bitmap->bits[start_byte] |=
134 ((1 << lub) - 1) << (start & BITMAP_REMAINER);
135 return;
136 }
137
138 if (lub) {
139 /* Make sure to set any leading unaligned bits. */
140 bitmap->bits[start_byte] |=
141 ~((1 << (BITMAP_ELEMENT - lub)) - 1);
142 }
143
144 size_t i;
145
146 for (i = 0; i < amb / BITMAP_ELEMENT; i++) {
147 /* The middle bits can be set byte by byte. */
148 bitmap->bits[aligned_start / BITMAP_ELEMENT + i] =
149 ALL_ONES;
150 }
151
152 if (tab) {
153 /* Make sure to set any trailing aligned bits. */
154 bitmap->bits[aligned_start / BITMAP_ELEMENT + i] |=
155 (1 << tab) - 1;
156 }
157}
158
159/** Clear range of bits.
160 *
161 * @param bitmap Bitmap structure.
162 * @param start Starting bit.
163 * @param count Number of bits to clear.
164 *
165 */
166void bitmap_clear_range(bitmap_t *bitmap, size_t start, size_t count)
167{
168 assert(start + count <= bitmap->elements);
169
170 if (count == 0)
171 return;
172
173 size_t start_byte = start / BITMAP_ELEMENT;
174 size_t aligned_start = ALIGN_UP(start, BITMAP_ELEMENT);
175
176 /* Leading unaligned bits */
177 size_t lub = min(aligned_start - start, count);
178
179 /* Aligned middle bits */
180 size_t amb = (count > lub) ? (count - lub) : 0;
181
182 /* Trailing aligned bits */
183 size_t tab = amb % BITMAP_ELEMENT;
184
185 if (start + count < aligned_start) {
186 /* Set bits in the middle of byte */
187 bitmap->bits[start_byte] &=
188 ~(((1 << lub) - 1) << (start & BITMAP_REMAINER));
189 return;
190 }
191
192 if (lub) {
193 /* Make sure to clear any leading unaligned bits. */
194 bitmap->bits[start_byte] &=
195 (1 << (BITMAP_ELEMENT - lub)) - 1;
196 }
197
198 size_t i;
199
200 for (i = 0; i < amb / BITMAP_ELEMENT; i++) {
201 /* The middle bits can be cleared byte by byte. */
202 bitmap->bits[aligned_start / BITMAP_ELEMENT + i] =
203 ALL_ZEROES;
204 }
205
206 if (tab) {
207 /* Make sure to clear any trailing aligned bits. */
208 bitmap->bits[aligned_start / BITMAP_ELEMENT + i] &=
209 ~((1 << tab) - 1);
210 }
211
212 bitmap->next_fit = start_byte;
213}
214
215/** Copy portion of one bitmap into another bitmap.
216 *
217 * @param dst Destination bitmap.
218 * @param src Source bitmap.
219 * @param count Number of bits to copy.
220 *
221 */
222void bitmap_copy(bitmap_t *dst, bitmap_t *src, size_t count)
223{
224 assert(count <= dst->elements);
225 assert(count <= src->elements);
226
227 size_t i;
228
229 for (i = 0; i < count / BITMAP_ELEMENT; i++)
230 dst->bits[i] = src->bits[i];
231
232 if (count % BITMAP_ELEMENT) {
233 bitmap_clear_range(dst, i * BITMAP_ELEMENT,
234 count % BITMAP_ELEMENT);
235 dst->bits[i] |= src->bits[i] &
236 ((1 << (count % BITMAP_ELEMENT)) - 1);
237 }
238}
239
240static int constraint_satisfy(size_t index, size_t base, size_t constraint)
241{
242 return (((base + index) & constraint) == 0);
243}
244
245/** Find a continuous zero bit range
246 *
247 * Find a continuous zero bit range in the bitmap. The address
248 * computed as the sum of the index of the first zero bit and
249 * the base argument needs to be compliant with the constraint
250 * (those bits that are set in the constraint cannot be set in
251 * the address).
252 *
253 * If the index argument is non-NULL, the continuous zero range
254 * is set and the index of the first bit is stored to index.
255 * Otherwise the bitmap stays untouched.
256 *
257 * @param bitmap Bitmap structure.
258 * @param count Number of continuous zero bits to find.
259 * @param base Address of the first bit in the bitmap.
260 * @param prefered Prefered address to start searching from.
261 * @param constraint Constraint for the address of the first zero bit.
262 * @param index Place to store the index of the first zero
263 * bit. Can be NULL (in which case the bitmap
264 * is not modified).
265 *
266 * @return Non-zero if a continuous range of zero bits satisfying
267 * the constraint has been found.
268 * @return Zero otherwise.
269 *
270 */
271bool bitmap_allocate_range(bitmap_t *bitmap, size_t count, size_t base,
272 size_t prefered, size_t constraint, size_t *index)
273{
274 if (count == 0)
275 return false;
276
277 size_t size = bitmap_size(bitmap->elements);
278 size_t next_fit = bitmap->next_fit;
279
280 /*
281 * Adjust the next-fit value according to the address
282 * the caller prefers to start the search at.
283 */
284 if ((prefered > base) && (prefered < base + bitmap->elements)) {
285 size_t prefered_fit = (prefered - base) / BITMAP_ELEMENT;
286
287 if (prefered_fit > next_fit)
288 next_fit = prefered_fit;
289 }
290
291 for (size_t pos = 0; pos < size; pos++) {
292 size_t byte = (next_fit + pos) % size;
293
294 /* Skip if the current byte has all bits set */
295 if (bitmap->bits[byte] == ALL_ONES)
296 continue;
297
298 size_t byte_bit = byte * BITMAP_ELEMENT;
299
300 for (size_t bit = 0; bit < BITMAP_ELEMENT; bit++) {
301 size_t i = byte_bit + bit;
302
303 if (i >= bitmap->elements)
304 break;
305
306 if (!constraint_satisfy(i, base, constraint))
307 continue;
308
309 if (!bitmap_get_fast(bitmap, i)) {
310 size_t continuous = 1;
311
312 for (size_t j = 1; j < count; j++) {
313 if ((i + j < bitmap->elements) &&
314 (!bitmap_get_fast(bitmap, i + j)))
315 continuous++;
316 else
317 break;
318 }
319
320 if (continuous == count) {
321 if (index != NULL) {
322 bitmap_set_range(bitmap, i, count);
323 bitmap->next_fit = i / BITMAP_ELEMENT;
324 *index = i;
325 }
326
327 return true;
328 } else
329 i += continuous;
330 }
331 }
332 }
333
334 return false;
335}
336
337/** @}
338 */
Note: See TracBrowser for help on using the repository browser.