#ifndef LLVM_ADT_SEQUENCE_H
#define LLVM_ADT_SEQUENCE_H
#include <cassert>
#include <iterator>
#include <limits>
#include <type_traits>
#include "llvm/Support/MathExtras.h"
namespace llvm {
template <typename EnumT> struct enum_iteration_traits {
static constexpr bool is_iterable = false;
};
struct force_iteration_on_noniterable_enum_t {
explicit force_iteration_on_noniterable_enum_t() = default;
};
constexpr force_iteration_on_noniterable_enum_t
force_iteration_on_noniterable_enum;
namespace detail {
template <typename T, typename U> bool canTypeFitValue(const U Value) {
const intmax_t BotT = intmax_t(std::numeric_limits<T>::min());
const intmax_t BotU = intmax_t(std::numeric_limits<U>::min());
const uintmax_t TopT = uintmax_t(std::numeric_limits<T>::max());
const uintmax_t TopU = uintmax_t(std::numeric_limits<U>::max());
return !((BotT > BotU && Value < static_cast<U>(BotT)) ||
(TopT < TopU && Value > static_cast<U>(TopT)));
}
struct CheckedInt {
template <typename Integral, typename std::enable_if_t<
std::is_integral<Integral>::value, bool> = 0>
static CheckedInt from(Integral FromValue) {
if (!canTypeFitValue<intmax_t>(FromValue))
assertOutOfBounds();
CheckedInt Result;
Result.Value = static_cast<intmax_t>(FromValue);
return Result;
}
template <typename Enum,
typename std::enable_if_t<std::is_enum<Enum>::value, bool> = 0>
static CheckedInt from(Enum FromValue) {
using type = typename std::underlying_type<Enum>::type;
return from<type>(static_cast<type>(FromValue));
}
bool operator==(const CheckedInt &O) const { return Value == O.Value; }
bool operator!=(const CheckedInt &O) const { return Value != O.Value; }
CheckedInt operator+(intmax_t Offset) const {
CheckedInt Result;
if (AddOverflow(Value, Offset, Result.Value))
assertOutOfBounds();
return Result;
}
intmax_t operator-(CheckedInt Other) const {
intmax_t Result;
if (SubOverflow(Value, Other.Value, Result))
assertOutOfBounds();
return Result;
}
template <typename Integral, typename std::enable_if_t<
std::is_integral<Integral>::value, bool> = 0>
Integral to() const {
if (!canTypeFitValue<Integral>(Value))
assertOutOfBounds();
return static_cast<Integral>(Value);
}
template <typename Enum,
typename std::enable_if_t<std::is_enum<Enum>::value, bool> = 0>
Enum to() const {
using type = typename std::underlying_type<Enum>::type;
return Enum(to<type>());
}
private:
static void assertOutOfBounds() { assert(false && "Out of bounds"); }
intmax_t Value;
};
template <typename T, bool IsReverse> struct SafeIntIterator {
using iterator_category = std::random_access_iterator_tag;
using value_type = T;
using difference_type = intmax_t;
using pointer = T *;
using reference = T &;
explicit SafeIntIterator(T Value) : SI(CheckedInt::from<T>(Value)) {}
SafeIntIterator(const SafeIntIterator<T, !IsReverse> &O) : SI(O.SI) {}
value_type operator*() const { return SI.to<T>(); }
value_type operator[](intmax_t Offset) const { return *(*this + Offset); }
bool operator==(const SafeIntIterator &O) const { return SI == O.SI; }
bool operator!=(const SafeIntIterator &O) const { return SI != O.SI; }
bool operator<(const SafeIntIterator &O) const { return (*this - O) < 0; }
bool operator>(const SafeIntIterator &O) const { return (*this - O) > 0; }
bool operator<=(const SafeIntIterator &O) const { return (*this - O) <= 0; }
bool operator>=(const SafeIntIterator &O) const { return (*this - O) >= 0; }
void operator++() { offset(1); }
void operator--() { offset(-1); }
SafeIntIterator operator++(int) {
const auto Copy = *this;
++*this;
return Copy;
}
SafeIntIterator operator--(int) {
const auto Copy = *this;
--*this;
return Copy;
}
void operator+=(intmax_t Offset) { offset(Offset); }
void operator-=(intmax_t Offset) { offset(-Offset); }
SafeIntIterator operator+(intmax_t Offset) const { return add(Offset); }
SafeIntIterator operator-(intmax_t Offset) const { return add(-Offset); }
intmax_t operator-(const SafeIntIterator &O) const {
return IsReverse ? O.SI - SI : SI - O.SI;
}
private:
SafeIntIterator(const CheckedInt &SI) : SI(SI) {}
static intmax_t getOffset(intmax_t Offset) {
return IsReverse ? -Offset : Offset;
}
CheckedInt add(intmax_t Offset) const { return SI + getOffset(Offset); }
void offset(intmax_t Offset) { SI = SI + getOffset(Offset); }
CheckedInt SI;
template <typename, bool> friend struct SafeIntIterator;
};
}
template <typename T> struct iota_range {
using value_type = T;
using reference = T &;
using const_reference = const T &;
using iterator = detail::SafeIntIterator<value_type, false>;
using const_iterator = iterator;
using reverse_iterator = detail::SafeIntIterator<value_type, true>;
using const_reverse_iterator = reverse_iterator;
using difference_type = intmax_t;
using size_type = std::size_t;
explicit iota_range(T Begin, T End, bool Inclusive)
: BeginValue(Begin), PastEndValue(End) {
assert(Begin <= End && "Begin must be less or equal to End.");
if (Inclusive)
++PastEndValue;
}
size_t size() const { return PastEndValue - BeginValue; }
bool empty() const { return BeginValue == PastEndValue; }
auto begin() const { return const_iterator(BeginValue); }
auto end() const { return const_iterator(PastEndValue); }
auto rbegin() const { return const_reverse_iterator(PastEndValue - 1); }
auto rend() const { return const_reverse_iterator(BeginValue - 1); }
private:
static_assert(std::is_integral<T>::value || std::is_enum<T>::value,
"T must be an integral or enum type");
static_assert(std::is_same<T, std::remove_cv_t<T>>::value,
"T must not be const nor volatile");
iterator BeginValue;
iterator PastEndValue;
};
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value &&
!std::is_enum<T>::value>>
auto seq(T Begin, T End) {
return iota_range<T>(Begin, End, false);
}
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value &&
!std::is_enum<T>::value>>
auto seq_inclusive(T Begin, T End) {
return iota_range<T>(Begin, End, true);
}
template <typename EnumT,
typename = std::enable_if_t<std::is_enum<EnumT>::value>>
auto enum_seq(EnumT Begin, EnumT End) {
static_assert(enum_iteration_traits<EnumT>::is_iterable,
"Enum type is not marked as iterable.");
return iota_range<EnumT>(Begin, End, false);
}
template <typename EnumT,
typename = std::enable_if_t<std::is_enum<EnumT>::value>>
auto enum_seq(EnumT Begin, EnumT End, force_iteration_on_noniterable_enum_t) {
return iota_range<EnumT>(Begin, End, false);
}
template <typename EnumT,
typename = std::enable_if_t<std::is_enum<EnumT>::value>>
auto enum_seq_inclusive(EnumT Begin, EnumT End) {
static_assert(enum_iteration_traits<EnumT>::is_iterable,
"Enum type is not marked as iterable.");
return iota_range<EnumT>(Begin, End, true);
}
template <typename EnumT,
typename = std::enable_if_t<std::is_enum<EnumT>::value>>
auto enum_seq_inclusive(EnumT Begin, EnumT End,
force_iteration_on_noniterable_enum_t) {
return iota_range<EnumT>(Begin, End, true);
}
}
#endif