Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

/*	$NetBSD: bitmap.h,v 1.8 2018/08/27 14:52:16 riastradh Exp $	*/

/*-
 * Copyright (c) 2018 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Taylor R. Campbell.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef _LINUX_BITMAP_H_
#define _LINUX_BITMAP_H_

#include <sys/param.h>
#include <sys/types.h>
#include <sys/systm.h>

/*
 * bitmap_zero(bitmap, nbits)
 *
 *	Zero a bitmap that was allocated to have nbits bits.  Yes, this
 *	zeros bits past nbits.
 */
static inline void
bitmap_zero(unsigned long *bitmap, size_t nbits)
{
	const size_t bpl = NBBY * sizeof(*bitmap);
	size_t n = howmany(nbits, bpl);

	memset(bitmap, 0, n * sizeof(*bitmap));
}

/*
 * bitmap_empty(bitmap, nbits)
 *
 *	Return true if all bits at 0, 1, 2, ..., nbits-2, nbits-1 are
 *	0, or false if any of them is 1.
 */
static inline bool
bitmap_empty(const unsigned long *bitmap, size_t nbits)
{
	const size_t bpl = NBBY * sizeof(*bitmap);

	for (; nbits >= bpl; nbits -= bpl) {
		if (*bitmap++)
			return false;
	}

	if (nbits) {
		if (*bitmap & ~(~0UL << nbits))
			return false;
	}

	return true;
}

/*
 * bitmap_weight(bitmap, nbits)
 *
 *	Compute the number of 1 bits at 0, 1, 2, ..., nbits-2, nbits-1.
 */
static inline int
bitmap_weight(const unsigned long *bitmap, size_t nbits)
{
	const size_t bpl = NBBY * sizeof(*bitmap);
	int weight = 0;

	for (; nbits >= bpl; nbits -= bpl)
		weight += popcountl(*bitmap++);
	if (nbits)
		weight += popcountl(*bitmap & ~(~0UL << nbits));

	return weight;
}

/*
 * bitmap_set(bitmap, startbit, nbits)
 *
 *	Set bits at startbit, startbit+1, ..., startbit+nbits-2,
 *	startbit+nbits-1 to 1.
 */
static inline void
bitmap_set(unsigned long *bitmap, size_t startbit, size_t nbits)
{
	const size_t bpl = NBBY * sizeof(*bitmap);
	unsigned long *p = bitmap + startbit/bpl;
	unsigned initial = startbit%bpl;

	/* Handle an initial odd word if any.  */
	if (initial) {
		/* Does the whole thing fit in a single word?  */
		if (nbits <= bpl - initial) {
			/* Yes: just set nbits starting at initial.  */
			*p |= ~(~0ULL << nbits) << initial;
			return;
		}
		/* Nope: set all bits above initial, and advance.  */
		*p++ |= ~0ULL << initial;
		nbits -= bpl - initial;
	}

	/* Set the middle part to all bits 1.  */
	for (; nbits >= bpl; nbits -= bpl)
		*p++ = ~0UL;

	/* Handle a final odd word if any by setting its low nbits.  */
	if (nbits)
		*p |= ~(~0ULL << nbits);
}

/*
 * bitmap_clear(bitmap, startbit, nbits)
 *
 *	Clear bits at startbit, startbit+1, ..., startbit+nbits-2,
 *	startbit+nbits-1, replacing them by 0.
 */
static inline void
bitmap_clear(unsigned long *bitmap, size_t startbit, size_t nbits)
{
	const size_t bpl = NBBY * sizeof(*bitmap);
	unsigned long *p = bitmap + startbit/bpl;
	unsigned initial = startbit%bpl;

	/* Handle an initial odd word if any.  */
	if (initial) {
		/* Does the whole thing fit in a single word?  */
		if (nbits <= bpl - initial) {
			/* Yes: just clear nbits starting at initial.  */
			*p &= ~(~(~0ULL << nbits) << initial);
			return;
		}
		/* Nope: clear all bits above initial, and advance.  */
		*p++ &= ~(~0ULL << initial);
		nbits -= bpl - initial;
	}

	/* Zero the middle part.  */
	for (; nbits >= bpl; nbits -= bpl)
		*p++ = 0UL;

	/* Handle a final odd word if any by clearing its low nbits.  */
	if (nbits)
		*p &= ~0ULL << nbits;
}

/*
 * bitmap_and(dst, src1, src2, nbits)
 *
 *	Set dst to be the bitwise AND of src1 and src2, all bitmaps
 *	allocated to have nbits bits.  Yes, this modifies bits past
 *	nbits.  Any pair of {dst, src1, src2} may be aliases.
 */
static inline void
bitmap_and(unsigned long *dst, const unsigned long *src1,
    const unsigned long *src2, size_t nbits)
{
	const size_t bpl = NBBY * sizeof(unsigned long);
	size_t n = howmany(nbits, bpl);

	while (n --> 0)
		*dst++ = *src1++ & *src2++;
}

/*
 * bitmap_or(dst, src1, src2, nbits)
 *
 *	Set dst to be the bitwise inclusive-OR of src1 and src2, all
 *	bitmaps allocated to have nbits bits.  Yes, this modifies bits
 *	past nbits.  Any pair of {dst, src1, src2} may be aliases.
 */
static inline void
bitmap_or(unsigned long *dst, const unsigned long *src1,
    const unsigned long *src2, size_t nbits)
{
	const size_t bpl = NBBY * sizeof(unsigned long);
	size_t n = howmany(nbits, bpl);

	while (n --> 0)
		*dst++ = *src1++ | *src2++;
}

#endif  /* _LINUX_BITMAP_H_ */