#ifndef UTILS2_HPP
#define UTILS2_HPP
#include "sanity.hpp"
#include <algorithm>
#include <functional>
#include <iterator>
#include <memory>
#include <type_traits>
#ifdef __clang__
# define FALLTHROUGH [[clang::fallthrough]]
#else
# define FALLTHROUGH /* fallthrough */
#endif
template<class T, class E, E max>
struct earray
{
// no ctor/dtor and one public member variable for easy initialization
T _data[size_t(max)];
T& operator[](E v)
{
return _data[size_t(v)];
}
const T& operator[](E v) const
{
return _data[size_t(v)];
}
T *begin()
{
return _data;
}
T *end()
{
return _data + size_t(max);
}
const T *begin() const
{
return _data;
}
const T *end() const
{
return _data + size_t(max);
}
friend bool operator == (const earray& l, const earray& r)
{
return std::equal(l.begin(), l.end(), r.begin());
}
friend bool operator != (const earray& l, const earray& r)
{
return !(l == r);
}
};
template<class T, class E>
class eptr
{
T *_data;
public:
eptr(decltype(nullptr)=nullptr)
: _data(nullptr)
{}
template<E max>
eptr(earray<T, E, max>& arr)
: _data(arr._data)
{}
T& operator [](E v)
{
return _data[size_t(v)];
}
explicit operator bool()
{
return _data;
}
bool operator not()
{
return not _data;
}
};
template<class It>
class IteratorPair
{
It _b, _e;
public:
IteratorPair(It b, It e)
: _b(b), _e(e)
{}
It begin() { return _b; }
It end() { return _e; }
};
template<class It>
IteratorPair<It> iterator_pair(It b, It e)
{
return {b, e};
}
// std::underlying_type isn't supported until gcc 4.7
// this is a poor man's emulation
template<class E>
struct underlying_type
{
static_assert(std::is_enum<E>::value, "Only enums have underlying type!");
typedef typename std::conditional<
std::is_signed<E>::value,
typename std::make_signed<E>::type,
typename std::make_unsigned<E>::type
>::type type;
};
template<class E, bool=std::is_enum<E>::value>
struct remove_enum
{
typedef E type;
};
template<class E>
struct remove_enum<E, true>
{
typedef typename underlying_type<E>::type type;
};
#define ENUM_BITWISE_OPERATORS(E) \
inline \
E operator & (E l, E r) \
{ \
typedef underlying_type<E>::type U; \
return E(U(l) & U(r)); \
} \
inline \
E operator | (E l, E r) \
{ \
typedef underlying_type<E>::type U; \
return E(U(l) | U(r)); \
} \
inline \
E operator ^ (E l, E r) \
{ \
typedef underlying_type<E>::type U; \
return E(U(l) ^ U(r)); \
} \
inline \
E& operator &= (E& l, E r) \
{ \
return l = l & r; \
} \
inline \
E& operator |= (E& l, E r) \
{ \
return l = l | r; \
} \
inline \
E& operator ^= (E& l, E r) \
{ \
return l = l ^ r; \
} \
inline \
E operator ~ (E r) \
{ \
return E(-1) ^ r; \
}
template<class E>
class EnumValueIterator
{
typedef typename underlying_type<E>::type U;
E value;
public:
EnumValueIterator(E v)
: value(v)
{}
E operator *()
{
return value;
}
EnumValueIterator& operator++ ()
{
value = E(U(value) + 1);
return *this;
}
EnumValueIterator& operator-- ()
{
value = E(U(value) - 1);
return *this;
}
friend bool operator == (EnumValueIterator l, EnumValueIterator r)
{
return l.value == r.value;
}
friend bool operator != (EnumValueIterator l, EnumValueIterator r)
{
return !(l == r);
}
};
template<class E>
IteratorPair<EnumValueIterator<E>> erange(E b, E e)
{
return {b, e};
}
namespace ph = std::placeholders;
template<class A, class B>
typename std::common_type<A, B>::type min(A a, B b)
{
return a < b ? a : b;
}
template<class A, class B>
typename std::common_type<A, B>::type max(A a, B b)
{
return b < a ? a : b;
}
template<class T>
struct is_array_of_unknown_bound
: std::is_same<T, typename std::remove_extent<T>::type[]>
{};
template<class T, class D=std::default_delete<T>, class... A>
typename std::enable_if<!is_array_of_unknown_bound<T>::value, std::unique_ptr<T, D>>::type make_unique(A&&... a)
{
return std::unique_ptr<T, D>(new T(a...));
}
template<class T, class D=std::default_delete<T>>
typename std::enable_if<is_array_of_unknown_bound<T>::value, std::unique_ptr<T, D>>::type make_unique(size_t sz)
{
typedef typename std::remove_extent<T>::type E;
return std::unique_ptr<E[], D>(new E[sz]());
}
template<class T>
const T& const_(T& t)
{
return t;
}
template<class T, class U>
T no_cast(U&& u)
{
typedef typename std::remove_reference<T>::type Ti;
typedef typename std::remove_reference<U>::type Ui;
typedef typename std::remove_cv<Ti>::type Tb;
typedef typename std::remove_cv<Ui>::type Ub;
static_assert(std::is_same<Tb, Ub>::value, "not no cast");
return std::forward<U>(u);
}
template<class T, class U>
T base_cast(U&& u)
{
static_assert(std::is_reference<T>::value, "must base cast with references");
typedef typename std::remove_reference<T>::type Ti;
typedef typename std::remove_reference<U>::type Ui;
typedef typename std::remove_cv<Ti>::type Tb;
typedef typename std::remove_cv<Ui>::type Ub;
static_assert(std::is_base_of<Tb, Ub>::value, "not base cast");
return std::forward<U>(u);
}
// use this when e.g. U is an int of unknown size
template<class T, class U>
T maybe_cast(U u)
{
return u;
}
#endif // UTILS2_HPP