Files
moslab-code/src/l4/pkg/l4re-core/cxx/lib/tl/include/bitmap
2025-09-12 15:55:45 +02:00

371 lines
8.3 KiB
C++

// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* (c) 2008-2014 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
namespace cxx {
/**
* Basic bitmap abstraction.
*
* This abstraction keeps a pointer to a memory area that is used as bitmap.
*/
class Bitmap_base
{
protected:
/**
* Data type for each element of the bit buffer.
*/
typedef unsigned long word_type;
enum
{
W_bits = sizeof(word_type) * 8, ///< number of bits in word_type
C_bits = 8, ///< number of bits in char
};
/**
* Pointer to the buffer storing the bits.
*/
word_type *_bits;
/**
* Get the word index for the given bit.
*
* \param bit The index of the bit in question.
*
* \return the index in Bitmap_base::_bits for the given bit (bit / W_bits).
*/
static unsigned word_index(unsigned bit) { return bit / W_bits; }
/**
* Get the bit index within word_type for the given bit.
*
* \param bit The bit index in the bitmap.
*
* \return the bit index within word_type (bit % W_bits).
*/
static unsigned bit_index(unsigned bit) { return bit % W_bits; }
/**
* A writable bit in a bitmap.
*/
class Bit
{
Bitmap_base *_bm;
long _bit;
public:
Bit(Bitmap_base *bm, long bit) : _bm(bm), _bit(bit) {}
Bit &operator = (bool val) { _bm->bit(_bit, val); return *this; }
operator bool () const { return _bm->bit(_bit); }
};
public:
explicit Bitmap_base(void *bits) noexcept : _bits(reinterpret_cast<word_type *>(bits)) {}
/** Get the number of `Words` that are used for the bitmap. */
static long words(long bits) noexcept { return (bits + W_bits -1) / W_bits; }
static long bit_buffer_bytes(long bits) noexcept
{ return words(bits) * W_bits / 8; }
/** Helper abstraction for a word contained in the bitmap. */
template< long BITS >
class Word
{
public:
typedef unsigned long Type;
enum
{
Size = (BITS + W_bits - 1) / W_bits
};
};
/** Get the number of chars that are used for the bitmap. */
static long chars(long bits) noexcept
{ return (bits + C_bits -1) / C_bits; }
/** Helper abstraction for a byte contained in the bitmap. */
template< long BITS >
class Char
{
public:
typedef unsigned char Type;
enum
{
Size = (BITS + C_bits - 1) / C_bits
};
};
/**
* Set the value of bit `bit` to `on`.
*
* \param bit The number of the bit.
* \param on The boolean value that shall be assigned to the bit.
*/
void bit(long bit, bool on) noexcept;
/**
* Clear bit `bit`.
*
* \param bit The number of the bit to clear.
*/
void clear_bit(long bit) noexcept;
/**
* Clear bit `bit` atomically.
*
* Use this function for multi-threaded access to the bitmap.
*
* \param bit The number of the bit to clear.
*/
void atomic_clear_bit(long bit) noexcept;
/**
* Clear bit `bit` atomically and return old state.
*
* Use this function for multi-threaded access to the bitmap.
*
* \param bit The number of the bit to clear.
*/
word_type atomic_get_and_clear(long bit) noexcept;
/**
* Set bit `bit`.
*
* \param bit The number of the bit to set.
*/
void set_bit(long bit) noexcept;
/**
* Set bit `bit` atomically.
*
* Use this function for multi-threaded access to the bitmap.
*
* \param bit The number of the bit to set.
*/
void atomic_set_bit(long bit) noexcept;
/**
* Set bit `bit` atomically and return old state.
*
* Use this function for multi-threaded access to the bitmap.
*
* \param bit The number of the bit to set.
*/
word_type atomic_get_and_set(long bit) noexcept;
/**
* Get the truth value of a bit.
*
* \param bit The number of the bit to read.
*
* \retval 0 Bit is not set.
* \retval != 0 Bit is set.
*/
word_type bit(long bit) const noexcept;
/**
* Get the bit at index `bit`.
*
* \param bit The number of the bit to read.
*
* \retval 0 Bit is not set.
* \retval != 0 Bit is set.
*/
word_type operator [] (long bit) const noexcept
{ return this->bit(bit); }
/**
* Get the lvalue for the bit at index `bit`.
*
* \param bit The number.
*
* \return lvalue for `bit`
*/
Bit operator [] (long bit) noexcept
{ return Bit(this, bit); }
/**
* Scan for the first zero bit.
*
* \param max_bit Upper bound (exclusive) for the scanning operation.
* \param start_bit Hint at the number of the first bit to look at.
* Zero bits below `start_bit` may or may not be
* taken into account by the implementation.
*
* \retval >= 0 Number of first zero bit found.
* \retval -1 All bits between `start_bit` and `max_bit` are set.
*/
long scan_zero(long max_bit, long start_bit = 0) const noexcept;
void *bit_buffer() const noexcept { return _bits; }
protected:
static int _bzl(unsigned long w) noexcept;
};
/**
* A static bitmap.
*
* \tparam BITS The number of bits that shall be in the bitmap.
*/
template<int BITS>
class Bitmap : public Bitmap_base
{
private:
char _bits[Bitmap_base::Char<BITS>::Size];
public:
/** Create a bitmap with `BITS` bits. */
Bitmap() noexcept : Bitmap_base(_bits) {}
Bitmap(Bitmap<BITS> const &o) noexcept : Bitmap_base(_bits)
{ __builtin_memcpy(_bits, o._bits, sizeof(_bits)); }
/**
* Scan for the first zero bit.
*
* \param start_bit Hint at the number of the first bit to look at.
* Zero bits below `start_bit` may or may not be
* taken into account by the implementation.
*
* \retval >= 0 Number of first zero bit found.
* \retval -1 All bits at `start_bit` or higher are set.
*
* Compared to Bitmap_base::scan_zero(), the upper bound is set to BITS.
*/
long scan_zero(long start_bit = 0) const noexcept;
void clear_all()
{ __builtin_memset(_bits, 0, sizeof(_bits)); }
};
inline
void
Bitmap_base::bit(long bit, bool on) noexcept
{
long idx = word_index(bit);
long b = bit_index(bit);
_bits[idx] = (_bits[idx] & ~(1UL << b)) | (static_cast<unsigned long>(on) << b);
}
inline
void
Bitmap_base::clear_bit(long bit) noexcept
{
long idx = word_index(bit);
long b = bit_index(bit);
_bits[idx] &= ~(1UL << b);
}
inline
void
Bitmap_base::atomic_clear_bit(long bit) noexcept
{
long idx = word_index(bit);
long b = bit_index(bit);
word_type mask = 1UL << b;
__atomic_and_fetch(&_bits[idx], ~mask, __ATOMIC_RELAXED);
}
inline
Bitmap_base::word_type
Bitmap_base::atomic_get_and_clear(long bit) noexcept
{
long idx = word_index(bit);
long b = bit_index(bit);
word_type mask = 1UL << b;
return __atomic_fetch_and(&_bits[idx], ~mask, __ATOMIC_RELAXED) & mask;
}
inline
void
Bitmap_base::set_bit(long bit) noexcept
{
long idx = word_index(bit);
long b = bit_index(bit);
_bits[idx] |= (1UL << b);
}
inline
void
Bitmap_base::atomic_set_bit(long bit) noexcept
{
long idx = word_index(bit);
long b = bit_index(bit);
word_type mask = 1UL << b;
__atomic_or_fetch(&_bits[idx], mask, __ATOMIC_RELAXED);
}
inline
Bitmap_base::word_type
Bitmap_base::atomic_get_and_set(long bit) noexcept
{
long idx = word_index(bit);
long b = bit_index(bit);
word_type mask = 1UL << b;
return __atomic_fetch_or(&_bits[idx], mask, __ATOMIC_RELAXED) & mask;
}
inline
Bitmap_base::word_type
Bitmap_base::bit(long bit) const noexcept
{
long idx = word_index(bit);
long b = bit_index(bit);
return _bits[idx] & (1UL << b);
}
inline
int
Bitmap_base::_bzl(unsigned long w) noexcept
{
for (int i = 0; i < W_bits; ++i, w >>= 1)
{
if ((w & 1) == 0)
return i;
}
return -1;
}
inline
long
Bitmap_base::scan_zero(long max_bit, long start_bit) const noexcept
{
if (!(operator [] (start_bit)))
return start_bit;
long idx = word_index(start_bit);
max_bit -= start_bit & ~(W_bits - 1);
for (; max_bit > 0; max_bit -= W_bits, ++idx)
{
if (_bits[idx] == 0)
return idx * W_bits;
if (_bits[idx] != ~0UL)
{
long zbit = _bzl(_bits[idx]);
return zbit < max_bit ? idx * W_bits + zbit : -1;
}
}
return -1;
}
template<int BITS> inline
long
Bitmap<BITS>::scan_zero(long start_bit) const noexcept
{
return Bitmap_base::scan_zero(BITS, start_bit);
}
};