371 lines
8.3 KiB
C++
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);
|
|
}
|
|
|
|
};
|