Skip to content

Commit 2092767

Browse files
sbrivio-rhummakynes
authored andcommitted
bitmap: Introduce bitmap_cut(): cut bits and shift remaining
The new bitmap function bitmap_cut() copies bits from source to destination by removing the region specified by parameters first and cut, and remapping the bits above the cut region by right shifting them. Signed-off-by: Stefano Brivio <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent f3a2181 commit 2092767

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed

include/linux/bitmap.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
* bitmap_find_next_zero_area_off(buf, len, pos, n, mask) as above
5454
* bitmap_shift_right(dst, src, n, nbits) *dst = *src >> n
5555
* bitmap_shift_left(dst, src, n, nbits) *dst = *src << n
56+
* bitmap_cut(dst, src, first, n, nbits) Cut n bits from first, copy rest
5657
* bitmap_replace(dst, old, new, mask, nbits) *dst = (*old & ~(*mask)) | (*new & *mask)
5758
* bitmap_remap(dst, src, old, new, nbits) *dst = map(old, new)(src)
5859
* bitmap_bitremap(oldbit, old, new, nbits) newbit = map(old, new)(oldbit)
@@ -133,6 +134,9 @@ extern void __bitmap_shift_right(unsigned long *dst, const unsigned long *src,
133134
unsigned int shift, unsigned int nbits);
134135
extern void __bitmap_shift_left(unsigned long *dst, const unsigned long *src,
135136
unsigned int shift, unsigned int nbits);
137+
extern void bitmap_cut(unsigned long *dst, const unsigned long *src,
138+
unsigned int first, unsigned int cut,
139+
unsigned int nbits);
136140
extern int __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
137141
const unsigned long *bitmap2, unsigned int nbits);
138142
extern void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,

lib/bitmap.c

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,72 @@ void __bitmap_shift_left(unsigned long *dst, const unsigned long *src,
168168
}
169169
EXPORT_SYMBOL(__bitmap_shift_left);
170170

171+
/**
172+
* bitmap_cut() - remove bit region from bitmap and right shift remaining bits
173+
* @dst: destination bitmap, might overlap with src
174+
* @src: source bitmap
175+
* @first: start bit of region to be removed
176+
* @cut: number of bits to remove
177+
* @nbits: bitmap size, in bits
178+
*
179+
* Set the n-th bit of @dst iff the n-th bit of @src is set and
180+
* n is less than @first, or the m-th bit of @src is set for any
181+
* m such that @first <= n < nbits, and m = n + @cut.
182+
*
183+
* In pictures, example for a big-endian 32-bit architecture:
184+
*
185+
* @src:
186+
* 31 63
187+
* | |
188+
* 10000000 11000001 11110010 00010101 10000000 11000001 01110010 00010101
189+
* | | | |
190+
* 16 14 0 32
191+
*
192+
* if @cut is 3, and @first is 14, bits 14-16 in @src are cut and @dst is:
193+
*
194+
* 31 63
195+
* | |
196+
* 10110000 00011000 00110010 00010101 00010000 00011000 00101110 01000010
197+
* | | |
198+
* 14 (bit 17 0 32
199+
* from @src)
200+
*
201+
* Note that @dst and @src might overlap partially or entirely.
202+
*
203+
* This is implemented in the obvious way, with a shift and carry
204+
* step for each moved bit. Optimisation is left as an exercise
205+
* for the compiler.
206+
*/
207+
void bitmap_cut(unsigned long *dst, const unsigned long *src,
208+
unsigned int first, unsigned int cut, unsigned int nbits)
209+
{
210+
unsigned int len = BITS_TO_LONGS(nbits);
211+
unsigned long keep = 0, carry;
212+
int i;
213+
214+
memmove(dst, src, len * sizeof(*dst));
215+
216+
if (first % BITS_PER_LONG) {
217+
keep = src[first / BITS_PER_LONG] &
218+
(~0UL >> (BITS_PER_LONG - first % BITS_PER_LONG));
219+
}
220+
221+
while (cut--) {
222+
for (i = first / BITS_PER_LONG; i < len; i++) {
223+
if (i < len - 1)
224+
carry = dst[i + 1] & 1UL;
225+
else
226+
carry = 0;
227+
228+
dst[i] = (dst[i] >> 1) | (carry << (BITS_PER_LONG - 1));
229+
}
230+
}
231+
232+
dst[first / BITS_PER_LONG] &= ~0UL << (first % BITS_PER_LONG);
233+
dst[first / BITS_PER_LONG] |= keep;
234+
}
235+
EXPORT_SYMBOL(bitmap_cut);
236+
171237
int __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
172238
const unsigned long *bitmap2, unsigned int bits)
173239
{

0 commit comments

Comments
 (0)