llvm/llvm/include/llvm/ADT/Bitfields.h

//===-- llvm/ADT/Bitfield.h - Get and Set bits in an integer ---*- C++ -*--===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file implements methods to test, set and extract typed bits from packed
/// unsigned integers.
///
/// Why not C++ bitfields?
/// ----------------------
/// C++ bitfields do not offer control over the bit layout nor consistent
/// behavior when it comes to out of range values.
/// For instance, the layout is implementation defined and adjacent bits may be
/// packed together but are not required to. This is problematic when storage is
/// sparse and data must be stored in a particular integer type.
///
/// The methods provided in this file ensure precise control over the
/// layout/storage as well as protection against out of range values.
///
/// Usage example
/// -------------
/// \code{.cpp}
///  uint8_t Storage = 0;
///
///  // Store and retrieve a single bit as bool.
///  using Bool = Bitfield::Element<bool, 0, 1>;
///  Bitfield::set<Bool>(Storage, true);
///  EXPECT_EQ(Storage, 0b00000001);
///  //                          ^
///  EXPECT_EQ(Bitfield::get<Bool>(Storage), true);
///
///  // Store and retrieve a 2 bit typed enum.
///  // Note: enum underlying type must be unsigned.
///  enum class SuitEnum : uint8_t { CLUBS, DIAMONDS, HEARTS, SPADES };
///  // Note: enum maximum value needs to be passed in as last parameter.
///  using Suit = Bitfield::Element<SuitEnum, 1, 2, SuitEnum::SPADES>;
///  Bitfield::set<Suit>(Storage, SuitEnum::HEARTS);
///  EXPECT_EQ(Storage, 0b00000101);
///  //                        ^^
///  EXPECT_EQ(Bitfield::get<Suit>(Storage), SuitEnum::HEARTS);
///
///  // Store and retrieve a 5 bit value as unsigned.
///  using Value = Bitfield::Element<unsigned, 3, 5>;
///  Bitfield::set<Value>(Storage, 10);
///  EXPECT_EQ(Storage, 0b01010101);
///  //                   ^^^^^
///  EXPECT_EQ(Bitfield::get<Value>(Storage), 10U);
///
///  // Interpret the same 5 bit value as signed.
///  using SignedValue = Bitfield::Element<int, 3, 5>;
///  Bitfield::set<SignedValue>(Storage, -2);
///  EXPECT_EQ(Storage, 0b11110101);
///  //                   ^^^^^
///  EXPECT_EQ(Bitfield::get<SignedValue>(Storage), -2);
///
///  // Ability to efficiently test if a field is non zero.
///  EXPECT_TRUE(Bitfield::test<Value>(Storage));
///
///  // Alter Storage changes value.
///  Storage = 0;
///  EXPECT_EQ(Bitfield::get<Bool>(Storage), false);
///  EXPECT_EQ(Bitfield::get<Suit>(Storage), SuitEnum::CLUBS);
///  EXPECT_EQ(Bitfield::get<Value>(Storage), 0U);
///  EXPECT_EQ(Bitfield::get<SignedValue>(Storage), 0);
///
///  Storage = 255;
///  EXPECT_EQ(Bitfield::get<Bool>(Storage), true);
///  EXPECT_EQ(Bitfield::get<Suit>(Storage), SuitEnum::SPADES);
///  EXPECT_EQ(Bitfield::get<Value>(Storage), 31U);
///  EXPECT_EQ(Bitfield::get<SignedValue>(Storage), -1);
/// \endcode
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_ADT_BITFIELDS_H
#define LLVM_ADT_BITFIELDS_H

#include <cassert>
#include <climits> // CHAR_BIT
#include <cstddef> // size_t
#include <cstdint> // uintXX_t
#include <limits>  // numeric_limits
#include <type_traits>

namespace llvm {

namespace bitfields_details {

/// A struct defining useful bit patterns for n-bits integer types.
template <typename T, unsigned Bits> struct BitPatterns {};

/// `Compressor` is used to manipulate the bits of a (possibly signed) integer
/// type so it can be packed and unpacked into a `bits` sized integer,
/// `Compressor` is specialized on signed-ness so no runtime cost is incurred.
/// The `pack` method also checks that the passed in `UserValue` is valid.
template <typename T, unsigned Bits, bool = std::is_unsigned<T>::value>
struct Compressor {};

Compressor<T, Bits, false>;

/// Impl is where Bifield description and Storage are put together to interact
/// with values.
template <typename Bitfield, typename StorageType> struct Impl {};

/// `Bitfield` deals with the following type:
/// - unsigned enums
/// - signed and unsigned integer
/// - `bool`
/// Internally though we only manipulate integer with well defined and
/// consistent semantics, this excludes typed enums and `bool` that are replaced
/// with their unsigned counterparts. The correct type is restored in the public
/// API.
template <typename T, bool = std::is_enum<T>::value>
struct ResolveUnderlyingType {};
ResolveUnderlyingType<T, false>;
template <> struct ResolveUnderlyingType<bool, false> {};

} // namespace bitfields_details

/// Holds functions to get, set or test bitfields.
struct Bitfield {};

} // namespace llvm

#endif // LLVM_ADT_BITFIELDS_H