A lot of files were missing copyright field in the header and
the Blender Foundation contributed to them in a sense of bug
fixing and general maintenance.
This change makes it explicit that those files are at least
partially copyrighted by the Blender Foundation.
Note that this does not make it so the Blender Foundation is
the only holder of the copyright in those files, and developers
who do not have a signed contract with the foundation still
hold the copyright as well.
Another aspect of this change is using SPDX format for the
header. We already used it for the license specification,
and now we state it for the copyright as well, following the
FAQ:
https://reuse.software/faq/
253 lines
6.1 KiB
C++
253 lines
6.1 KiB
C++
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#pragma once
|
|
|
|
/** \file
|
|
* \ingroup bli
|
|
*
|
|
* This file provides the basis for processing "indexed bits" (i.e. every bit has an index).
|
|
* The main purpose of this file is to define how bits are indexed within a memory buffer.
|
|
* For example, one has to define whether the first bit is the least or most significant bit and
|
|
* how endianness affect the bit order.
|
|
*
|
|
* The order is defined as follows:
|
|
* - Every indexed bit is part of an #BitInt. These ints are ordered by their address as usual.
|
|
* - Within each #BitInt, the bits are ordered from least to most significant.
|
|
*/
|
|
|
|
#include "BLI_index_range.hh"
|
|
#include "BLI_utildefines.h"
|
|
|
|
#include <ostream>
|
|
|
|
namespace blender::bits {
|
|
|
|
/** Using a large integer type is better because then it's easier to process many bits at once. */
|
|
using BitInt = uint64_t;
|
|
/** Number of bits that fit into #BitInt. */
|
|
static constexpr int64_t BitsPerInt = int64_t(sizeof(BitInt) * 8);
|
|
/** Shift amount to get from a bit index to an int index. Equivalent to `log(BitsPerInt, 2)`. */
|
|
static constexpr int64_t BitToIntIndexShift = 3 + (sizeof(BitInt) >= 2) + (sizeof(BitInt) >= 4) +
|
|
(sizeof(BitInt) >= 8);
|
|
/** Bit mask containing a 1 for the last few bits that index a bit inside of an #BitInt. */
|
|
static constexpr BitInt BitIndexMask = (BitInt(1) << BitToIntIndexShift) - 1;
|
|
|
|
inline BitInt mask_first_n_bits(const int64_t n)
|
|
{
|
|
BLI_assert(n >= 0);
|
|
BLI_assert(n <= BitsPerInt);
|
|
if (n == BitsPerInt) {
|
|
return BitInt(-1);
|
|
}
|
|
return (BitInt(1) << n) - 1;
|
|
}
|
|
|
|
inline BitInt mask_last_n_bits(const int64_t n)
|
|
{
|
|
return ~mask_first_n_bits(BitsPerInt - n);
|
|
}
|
|
|
|
inline BitInt mask_range_bits(const int64_t start, const int64_t size)
|
|
{
|
|
BLI_assert(start >= 0);
|
|
BLI_assert(size >= 0);
|
|
const int64_t end = start + size;
|
|
BLI_assert(end <= BitsPerInt);
|
|
if (end == BitsPerInt) {
|
|
return mask_last_n_bits(size);
|
|
}
|
|
return ((BitInt(1) << end) - 1) & ~((BitInt(1) << start) - 1);
|
|
}
|
|
|
|
inline BitInt mask_single_bit(const int64_t bit_index)
|
|
{
|
|
BLI_assert(bit_index >= 0);
|
|
BLI_assert(bit_index < BitsPerInt);
|
|
return BitInt(1) << bit_index;
|
|
}
|
|
|
|
inline BitInt *int_containing_bit(BitInt *data, const int64_t bit_index)
|
|
{
|
|
return data + (bit_index >> BitToIntIndexShift);
|
|
}
|
|
|
|
inline const BitInt *int_containing_bit(const BitInt *data, const int64_t bit_index)
|
|
{
|
|
return data + (bit_index >> BitToIntIndexShift);
|
|
}
|
|
|
|
/**
|
|
* This is a read-only pointer to a specific bit. The value of the bit can be retrieved, but
|
|
* not changed.
|
|
*/
|
|
class BitRef {
|
|
private:
|
|
/** Points to the exact integer that the bit is in. */
|
|
const BitInt *int_;
|
|
/** All zeros except for a single one at the bit that is referenced. */
|
|
BitInt mask_;
|
|
|
|
friend class MutableBitRef;
|
|
|
|
public:
|
|
BitRef() = default;
|
|
|
|
/**
|
|
* Reference a specific bit in an array. Note that #data does *not* have to point to the
|
|
* exact integer the bit is in.
|
|
*/
|
|
BitRef(const BitInt *data, const int64_t bit_index)
|
|
{
|
|
int_ = int_containing_bit(data, bit_index);
|
|
mask_ = mask_single_bit(bit_index & BitIndexMask);
|
|
}
|
|
|
|
/**
|
|
* Return true when the bit is currently 1 and false otherwise.
|
|
*/
|
|
bool test() const
|
|
{
|
|
const BitInt value = *int_;
|
|
const BitInt masked_value = value & mask_;
|
|
return masked_value != 0;
|
|
}
|
|
|
|
operator bool() const
|
|
{
|
|
return this->test();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Similar to #BitRef, but also allows changing the referenced bit.
|
|
*/
|
|
class MutableBitRef {
|
|
private:
|
|
/** Points to the integer that the bit is in. */
|
|
BitInt *int_;
|
|
/** All zeros except for a single one at the bit that is referenced. */
|
|
BitInt mask_;
|
|
|
|
public:
|
|
MutableBitRef() = default;
|
|
|
|
/**
|
|
* Reference a specific bit in an array. Note that #data does *not* have to point to the
|
|
* exact int the bit is in.
|
|
*/
|
|
MutableBitRef(BitInt *data, const int64_t bit_index)
|
|
{
|
|
int_ = int_containing_bit(data, bit_index);
|
|
mask_ = mask_single_bit(bit_index & BitIndexMask);
|
|
}
|
|
|
|
/**
|
|
* Support implicitly casting to a read-only #BitRef.
|
|
*/
|
|
operator BitRef() const
|
|
{
|
|
BitRef bit_ref;
|
|
bit_ref.int_ = int_;
|
|
bit_ref.mask_ = mask_;
|
|
return bit_ref;
|
|
}
|
|
|
|
/**
|
|
* Return true when the bit is currently 1 and false otherwise.
|
|
*/
|
|
bool test() const
|
|
{
|
|
const BitInt value = *int_;
|
|
const BitInt masked_value = value & mask_;
|
|
return masked_value != 0;
|
|
}
|
|
|
|
operator bool() const
|
|
{
|
|
return this->test();
|
|
}
|
|
|
|
/**
|
|
* Change the bit to a 1.
|
|
*/
|
|
void set()
|
|
{
|
|
*int_ |= mask_;
|
|
}
|
|
|
|
/**
|
|
* Change the bit to a 0.
|
|
*/
|
|
void reset()
|
|
{
|
|
*int_ &= ~mask_;
|
|
}
|
|
|
|
/**
|
|
* Change the bit to a 1 if #value is true and 0 otherwise. If the value is highly unpredictable
|
|
* by the CPU branch predictor, it can be faster to use #set_branchless instead.
|
|
*/
|
|
void set(const bool value)
|
|
{
|
|
if (value) {
|
|
this->set();
|
|
}
|
|
else {
|
|
this->reset();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Does the same as #set, but does not use a branch. This is faster when the input value is
|
|
* unpredictable for the CPU branch predictor (best case for this function is a uniform random
|
|
* distribution with 50% probability for true and false). If the value is predictable, this is
|
|
* likely slower than #set.
|
|
*/
|
|
void set_branchless(const bool value)
|
|
{
|
|
const BitInt value_int = BitInt(value);
|
|
BLI_assert(ELEM(value_int, 0, 1));
|
|
const BitInt old = *int_;
|
|
*int_ =
|
|
/* Unset bit. */
|
|
(~mask_ & old)
|
|
/* Optionally set it again. The -1 turns a 1 into `0x00...` and a 0 into `0xff...`. */
|
|
| (mask_ & ~(value_int - 1));
|
|
}
|
|
|
|
MutableBitRef &operator|=(const bool value)
|
|
{
|
|
if (value) {
|
|
this->set();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
MutableBitRef &operator&=(const bool value)
|
|
{
|
|
if (!value) {
|
|
this->reset();
|
|
}
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
inline std::ostream &operator<<(std::ostream &stream, const BitRef &bit)
|
|
{
|
|
return stream << (bit ? "1" : "0");
|
|
}
|
|
|
|
inline std::ostream &operator<<(std::ostream &stream, const MutableBitRef &bit)
|
|
{
|
|
return stream << BitRef(bit);
|
|
}
|
|
|
|
} // namespace blender::bits
|
|
|
|
namespace blender {
|
|
using bits::BitRef;
|
|
using bits::MutableBitRef;
|
|
} // namespace blender
|