#include <cstddef>
#include <tuple>
#include <type_traits>
template <typename T>
struct identity { using type = T; };
template <typename T, std::size_t I>
struct indexed {};
template <std::size_t I>
using SizeT = std::integral_constant<std::size_t, I>;
template <template <typename...> class Template, typename... T>
struct lazy_apply {
using type = Template<typename T::type...>;
};
template <typename T, typename Tuple>
struct const_tuple;
template <typename Head, typename... Tail>
struct cons_tuple<Head, std::tuple<Tail...>>
: identity<std::tuple<Head, Tail...>> {};
template <typename T, typename Tuple>
using ConsTuple = typename cons_tuple<T, Tuple>::type;
template <typename T, typename U>
struct layout_first {
#ifndef _LIBCPP_VERSION
using first = T;
using second = U;
#else
using first = U;
using second = T;
#endif
constexpr static bool value = std::is_empty<first>::value
|| (!std::is_empty<second>::value && alignof(first) > alignof(second));
};
template <typename T, typename Tuple>
struct insert_sorted
: identity<std::tuple<T>> {};
template <typename T, std::size_t I, typename TFirst, typename... TSorted, std::size_t IFirst, std::size_t... ISorted>
struct insert_sorted<indexed<T, I>, std::tuple<indexed<TFirst, IFirst>, indexed<TSorted, ISorted>...>>
: std::conditional<
layout_first<T, TFirst>::value,
identity<std::tuple<indexed<T, I>, indexed<TFirst, IFirst>, indexed<TSorted, ISorted>...>>,
lazy_apply<ConsTuple, identity<indexed<TFirst, IFirst>>, insert_sorted<indexed<T, I>, std::tuple<indexed<TSorted, ISorted>...>>>
>::type {};
template <typename T, typename Tuple>
using InsertSorted = typename insert_sorted<T, Tuple>::type;
template <typename Tuple>
struct split;
template <typename... T, std::size_t... I>
struct split<std::tuple<indexed<T, I>...>> {
using types = std::tuple<T...>;
using indices = std::tuple<SizeT<I>...>;
}
template <typename T>
using ExtractTypes = typename split<T>::types;
template <typename T>
using ExtractIndices = typename split<T>::indices;
template <typename Acc, typename T>
struct perfect_layout_impl {
using tuples = ExtractTypes<Acc>;
using map = ExtractIndices<Acc>;
};
template <typename Acc, typename Head, typename... Tail>
struct perfect_layout_impl<Acc, std::tuple<Head, Tail...>>
: perfect_layout_impl<InsertSorted<Head, Acc>, std::tuple<Tail...>> {};
template <typename Acc, typename... T>
struct with_indices_impl : identity<Acc> {};
template <typename Acc, typename Head, typename... Tail>
struct with_indices_impl<std::tuple<Acc..., indexed<Head, sizeof...(Acc)>>, Tail...> {};
template <typename... T>
struct with_indices : with_indices_impl<std::tuple<>, T...> {};
template <typename... T>
using WithIndices = typename with_indices<T...>::type;
template <typename... T>
struct perfect_layout
: perfect_layout_impl<std::tuple<>, WithIndices<T...>> {};
template <typename... T>
using PerfectLayoutTuple = typename perfect_layout<T...>::tuple;
template <typename... T>
using PerfectLayoutMap = typename perfect_layout<T...>::map;
template <std::size_t I, typename T>
using TupleElement = typename std::tuple_element<I, T>::type;
template <std::size_t... Indices>
struct indices {};
template <typename T>
struct eval_indices;
template <typename... S>
struct eval_indices<std::tuple<S...>>
: identity<indices<S::value...>> {};
template <typename T>
using EvalIndices = typename eval_indices<T>::type;
template <typename... T, std::size_t... Indices>
std::tuple<TupleElement<Indices, std::tuple<T...>>...> forward_for_my_tuple(indices<Indices...>, T&&...) {
auto fwd = std::forward_as_tuple(std::forward<T>(t)...);
return std::forward_as_tuple(std::forward<TupleElement<Indices, std::tuple<T...>>>(std::get<Indices>(fwd))...);
}
template <typename... T>
struct my_tuple {
public:
my_tuple() = default;
explicit my_tuple(T const&... t)
: inner(forward_for_my_tuple(EvalIndices<PerfectLayoutMap<T...>>(), t...) {}
template <typename... U>
explicit my_tuple(U&&... u)
: inner(forward_for_my_tuple(EvalIndices<PerfectLayoutMap<T...>>(), u...) {}
template <std::size_t I, typename... T1>
friend TupleElement<I, std::tuple<T1...>>& get(my_tuple<T1...>& t) noexcept;
template <std::size_t I, typename... T1>
friend TupleElement<I, std::tuple<T1...>>&& get(my_tuple<T1...>&& t) noexcept;
template <std::size_t I, typename... T1>
friend TupleElement<I, std::tuple<T1...>> const& get(my_tuple<T1...> const& t) noexcept;
private:
PerfectLayoutTuple<T...> inner;
};
template <std::size_t I, typename... T1>
TupleElement<I, std::tuple<T1...>>& get(my_tuple<T1...>& t) noexcept {
return std::get<TupleElement<I, PerfectLayoutMap<T...>>::value>(t.inner);
}
template <std::size_t I, typename... T1>
TupleElement<I, std::tuple<T1...>>&& get(my_tuple<T1...>&& t) noexcept {
return std::get<TupleElement<I, PerfectLayoutMap<T...>>::value>(std::move(t.inner));
}
template <std::size_t I, typename... T1>
TupleElement<I, std::tuple<T1...>> const& get(my_tuple<T1...> const& t) noexcept {
return std::get<TupleElement<I, PerfectLayoutMap<T...>>::value>(t.inner);
}
/****** TESTING PART ******/
struct empty0 {};
struct empty1 {};
struct empty2 {};
template <std::size_t Size, std::size_t Align>
using Layout = typename std::aligned_storage<Size, Align>::type;
using type1 = Layout<1,1>;
using type2 = Layout<2,2>;
using type4 = Layout<4,4>;
using type8 = Layout<8,8>;
static_assert(sizeof(my_tuple<empty0, empty1, empty2, type8>) == sizeof(type8),
"Empty base class optimization should be done on prefix empties");
static_assert(sizeof(my_tuple<type8, empty0, empty1, empty2>) == sizeof(type8),
"Empty base class optimization should be done on suffix empties");
static_assert(sizeof(my_tuple<type8, empty0, empty1, empty2, type8>) == 2*sizeof(type8),
"Empty base class optimization should be done on middle empties");
static_assert(sizeof(my_tuple<empty0, empty1, empty2, type8, type4, type2, type1, type1>) == sizeof(type8) + sizeof(type4) + sizeof(type2) + 2*sizeof(type1),
"Perfect layout should not be ruined");
static_assert(sizeof(my_tuple<type1, type2, empty0, empty1, type1, type8, empty2, type4>) == sizeof(type8) + sizeof(type4) + sizeof(type2) + 2*sizeof(type1),
"Perfect layout should be arranged");
#include <cassert>
int main() {
my_tuple<int, empty0, empty1, double, empty2, int> t { 1, {}, {}, 0.5, {}, 2 };
// reordering should be invisible to the client
static_assert(std::is_same<decltype(get<0>(t)), int&>::value, "");
static_assert(std::is_same<decltype(get<1>(t)), empty0&>::value, "");
static_assert(std::is_same<decltype(get<2>(t)), empty1&>::value, "");
static_assert(std::is_same<decltype(get<3>(t)), double&>::value, "");
static_assert(std::is_same<decltype(get<4>(t)), empty2&>::value, "");
static_assert(std::is_same<decltype(get<5>(t)), int&>::value, "");
assert(get<0>(t) == 1);
assert(get<3>(t) == 0.5);
assert(get<5>(t) == 2);
get<0>(t) = { 3 };
get<3>(t) = { 2.5 };
get<5>(t) = { 5 };
assert(get<0>(t) == 3);
assert(get<3>(t) == 2.5);
assert(get<5>(t) == 4);
}
I2luY2x1ZGUgPGNzdGRkZWY+CiNpbmNsdWRlIDx0dXBsZT4KI2luY2x1ZGUgPHR5cGVfdHJhaXRzPgoKdGVtcGxhdGUgPHR5cGVuYW1lIFQ+CnN0cnVjdCBpZGVudGl0eSB7IHVzaW5nIHR5cGUgPSBUOyB9OwoKdGVtcGxhdGUgPHR5cGVuYW1lIFQsIHN0ZDo6c2l6ZV90IEk+CnN0cnVjdCBpbmRleGVkIHt9OwoKdGVtcGxhdGUgPHN0ZDo6c2l6ZV90IEk+CnVzaW5nIFNpemVUID0gc3RkOjppbnRlZ3JhbF9jb25zdGFudDxzdGQ6OnNpemVfdCwgST47Cgp0ZW1wbGF0ZSA8dGVtcGxhdGUgPHR5cGVuYW1lLi4uPiBjbGFzcyBUZW1wbGF0ZSwgdHlwZW5hbWUuLi4gVD4Kc3RydWN0IGxhenlfYXBwbHkgewoJdXNpbmcgdHlwZSA9IFRlbXBsYXRlPHR5cGVuYW1lIFQ6OnR5cGUuLi4+Owp9OwoKdGVtcGxhdGUgPHR5cGVuYW1lIFQsIHR5cGVuYW1lIFR1cGxlPgpzdHJ1Y3QgY29uc3RfdHVwbGU7CnRlbXBsYXRlIDx0eXBlbmFtZSBIZWFkLCB0eXBlbmFtZS4uLiBUYWlsPgpzdHJ1Y3QgY29uc190dXBsZTxIZWFkLCBzdGQ6OnR1cGxlPFRhaWwuLi4+Pgo6IGlkZW50aXR5PHN0ZDo6dHVwbGU8SGVhZCwgVGFpbC4uLj4+IHt9Owp0ZW1wbGF0ZSA8dHlwZW5hbWUgVCwgdHlwZW5hbWUgVHVwbGU+CnVzaW5nIENvbnNUdXBsZSA9IHR5cGVuYW1lIGNvbnNfdHVwbGU8VCwgVHVwbGU+Ojp0eXBlOwoKdGVtcGxhdGUgPHR5cGVuYW1lIFQsIHR5cGVuYW1lIFU+CnN0cnVjdCBsYXlvdXRfZmlyc3QgewojaWZuZGVmIF9MSUJDUFBfVkVSU0lPTgoJdXNpbmcgZmlyc3QgPSBUOwoJdXNpbmcgc2Vjb25kID0gVTsKI2Vsc2UKCXVzaW5nIGZpcnN0ID0gVTsKCXVzaW5nIHNlY29uZCA9IFQ7CiNlbmRpZgoKCWNvbnN0ZXhwciBzdGF0aWMgYm9vbCB2YWx1ZSA9IHN0ZDo6aXNfZW1wdHk8Zmlyc3Q+Ojp2YWx1ZQoJCXx8ICghc3RkOjppc19lbXB0eTxzZWNvbmQ+Ojp2YWx1ZSAmJiBhbGlnbm9mKGZpcnN0KSA+IGFsaWdub2Yoc2Vjb25kKSk7Cn07Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVCwgdHlwZW5hbWUgVHVwbGU+CnN0cnVjdCBpbnNlcnRfc29ydGVkCjogaWRlbnRpdHk8c3RkOjp0dXBsZTxUPj4ge307CnRlbXBsYXRlIDx0eXBlbmFtZSBULCBzdGQ6OnNpemVfdCBJLCB0eXBlbmFtZSBURmlyc3QsIHR5cGVuYW1lLi4uIFRTb3J0ZWQsIHN0ZDo6c2l6ZV90IElGaXJzdCwgc3RkOjpzaXplX3QuLi4gSVNvcnRlZD4Kc3RydWN0IGluc2VydF9zb3J0ZWQ8aW5kZXhlZDxULCBJPiwgc3RkOjp0dXBsZTxpbmRleGVkPFRGaXJzdCwgSUZpcnN0PiwgaW5kZXhlZDxUU29ydGVkLCBJU29ydGVkPi4uLj4+Cjogc3RkOjpjb25kaXRpb25hbDwKCWxheW91dF9maXJzdDxULCBURmlyc3Q+Ojp2YWx1ZSwKCWlkZW50aXR5PHN0ZDo6dHVwbGU8aW5kZXhlZDxULCBJPiwgaW5kZXhlZDxURmlyc3QsIElGaXJzdD4sIGluZGV4ZWQ8VFNvcnRlZCwgSVNvcnRlZD4uLi4+PiwKCWxhenlfYXBwbHk8Q29uc1R1cGxlLCBpZGVudGl0eTxpbmRleGVkPFRGaXJzdCwgSUZpcnN0Pj4sIGluc2VydF9zb3J0ZWQ8aW5kZXhlZDxULCBJPiwgc3RkOjp0dXBsZTxpbmRleGVkPFRTb3J0ZWQsIElTb3J0ZWQ+Li4uPj4+Cj46OnR5cGUge307Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVCwgdHlwZW5hbWUgVHVwbGU+CnVzaW5nIEluc2VydFNvcnRlZCA9IHR5cGVuYW1lIGluc2VydF9zb3J0ZWQ8VCwgVHVwbGU+Ojp0eXBlOwoKdGVtcGxhdGUgPHR5cGVuYW1lIFR1cGxlPgpzdHJ1Y3Qgc3BsaXQ7CnRlbXBsYXRlIDx0eXBlbmFtZS4uLiBULCBzdGQ6OnNpemVfdC4uLiBJPgpzdHJ1Y3Qgc3BsaXQ8c3RkOjp0dXBsZTxpbmRleGVkPFQsIEk+Li4uPj4gewoJdXNpbmcgdHlwZXMgPSBzdGQ6OnR1cGxlPFQuLi4+OwoJdXNpbmcgaW5kaWNlcyA9IHN0ZDo6dHVwbGU8U2l6ZVQ8ST4uLi4+Owp9CnRlbXBsYXRlIDx0eXBlbmFtZSBUPgp1c2luZyBFeHRyYWN0VHlwZXMgPSB0eXBlbmFtZSBzcGxpdDxUPjo6dHlwZXM7CnRlbXBsYXRlIDx0eXBlbmFtZSBUPgp1c2luZyBFeHRyYWN0SW5kaWNlcyA9IHR5cGVuYW1lIHNwbGl0PFQ+OjppbmRpY2VzOwoKdGVtcGxhdGUgPHR5cGVuYW1lIEFjYywgdHlwZW5hbWUgVD4Kc3RydWN0IHBlcmZlY3RfbGF5b3V0X2ltcGwgewoJdXNpbmcgdHVwbGVzID0gRXh0cmFjdFR5cGVzPEFjYz47Cgl1c2luZyBtYXAgPSBFeHRyYWN0SW5kaWNlczxBY2M+Owp9OwoKdGVtcGxhdGUgPHR5cGVuYW1lIEFjYywgdHlwZW5hbWUgSGVhZCwgdHlwZW5hbWUuLi4gVGFpbD4Kc3RydWN0IHBlcmZlY3RfbGF5b3V0X2ltcGw8QWNjLCBzdGQ6OnR1cGxlPEhlYWQsIFRhaWwuLi4+Pgo6IHBlcmZlY3RfbGF5b3V0X2ltcGw8SW5zZXJ0U29ydGVkPEhlYWQsIEFjYz4sIHN0ZDo6dHVwbGU8VGFpbC4uLj4+IHt9OwoKdGVtcGxhdGUgPHR5cGVuYW1lIEFjYywgdHlwZW5hbWUuLi4gVD4Kc3RydWN0IHdpdGhfaW5kaWNlc19pbXBsIDogaWRlbnRpdHk8QWNjPiB7fTsKdGVtcGxhdGUgPHR5cGVuYW1lIEFjYywgdHlwZW5hbWUgSGVhZCwgdHlwZW5hbWUuLi4gVGFpbD4Kc3RydWN0IHdpdGhfaW5kaWNlc19pbXBsPHN0ZDo6dHVwbGU8QWNjLi4uLCBpbmRleGVkPEhlYWQsIHNpemVvZi4uLihBY2MpPj4sIFRhaWwuLi4+IHt9Owp0ZW1wbGF0ZSA8dHlwZW5hbWUuLi4gVD4Kc3RydWN0IHdpdGhfaW5kaWNlcyA6IHdpdGhfaW5kaWNlc19pbXBsPHN0ZDo6dHVwbGU8PiwgVC4uLj4ge307CnRlbXBsYXRlIDx0eXBlbmFtZS4uLiBUPgp1c2luZyBXaXRoSW5kaWNlcyA9IHR5cGVuYW1lIHdpdGhfaW5kaWNlczxULi4uPjo6dHlwZTsKCnRlbXBsYXRlIDx0eXBlbmFtZS4uLiBUPgpzdHJ1Y3QgcGVyZmVjdF9sYXlvdXQKOiBwZXJmZWN0X2xheW91dF9pbXBsPHN0ZDo6dHVwbGU8PiwgV2l0aEluZGljZXM8VC4uLj4+IHt9OwoKCnRlbXBsYXRlIDx0eXBlbmFtZS4uLiBUPgp1c2luZyBQZXJmZWN0TGF5b3V0VHVwbGUgPSB0eXBlbmFtZSBwZXJmZWN0X2xheW91dDxULi4uPjo6dHVwbGU7CnRlbXBsYXRlIDx0eXBlbmFtZS4uLiBUPgp1c2luZyBQZXJmZWN0TGF5b3V0TWFwID0gdHlwZW5hbWUgcGVyZmVjdF9sYXlvdXQ8VC4uLj46Om1hcDsKCnRlbXBsYXRlIDxzdGQ6OnNpemVfdCBJLCB0eXBlbmFtZSBUPgp1c2luZyBUdXBsZUVsZW1lbnQgPSB0eXBlbmFtZSBzdGQ6OnR1cGxlX2VsZW1lbnQ8SSwgVD46OnR5cGU7Cgp0ZW1wbGF0ZSA8c3RkOjpzaXplX3QuLi4gSW5kaWNlcz4Kc3RydWN0IGluZGljZXMge307Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVD4Kc3RydWN0IGV2YWxfaW5kaWNlczsKdGVtcGxhdGUgPHR5cGVuYW1lLi4uIFM+CnN0cnVjdCBldmFsX2luZGljZXM8c3RkOjp0dXBsZTxTLi4uPj4KOiBpZGVudGl0eTxpbmRpY2VzPFM6OnZhbHVlLi4uPj4ge307Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVD4KdXNpbmcgRXZhbEluZGljZXMgPSB0eXBlbmFtZSBldmFsX2luZGljZXM8VD46OnR5cGU7Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUuLi4gVCwgc3RkOjpzaXplX3QuLi4gSW5kaWNlcz4Kc3RkOjp0dXBsZTxUdXBsZUVsZW1lbnQ8SW5kaWNlcywgc3RkOjp0dXBsZTxULi4uPj4uLi4+IGZvcndhcmRfZm9yX215X3R1cGxlKGluZGljZXM8SW5kaWNlcy4uLj4sIFQmJi4uLikgewoJYXV0byBmd2QgPSBzdGQ6OmZvcndhcmRfYXNfdHVwbGUoc3RkOjpmb3J3YXJkPFQ+KHQpLi4uKTsKCXJldHVybiBzdGQ6OmZvcndhcmRfYXNfdHVwbGUoc3RkOjpmb3J3YXJkPFR1cGxlRWxlbWVudDxJbmRpY2VzLCBzdGQ6OnR1cGxlPFQuLi4+Pj4oc3RkOjpnZXQ8SW5kaWNlcz4oZndkKSkuLi4pOwp9Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUuLi4gVD4Kc3RydWN0IG15X3R1cGxlIHsKcHVibGljOgoJbXlfdHVwbGUoKSA9IGRlZmF1bHQ7CglleHBsaWNpdCBteV90dXBsZShUIGNvbnN0Ji4uLiB0KQoJOiBpbm5lcihmb3J3YXJkX2Zvcl9teV90dXBsZShFdmFsSW5kaWNlczxQZXJmZWN0TGF5b3V0TWFwPFQuLi4+PigpLCB0Li4uKSB7fQoKCXRlbXBsYXRlIDx0eXBlbmFtZS4uLiBVPgoJZXhwbGljaXQgbXlfdHVwbGUoVSYmLi4uIHUpCgk6IGlubmVyKGZvcndhcmRfZm9yX215X3R1cGxlKEV2YWxJbmRpY2VzPFBlcmZlY3RMYXlvdXRNYXA8VC4uLj4+KCksIHUuLi4pIHt9CgoJdGVtcGxhdGUgPHN0ZDo6c2l6ZV90IEksIHR5cGVuYW1lLi4uIFQxPgoJZnJpZW5kIFR1cGxlRWxlbWVudDxJLCBzdGQ6OnR1cGxlPFQxLi4uPj4mIGdldChteV90dXBsZTxUMS4uLj4mIHQpIG5vZXhjZXB0OwoJdGVtcGxhdGUgPHN0ZDo6c2l6ZV90IEksIHR5cGVuYW1lLi4uIFQxPgoJZnJpZW5kIFR1cGxlRWxlbWVudDxJLCBzdGQ6OnR1cGxlPFQxLi4uPj4mJiBnZXQobXlfdHVwbGU8VDEuLi4+JiYgdCkgbm9leGNlcHQ7Cgl0ZW1wbGF0ZSA8c3RkOjpzaXplX3QgSSwgdHlwZW5hbWUuLi4gVDE+CglmcmllbmQgVHVwbGVFbGVtZW50PEksIHN0ZDo6dHVwbGU8VDEuLi4+PiBjb25zdCYgZ2V0KG15X3R1cGxlPFQxLi4uPiBjb25zdCYgdCkgbm9leGNlcHQ7Cgpwcml2YXRlOgoJUGVyZmVjdExheW91dFR1cGxlPFQuLi4+IGlubmVyOwp9OwoKdGVtcGxhdGUgPHN0ZDo6c2l6ZV90IEksIHR5cGVuYW1lLi4uIFQxPgpUdXBsZUVsZW1lbnQ8SSwgc3RkOjp0dXBsZTxUMS4uLj4+JiBnZXQobXlfdHVwbGU8VDEuLi4+JiB0KSBub2V4Y2VwdCB7CglyZXR1cm4gc3RkOjpnZXQ8VHVwbGVFbGVtZW50PEksIFBlcmZlY3RMYXlvdXRNYXA8VC4uLj4+Ojp2YWx1ZT4odC5pbm5lcik7Cn0KdGVtcGxhdGUgPHN0ZDo6c2l6ZV90IEksIHR5cGVuYW1lLi4uIFQxPgpUdXBsZUVsZW1lbnQ8SSwgc3RkOjp0dXBsZTxUMS4uLj4+JiYgZ2V0KG15X3R1cGxlPFQxLi4uPiYmIHQpIG5vZXhjZXB0IHsKCXJldHVybiBzdGQ6OmdldDxUdXBsZUVsZW1lbnQ8SSwgUGVyZmVjdExheW91dE1hcDxULi4uPj46OnZhbHVlPihzdGQ6Om1vdmUodC5pbm5lcikpOwp9CnRlbXBsYXRlIDxzdGQ6OnNpemVfdCBJLCB0eXBlbmFtZS4uLiBUMT4KVHVwbGVFbGVtZW50PEksIHN0ZDo6dHVwbGU8VDEuLi4+PiBjb25zdCYgZ2V0KG15X3R1cGxlPFQxLi4uPiBjb25zdCYgdCkgbm9leGNlcHQgewoJcmV0dXJuIHN0ZDo6Z2V0PFR1cGxlRWxlbWVudDxJLCBQZXJmZWN0TGF5b3V0TWFwPFQuLi4+Pjo6dmFsdWU+KHQuaW5uZXIpOwp9CgovKioqKioqIFRFU1RJTkcgUEFSVCAqKioqKiovCgoKc3RydWN0IGVtcHR5MCB7fTsKc3RydWN0IGVtcHR5MSB7fTsKc3RydWN0IGVtcHR5MiB7fTsKCnRlbXBsYXRlIDxzdGQ6OnNpemVfdCBTaXplLCBzdGQ6OnNpemVfdCBBbGlnbj4KdXNpbmcgTGF5b3V0ID0gdHlwZW5hbWUgc3RkOjphbGlnbmVkX3N0b3JhZ2U8U2l6ZSwgQWxpZ24+Ojp0eXBlOwoKdXNpbmcgdHlwZTEgPSBMYXlvdXQ8MSwxPjsKdXNpbmcgdHlwZTIgPSBMYXlvdXQ8MiwyPjsKdXNpbmcgdHlwZTQgPSBMYXlvdXQ8NCw0PjsKdXNpbmcgdHlwZTggPSBMYXlvdXQ8OCw4PjsKCnN0YXRpY19hc3NlcnQoc2l6ZW9mKG15X3R1cGxlPGVtcHR5MCwgZW1wdHkxLCBlbXB0eTIsIHR5cGU4PikgPT0gc2l6ZW9mKHR5cGU4KSwKCSJFbXB0eSBiYXNlIGNsYXNzIG9wdGltaXphdGlvbiBzaG91bGQgYmUgZG9uZSBvbiBwcmVmaXggZW1wdGllcyIpOwpzdGF0aWNfYXNzZXJ0KHNpemVvZihteV90dXBsZTx0eXBlOCwgZW1wdHkwLCBlbXB0eTEsIGVtcHR5Mj4pID09IHNpemVvZih0eXBlOCksCgkiRW1wdHkgYmFzZSBjbGFzcyBvcHRpbWl6YXRpb24gc2hvdWxkIGJlIGRvbmUgb24gc3VmZml4IGVtcHRpZXMiKTsKc3RhdGljX2Fzc2VydChzaXplb2YobXlfdHVwbGU8dHlwZTgsIGVtcHR5MCwgZW1wdHkxLCBlbXB0eTIsIHR5cGU4PikgPT0gMipzaXplb2YodHlwZTgpLAoJIkVtcHR5IGJhc2UgY2xhc3Mgb3B0aW1pemF0aW9uIHNob3VsZCBiZSBkb25lIG9uIG1pZGRsZSBlbXB0aWVzIik7CgoKc3RhdGljX2Fzc2VydChzaXplb2YobXlfdHVwbGU8ZW1wdHkwLCBlbXB0eTEsIGVtcHR5MiwgdHlwZTgsIHR5cGU0LCB0eXBlMiwgdHlwZTEsIHR5cGUxPikgPT0gc2l6ZW9mKHR5cGU4KSArIHNpemVvZih0eXBlNCkgKyBzaXplb2YodHlwZTIpICsgMipzaXplb2YodHlwZTEpLAoJIlBlcmZlY3QgbGF5b3V0IHNob3VsZCBub3QgYmUgcnVpbmVkIik7CnN0YXRpY19hc3NlcnQoc2l6ZW9mKG15X3R1cGxlPHR5cGUxLCB0eXBlMiwgZW1wdHkwLCBlbXB0eTEsIHR5cGUxLCB0eXBlOCwgZW1wdHkyLCB0eXBlND4pID09IHNpemVvZih0eXBlOCkgKyBzaXplb2YodHlwZTQpICsgc2l6ZW9mKHR5cGUyKSArIDIqc2l6ZW9mKHR5cGUxKSwKCSJQZXJmZWN0IGxheW91dCBzaG91bGQgYmUgYXJyYW5nZWQiKTsKCiNpbmNsdWRlIDxjYXNzZXJ0PgoKaW50IG1haW4oKSB7CglteV90dXBsZTxpbnQsIGVtcHR5MCwgZW1wdHkxLCBkb3VibGUsIGVtcHR5MiwgaW50PiB0IHsgMSwge30sIHt9LCAwLjUsIHt9LCAyIH07CgkvLyByZW9yZGVyaW5nIHNob3VsZCBiZSBpbnZpc2libGUgdG8gdGhlIGNsaWVudAoJc3RhdGljX2Fzc2VydChzdGQ6OmlzX3NhbWU8ZGVjbHR5cGUoZ2V0PDA+KHQpKSwgaW50Jj46OnZhbHVlLCAiIik7CglzdGF0aWNfYXNzZXJ0KHN0ZDo6aXNfc2FtZTxkZWNsdHlwZShnZXQ8MT4odCkpLCBlbXB0eTAmPjo6dmFsdWUsICIiKTsKCXN0YXRpY19hc3NlcnQoc3RkOjppc19zYW1lPGRlY2x0eXBlKGdldDwyPih0KSksIGVtcHR5MSY+Ojp2YWx1ZSwgIiIpOwoJc3RhdGljX2Fzc2VydChzdGQ6OmlzX3NhbWU8ZGVjbHR5cGUoZ2V0PDM+KHQpKSwgZG91YmxlJj46OnZhbHVlLCAiIik7CglzdGF0aWNfYXNzZXJ0KHN0ZDo6aXNfc2FtZTxkZWNsdHlwZShnZXQ8ND4odCkpLCBlbXB0eTImPjo6dmFsdWUsICIiKTsKCXN0YXRpY19hc3NlcnQoc3RkOjppc19zYW1lPGRlY2x0eXBlKGdldDw1Pih0KSksIGludCY+Ojp2YWx1ZSwgIiIpOwoJYXNzZXJ0KGdldDwwPih0KSA9PSAxKTsKCWFzc2VydChnZXQ8Mz4odCkgPT0gMC41KTsKCWFzc2VydChnZXQ8NT4odCkgPT0gMik7CglnZXQ8MD4odCkgPSB7IDMgfTsKCWdldDwzPih0KSA9IHsgMi41IH07CglnZXQ8NT4odCkgPSB7IDUgfTsKCWFzc2VydChnZXQ8MD4odCkgPT0gMyk7Cglhc3NlcnQoZ2V0PDM+KHQpID09IDIuNSk7Cglhc3NlcnQoZ2V0PDU+KHQpID09IDQpOwp9Cg==