llvm-mirror/include/llvm/ADT/PointerEmbeddedInt.h
Chandler Carruth ae65e281f3 Update the file headers across all of the LLVM projects in the monorepo
to reflect the new license.

We understand that people may be surprised that we're moving the header
entirely to discuss the new license. We checked this carefully with the
Foundation's lawyer and we believe this is the correct approach.

Essentially, all code in the project is now made available by the LLVM
project under our new license, so you will see that the license headers
include that license only. Some of our contributors have contributed
code under our old license, and accordingly, we have retained a copy of
our old license notice in the top-level files in each project and
repository.

llvm-svn: 351636
2019-01-19 08:50:56 +00:00

120 lines
4.0 KiB
C++

//===- llvm/ADT/PointerEmbeddedInt.h ----------------------------*- 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
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_POINTEREMBEDDEDINT_H
#define LLVM_ADT_POINTEREMBEDDEDINT_H
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
#include <cassert>
#include <climits>
#include <cstdint>
#include <type_traits>
namespace llvm {
/// Utility to embed an integer into a pointer-like type. This is specifically
/// intended to allow embedding integers where fewer bits are required than
/// exist in a pointer, and the integer can participate in abstractions along
/// side other pointer-like types. For example it can be placed into a \c
/// PointerSumType or \c PointerUnion.
///
/// Note that much like pointers, an integer value of zero has special utility
/// due to boolean conversions. For example, a non-null value can be tested for
/// in the above abstractions without testing the particular active member.
/// Also, the default constructed value zero initializes the integer.
template <typename IntT, int Bits = sizeof(IntT) * CHAR_BIT>
class PointerEmbeddedInt {
uintptr_t Value = 0;
// Note: This '<' is correct; using '<=' would result in some shifts
// overflowing their storage types.
static_assert(Bits < sizeof(uintptr_t) * CHAR_BIT,
"Cannot embed more bits than we have in a pointer!");
enum : uintptr_t {
// We shift as many zeros into the value as we can while preserving the
// number of bits desired for the integer.
Shift = sizeof(uintptr_t) * CHAR_BIT - Bits,
// We also want to be able to mask out the preserved bits for asserts.
Mask = static_cast<uintptr_t>(-1) << Bits
};
struct RawValueTag {
explicit RawValueTag() = default;
};
friend struct PointerLikeTypeTraits<PointerEmbeddedInt>;
explicit PointerEmbeddedInt(uintptr_t Value, RawValueTag) : Value(Value) {}
public:
PointerEmbeddedInt() = default;
PointerEmbeddedInt(IntT I) { *this = I; }
PointerEmbeddedInt &operator=(IntT I) {
assert((std::is_signed<IntT>::value ? isInt<Bits>(I) : isUInt<Bits>(I)) &&
"Integer has bits outside those preserved!");
Value = static_cast<uintptr_t>(I) << Shift;
return *this;
}
// Note that this implicit conversion additionally allows all of the basic
// comparison operators to work transparently, etc.
operator IntT() const {
if (std::is_signed<IntT>::value)
return static_cast<IntT>(static_cast<intptr_t>(Value) >> Shift);
return static_cast<IntT>(Value >> Shift);
}
};
// Provide pointer like traits to support use with pointer unions and sum
// types.
template <typename IntT, int Bits>
struct PointerLikeTypeTraits<PointerEmbeddedInt<IntT, Bits>> {
using T = PointerEmbeddedInt<IntT, Bits>;
static inline void *getAsVoidPointer(const T &P) {
return reinterpret_cast<void *>(P.Value);
}
static inline T getFromVoidPointer(void *P) {
return T(reinterpret_cast<uintptr_t>(P), typename T::RawValueTag());
}
static inline T getFromVoidPointer(const void *P) {
return T(reinterpret_cast<uintptr_t>(P), typename T::RawValueTag());
}
enum { NumLowBitsAvailable = T::Shift };
};
// Teach DenseMap how to use PointerEmbeddedInt objects as keys if the Int type
// itself can be a key.
template <typename IntT, int Bits>
struct DenseMapInfo<PointerEmbeddedInt<IntT, Bits>> {
using T = PointerEmbeddedInt<IntT, Bits>;
using IntInfo = DenseMapInfo<IntT>;
static inline T getEmptyKey() { return IntInfo::getEmptyKey(); }
static inline T getTombstoneKey() { return IntInfo::getTombstoneKey(); }
static unsigned getHashValue(const T &Arg) {
return IntInfo::getHashValue(Arg);
}
static bool isEqual(const T &LHS, const T &RHS) { return LHS == RHS; }
};
} // end namespace llvm
#endif // LLVM_ADT_POINTEREMBEDDEDINT_H