#ifndef LLVM_ADT_FIXNUM_H
#define LLVM_ADT_FIXNUM_H
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
#include <cassert>
#include <limits>
namespace llvm {
template <unsigned Bits>
struct int_least {
static_assert(Bits <= 64, "too many bits");
using type = typename std::conditional<(Bits <= 8), int_least8_t,
typename std::conditional<(Bits <= 16), int_least16_t,
typename std::conditional<(Bits <= 32), int_least32_t,
int_least64_t>::type>::type>::type;
};
template <unsigned Bits>
struct uint_least {
using type =
typename std::make_unsigned<typename int_least<Bits>::type>::type;
};
template <unsigned Bits, typename IntType = typename uint_least<Bits>::type>
class Fixnum {
static_assert(Bits <= (std::numeric_limits<IntType>::digits +
std::numeric_limits<IntType>::is_signed),
"too many bits for integer type");
IntType Value;
void assertValid() const {
assert((std::is_signed<IntType>::value ? llvm::isInt<Bits>(Value)
: llvm::isUInt<Bits>(Value)) &&
"value exceeds limited bit width");
}
public:
using value_type = IntType;
Fixnum() : Value(0) {}
Fixnum(IntType val) : Value(val) {
assertValid();
}
template <unsigned OtherBits, typename OtherIntType>
Fixnum(
const typename std::enable_if<(OtherBits < Bits),
Fixnum<OtherBits,
OtherIntType>>::type &other)
: Value(static_cast<IntType>(other)) {}
template <unsigned OtherBits, typename OtherIntType>
explicit Fixnum(const Fixnum<OtherBits, OtherIntType> &other) {
operator=(other);
}
template <unsigned OtherBits, typename OtherIntType>
Fixnum &operator=(const Fixnum<OtherBits, OtherIntType> &other) {
Value = static_cast<IntType>(other);
assert(static_cast<OtherIntType>(Value) == other &&
"cannot represent the same value");
assert(((Value < 0) == (other < 0)) && "signedness mismatch");
assertValid();
return *this;
}
operator IntType() const {
return Value;
}
Fixnum &operator++() {
assert((Value != std::numeric_limits<IntType>::max()) &&
"increment would cause wraparound");
++Value;
assertValid();
return *this;
}
Fixnum operator++(int) {
assert((Value != std::numeric_limits<IntType>::max()) &&
"increment would cause wraparound");
Fixnum result = *this;
++Value;
assertValid();
return result;
}
Fixnum &operator--() {
assert((Value != std::numeric_limits<IntType>::min()) &&
"decrement would cause wraparound");
--Value;
assertValid();
return *this;
}
Fixnum operator--(int) {
assert((Value != std::numeric_limits<IntType>::min()) &&
"decrement would cause wraparound");
Fixnum result = *this;
--Value;
assertValid();
return result;
}
bool operator==(const Fixnum &RHS) const {
return Value == RHS.Value;
}
bool operator!=(const Fixnum &RHS) const {
return !operator==(RHS);
}
bool operator==(int RHS) const {
return Value == IntType(RHS);
}
bool operator!=(int RHS) const {
return !operator==(RHS);
}
};
template<unsigned IntBits, typename IntType>
class PointerLikeTypeTraits<Fixnum<IntBits, IntType>> {
using IntPointerType =
typename std::conditional<std::is_signed<IntType>::value,
intptr_t, uintptr_t>::type;
public:
static_assert(sizeof(IntType) <= sizeof(IntPointerType),
"Fixnum is too big to fit in a pointer");
static inline void *
getAsVoidPointer(const Fixnum<IntBits, IntType> &I) {
auto opaqueValue = static_cast<IntPointerType>(I) << NumLowBitsAvailable;
return reinterpret_cast<void *>(opaqueValue);
}
static inline Fixnum<IntBits, IntType>
getFromVoidPointer(const void *P) {
auto opaqueValue = reinterpret_cast<IntPointerType>(P);
return static_cast<IntType>(opaqueValue >> NumLowBitsAvailable);
}
enum {
NumLowBitsAvailable = std::numeric_limits<uintptr_t>::digits - IntBits
};
};
}
#endif