Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #pragma once
- #include <cstdint>
- #include <type_traits>
- #include <utility>
- namespace {
- template <bool Signed>
- using minint = std::conditional_t<Signed, int8_t, uint8_t>;
- template <bool Signed>
- using maxint = std::conditional_t<Signed, intmax_t, uintmax_t>;
- template <class T, class U>
- constexpr T combine() noexcept {
- return 0;
- }
- template <class T, class U>
- constexpr T combine(U x) noexcept {
- return x & static_cast<U>(~0);
- }
- template <class T, class U, class... Arg>
- constexpr T combine(U x, Arg... args) noexcept {
- return (combine<T, U>(x) << (sizeof...(args) * sizeof(U) * 8))
- | combine<T, U>(args...);
- }
- } // namespace
- template <std::size_t N, bool Signed = false>
- class ChainInt {
- using elem_type = minint<Signed>;
- using max_type = maxint<Signed>;
- static_assert(N > 0, "Cannot chain void integer");
- static_assert(N <= sizeof(max_type), "Chained integer too large");
- elem_type *data_[N];
- max_type x_;
- public:
- template <class... Arg>
- constexpr ChainInt(Arg&... args) noexcept :
- data_ {&args...}, x_(combine<max_type, elem_type>(args...)) { }
- ~ChainInt() noexcept = default;
- constexpr operator max_type() const noexcept {
- return x_;
- }
- constexpr elem_type &operator[](std::size_t n) noexcept {
- return *data_[n];
- }
- constexpr const elem_type &operator[](std::size_t n) const noexcept {
- return *data_[n];
- }
- constexpr ChainInt &operator=(const ChainInt &other) noexcept {
- return operator=(static_cast<const max_type&>(other));
- }
- #define ASSIGN(FN) \
- ChainInt &operator FN(const max_type &other) noexcept { \
- x_ FN other; update(); return *this; }
- ASSIGN(=)
- ASSIGN(+=)
- ASSIGN(-=)
- ASSIGN(*=)
- ASSIGN(/=)
- ASSIGN(%=)
- ASSIGN(<<=)
- ASSIGN(>>=)
- ASSIGN(&=)
- ASSIGN(|=)
- ASSIGN(^=)
- #undef ASSIGN
- #define UNARY(FN) \
- ChainInt &operator FN() noexcept { FN x_; update(); return *this; } \
- max_type operator FN(int) noexcept { auto v = x_; operator FN(); return v; }
- UNARY(++)
- UNARY(--)
- #undef UNARY
- private:
- constexpr void update() noexcept {
- x_ &= static_cast<max_type>(-1) >> (8 * (8 - N));
- auto v = x_;
- for (std::size_t i = 0; i < N; ++i) {
- *data_[N - i - 1] = v;
- v >>= sizeof(elem_type) * 8;
- }
- }
- };
- namespace {
- template <class... Arg> struct all_lv_refs;
- template <class T> struct all_lv_refs<T> :
- std::is_lvalue_reference<T> { };
- template <class T, class... Arg> struct all_lv_refs<T, Arg...> :
- std::conditional_t<!std::is_lvalue_reference<T>::value,
- std::false_type, all_lv_refs<Arg...>> { };
- template <bool B, class T, class... Arg> struct chain_impl;
- template <class T, class... Arg>
- struct chain_impl<false, T, Arg...> {
- constexpr auto operator()(T x, Arg... args) noexcept {
- using T2 = std::decay_t<T>;
- return combine<maxint<std::is_signed<T>::value>, T2>(
- x, static_cast<T2>(args)...);
- }
- };
- template <class T, class... Arg>
- struct chain_impl<true, T, Arg...> {
- constexpr auto operator()(T x, Arg... args) noexcept {
- return ChainInt<1 + sizeof...(Arg), std::is_signed<T>::value>(
- x, args...);
- }
- };
- } // namespace
- template <class T, class... Arg>
- constexpr auto chain(T &&x, Arg&&... args) noexcept {
- return chain_impl<all_lv_refs<T, Arg...>::value, T, Arg...>()(x, args...);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement