#include <stdio.h>
#include <algorithm> // for std::swap
// Preprocessor
//
#define PP_REPEAT_0(exp,sep) exp(0)
#define PP_REPEAT_1(exp,sep) sep(PP_REPEAT_0(exp,sep),exp(1))
#define PP_REPEAT_2(exp,sep) sep(PP_REPEAT_1(exp,sep),exp(2))
#define PP_REPEAT_3(exp,sep) sep(PP_REPEAT_2(exp,sep),exp(3))
#define PP_REPEAT_4(exp,sep) sep(PP_REPEAT_3(exp,sep),exp(4))
#define PP_REPEAT_5(exp,sep) sep(PP_REPEAT_4(exp,sep),exp(5))
#define PP_REPEAT(n,exp,sep) PP_REPEAT_##n(exp,sep)
#define PP_REPEAT_FROM_1_TO_1(exp,sep) exp(1)
#define PP_REPEAT_FROM_1_TO_2(exp,sep) sep(PP_REPEAT_FROM_1_TO_1(exp,sep),exp(2))
#define PP_REPEAT_FROM_1_TO_3(exp,sep) sep(PP_REPEAT_FROM_1_TO_2(exp,sep),exp(3))
#define PP_REPEAT_FROM_1_TO_4(exp,sep) sep(PP_REPEAT_FROM_1_TO_3(exp,sep),exp(4))
#define PP_REPEAT_FROM_1_TO_5(exp,sep) sep(PP_REPEAT_FROM_1_TO_4(exp,sep),exp(5))
#define PP_REPEAT_FROM_1_TO_6(exp,sep) sep(PP_REPEAT_FROM_1_TO_5(exp,sep),exp(6))
#define PP_REPEAT_FROM_1_TO(n,exp,sep) PP_REPEAT_FROM_1_TO_##n(exp,sep)
#define PP_SPACE(x,y) x y
#define PP_COMMA(x,y) x, y
#define PP_SEMICOLON(x,y) x; y
#define PP_DEC1 0
#define PP_DEC2 1
#define PP_DEC3 2
#define PP_DEC4 3
#define PP_DEC5 4
#define PP_DEC6 5
#define PP_DEC(x) PP_DEC##x
// Typelist
//
#define TEMPLATE_PARAM_NAME(n) T##n
#define TEMPLATE_PARAM(n) class T##n
#define TEMPLATE_PARAM_NULLTYPE(n) class T##n = NullType
#define TYPELIST_PARAM_NAMES PP_REPEAT(5,TEMPLATE_PARAM_NAME,PP_COMMA)
#define TYPELIST_PARAMS PP_REPEAT(5,TEMPLATE_PARAM,PP_COMMA)
#define TYPELIST_PARAMS_NULLTYPE PP_REPEAT(5,TEMPLATE_PARAM_NULLTYPE,PP_COMMA)
struct NullType;
template<class, class> struct Typelist;
template<TYPELIST_PARAMS_NULLTYPE>
struct MakeTypelist
{
typedef Typelist<T0, typename MakeTypelist<PP_REPEAT_FROM_1_TO(5,TEMPLATE_PARAM_NAME,PP_COMMA)>::Result> Result;
};
template<>
struct MakeTypelist<>
{
typedef NullType Result;
};
template<class TList> struct Length;
template<>
struct Length<NullType>
{
static const size_t value = 0;
};
template<class T, class U>
struct Length<Typelist<T, U> >
{
static const size_t value = 1 + Length<U>::value;
};
template<class TList, unsigned int index> struct TypeAt;
template<class Head, class Tail>
struct TypeAt<Typelist<Head, Tail>, 0>
{
typedef Head Result;
};
template<class Head, class Tail, unsigned int i>
struct TypeAt<Typelist<Head, Tail>, i>
{
typedef typename TypeAt<Tail, i - 1>::Result Result;
};
template<class TList, class T> struct IndexOf;
template<class T> struct IndexOf<NullType, T> {};
template<class T, class Tail>
struct IndexOf<Typelist<T, Tail>, T>
{
static const int value = 0;
};
template<class Head, class Tail, class T>
struct IndexOf<Typelist<Head, Tail>, T>
{
static const int value = 1 + IndexOf<Tail, T>::value;
};
// Selector
//
#define SELECTOR_CASE(n) \
case n: return visitor(*static_cast<typename TypeAt<TList, n>::Result*>(storage))
#define SELECTOR_CASES_ENUM(n) PP_REPEAT(n,SELECTOR_CASE,PP_SEMICOLON)
#define SELECTOR_ENUM(n) \
template<> \
struct Selector<n> \
{ \
template<class TList, class Visitor> \
static typename Visitor::ResultType apply(Visitor visitor, unsigned char which, void* storage) \
{ \
switch (which) \
{ \
SELECTOR_CASES_ENUM(PP_DEC(n)); \
} \
} \
}
template<size_t> struct Selector;
PP_REPEAT_FROM_1_TO(6,SELECTOR_ENUM,PP_SEMICOLON);
// Variant
//
template<TYPELIST_PARAMS_NULLTYPE>
class Variant
{
public:
template<class T>
Variant(T const &t)
: which_(IndexOf<internal_types, T>::value)
, storage_(new T(t))
{
}
~Variant()
{
apply(Destroyer());
}
Variant(Variant const &other)
: which_(other.which_)
, storage_(other.apply(CopyConstructHelper()))
{
}
template<class Visitor>
typename Visitor::ResultType apply(Visitor visitor) const
{
return Selector<Length<internal_types>::value>::template apply<internal_types>(visitor, which_, storage_);
}
void swap(Variant &other)
{
std::swap(which_, other.which_);
std::swap(storage_, other.storage_);
}
template<class T>
void operator=(T const &t)
{
Variant(t).swap(*this);
}
private:
typedef typename MakeTypelist<TYPELIST_PARAM_NAMES>::Result internal_types;
struct Destroyer
{
typedef void ResultType;
template<class T>
void operator()(T &t) const
{
delete &t;
}
};
struct CopyConstructHelper
{
typedef void* ResultType;
template<class T>
void* operator()(T const &t) const
{
return new T(t);
}
};
unsigned char which_;
void* storage_;
};
template<class T>
struct StaticVisitor
{
typedef T ResultType;
};
template<class A>
struct less_visitor : StaticVisitor<bool>
{
A a_;
less_visitor(A const &a) : a_(a) {}
template<class U>
bool operator()(U const &u) const
{
return u < a_;
}
};
#define TEMPLATE_PARAM_A(n) class A##n
#define TEMPLATE_PARAM_NAME_A(n) A##n
#define FUNCTION_PARAM(n) A##n a##n
#define FUNCTION_ARG(n) a##n
template<TYPELIST_PARAMS, class A>
Variant<TYPELIST_PARAM_NAMES>& max_helper(Variant<TYPELIST_PARAM_NAMES> &u, A a)
{
if (u.apply(less_visitor<A>(a))) // u < a
u = a;
return u;
}
#define MAX_HELPER_ENUM(n) \
template<TYPELIST_PARAMS, PP_REPEAT(n,TEMPLATE_PARAM_A,PP_COMMA)> \
Variant<TYPELIST_PARAM_NAMES>& max_helper(Variant<TYPELIST_PARAM_NAMES> &u, PP_REPEAT(n,FUNCTION_PARAM,PP_COMMA)) \
{ \
return max_helper(max_helper(u, a0), PP_REPEAT_FROM_1_TO(n,FUNCTION_ARG,PP_COMMA)); \
}
#define MAX_ENUM(n) \
template<PP_REPEAT(n,TEMPLATE_PARAM_A,PP_COMMA)> \
Variant<PP_REPEAT(n,TEMPLATE_PARAM_NAME_A,PP_COMMA)> max(PP_REPEAT(n,FUNCTION_PARAM,PP_COMMA)) \
{ \
Variant<PP_REPEAT(n,TEMPLATE_PARAM_NAME_A,PP_COMMA)> u(a0); \
return max_helper(u, PP_REPEAT_FROM_1_TO(n,FUNCTION_ARG,PP_COMMA)); \
}
// TODO: PP_REPEAT_FROM_1_TO(4,MAX_HELPER_ENUM,PP_SPACE)
MAX_HELPER_ENUM(1)
MAX_HELPER_ENUM(2)
MAX_HELPER_ENUM(3)
MAX_HELPER_ENUM(4)
// TODO: PP_REPEAT_FROM_1_TO(5,MAX_ENUM,PP_SPACE)
MAX_ENUM(1)
MAX_ENUM(2)
MAX_ENUM(3)
MAX_ENUM(4)
MAX_ENUM(5)
struct Println : StaticVisitor<void>
{
void operator()(int i) const
{
printf("int %d\n", i);
}
void operator()(float f) const
{
printf("float %f\n", f);
}
void operator()(double d) const
{
printf("double %f\n", d);
}
};
int main()
{
max(3, 3.14f).apply(Println()); // float 3.140000
max(3, 3.14f, 3.0).apply(Println()); // float 3.140000
max(3, 3.14f, 4.0).apply(Println()); // double 4.000000
max(3, 5, 3.14f, 4.0).apply(Println()); // int 5
return 0;
}
I2luY2x1ZGUgPHN0ZGlvLmg+CgojaW5jbHVkZSA8YWxnb3JpdGhtPiAvLyBmb3Igc3RkOjpzd2FwCgovLyBQcmVwcm9jZXNzb3IKLy8KI2RlZmluZSBQUF9SRVBFQVRfMChleHAsc2VwKSBleHAoMCkKI2RlZmluZSBQUF9SRVBFQVRfMShleHAsc2VwKSBzZXAoUFBfUkVQRUFUXzAoZXhwLHNlcCksZXhwKDEpKQojZGVmaW5lIFBQX1JFUEVBVF8yKGV4cCxzZXApIHNlcChQUF9SRVBFQVRfMShleHAsc2VwKSxleHAoMikpCiNkZWZpbmUgUFBfUkVQRUFUXzMoZXhwLHNlcCkgc2VwKFBQX1JFUEVBVF8yKGV4cCxzZXApLGV4cCgzKSkKI2RlZmluZSBQUF9SRVBFQVRfNChleHAsc2VwKSBzZXAoUFBfUkVQRUFUXzMoZXhwLHNlcCksZXhwKDQpKQojZGVmaW5lIFBQX1JFUEVBVF81KGV4cCxzZXApIHNlcChQUF9SRVBFQVRfNChleHAsc2VwKSxleHAoNSkpCiNkZWZpbmUgUFBfUkVQRUFUKG4sZXhwLHNlcCkgUFBfUkVQRUFUXyMjbihleHAsc2VwKQoKI2RlZmluZSBQUF9SRVBFQVRfRlJPTV8xX1RPXzEoZXhwLHNlcCkgZXhwKDEpCiNkZWZpbmUgUFBfUkVQRUFUX0ZST01fMV9UT18yKGV4cCxzZXApIHNlcChQUF9SRVBFQVRfRlJPTV8xX1RPXzEoZXhwLHNlcCksZXhwKDIpKQojZGVmaW5lIFBQX1JFUEVBVF9GUk9NXzFfVE9fMyhleHAsc2VwKSBzZXAoUFBfUkVQRUFUX0ZST01fMV9UT18yKGV4cCxzZXApLGV4cCgzKSkKI2RlZmluZSBQUF9SRVBFQVRfRlJPTV8xX1RPXzQoZXhwLHNlcCkgc2VwKFBQX1JFUEVBVF9GUk9NXzFfVE9fMyhleHAsc2VwKSxleHAoNCkpCiNkZWZpbmUgUFBfUkVQRUFUX0ZST01fMV9UT181KGV4cCxzZXApIHNlcChQUF9SRVBFQVRfRlJPTV8xX1RPXzQoZXhwLHNlcCksZXhwKDUpKQojZGVmaW5lIFBQX1JFUEVBVF9GUk9NXzFfVE9fNihleHAsc2VwKSBzZXAoUFBfUkVQRUFUX0ZST01fMV9UT181KGV4cCxzZXApLGV4cCg2KSkKI2RlZmluZSBQUF9SRVBFQVRfRlJPTV8xX1RPKG4sZXhwLHNlcCkgUFBfUkVQRUFUX0ZST01fMV9UT18jI24oZXhwLHNlcCkKCiNkZWZpbmUgUFBfU1BBQ0UoeCx5KSB4IHkKI2RlZmluZSBQUF9DT01NQSh4LHkpIHgsIHkKI2RlZmluZSBQUF9TRU1JQ09MT04oeCx5KSB4OyB5CgojZGVmaW5lIFBQX0RFQzEgMAojZGVmaW5lIFBQX0RFQzIgMQojZGVmaW5lIFBQX0RFQzMgMgojZGVmaW5lIFBQX0RFQzQgMwojZGVmaW5lIFBQX0RFQzUgNAojZGVmaW5lIFBQX0RFQzYgNQojZGVmaW5lIFBQX0RFQyh4KSBQUF9ERUMjI3gKCi8vIFR5cGVsaXN0Ci8vCiNkZWZpbmUgVEVNUExBVEVfUEFSQU1fTkFNRShuKSBUIyNuCiNkZWZpbmUgVEVNUExBVEVfUEFSQU0obikgY2xhc3MgVCMjbgojZGVmaW5lIFRFTVBMQVRFX1BBUkFNX05VTExUWVBFKG4pIGNsYXNzIFQjI24gPSBOdWxsVHlwZQoKI2RlZmluZSBUWVBFTElTVF9QQVJBTV9OQU1FUyBQUF9SRVBFQVQoNSxURU1QTEFURV9QQVJBTV9OQU1FLFBQX0NPTU1BKQojZGVmaW5lIFRZUEVMSVNUX1BBUkFNUyBQUF9SRVBFQVQoNSxURU1QTEFURV9QQVJBTSxQUF9DT01NQSkKI2RlZmluZSBUWVBFTElTVF9QQVJBTVNfTlVMTFRZUEUgUFBfUkVQRUFUKDUsVEVNUExBVEVfUEFSQU1fTlVMTFRZUEUsUFBfQ09NTUEpCgpzdHJ1Y3QgTnVsbFR5cGU7Cgp0ZW1wbGF0ZTxjbGFzcywgY2xhc3M+IHN0cnVjdCBUeXBlbGlzdDsKCnRlbXBsYXRlPFRZUEVMSVNUX1BBUkFNU19OVUxMVFlQRT4Kc3RydWN0IE1ha2VUeXBlbGlzdAp7Cgl0eXBlZGVmIFR5cGVsaXN0PFQwLCB0eXBlbmFtZSBNYWtlVHlwZWxpc3Q8UFBfUkVQRUFUX0ZST01fMV9UTyg1LFRFTVBMQVRFX1BBUkFNX05BTUUsUFBfQ09NTUEpPjo6UmVzdWx0PiBSZXN1bHQ7Cn07Cgp0ZW1wbGF0ZTw+CnN0cnVjdCBNYWtlVHlwZWxpc3Q8Pgp7Cgl0eXBlZGVmIE51bGxUeXBlIFJlc3VsdDsKfTsKCnRlbXBsYXRlPGNsYXNzIFRMaXN0PiBzdHJ1Y3QgTGVuZ3RoOwoKdGVtcGxhdGU8PgpzdHJ1Y3QgTGVuZ3RoPE51bGxUeXBlPgp7CglzdGF0aWMgY29uc3Qgc2l6ZV90IHZhbHVlID0gMDsKfTsKCnRlbXBsYXRlPGNsYXNzIFQsIGNsYXNzIFU+CnN0cnVjdCBMZW5ndGg8VHlwZWxpc3Q8VCwgVT4gPgp7CglzdGF0aWMgY29uc3Qgc2l6ZV90IHZhbHVlID0gMSArIExlbmd0aDxVPjo6dmFsdWU7Cn07Cgp0ZW1wbGF0ZTxjbGFzcyBUTGlzdCwgdW5zaWduZWQgaW50IGluZGV4PiBzdHJ1Y3QgVHlwZUF0OwoKdGVtcGxhdGU8Y2xhc3MgSGVhZCwgY2xhc3MgVGFpbD4Kc3RydWN0IFR5cGVBdDxUeXBlbGlzdDxIZWFkLCBUYWlsPiwgMD4KewoJdHlwZWRlZiBIZWFkIFJlc3VsdDsKfTsKCnRlbXBsYXRlPGNsYXNzIEhlYWQsIGNsYXNzIFRhaWwsIHVuc2lnbmVkIGludCBpPgpzdHJ1Y3QgVHlwZUF0PFR5cGVsaXN0PEhlYWQsIFRhaWw+LCBpPgp7Cgl0eXBlZGVmIHR5cGVuYW1lIFR5cGVBdDxUYWlsLCBpIC0gMT46OlJlc3VsdCBSZXN1bHQ7Cn07Cgp0ZW1wbGF0ZTxjbGFzcyBUTGlzdCwgY2xhc3MgVD4gc3RydWN0IEluZGV4T2Y7Cgp0ZW1wbGF0ZTxjbGFzcyBUPiBzdHJ1Y3QgSW5kZXhPZjxOdWxsVHlwZSwgVD4ge307Cgp0ZW1wbGF0ZTxjbGFzcyBULCBjbGFzcyBUYWlsPgpzdHJ1Y3QgSW5kZXhPZjxUeXBlbGlzdDxULCBUYWlsPiwgVD4KewoJc3RhdGljIGNvbnN0IGludCB2YWx1ZSA9IDA7Cn07Cgp0ZW1wbGF0ZTxjbGFzcyBIZWFkLCBjbGFzcyBUYWlsLCBjbGFzcyBUPgpzdHJ1Y3QgSW5kZXhPZjxUeXBlbGlzdDxIZWFkLCBUYWlsPiwgVD4KewoJc3RhdGljIGNvbnN0IGludCB2YWx1ZSA9IDEgKyBJbmRleE9mPFRhaWwsIFQ+Ojp2YWx1ZTsKfTsKCi8vIFNlbGVjdG9yCi8vCiNkZWZpbmUgU0VMRUNUT1JfQ0FTRShuKSBcCgljYXNlIG46IHJldHVybiB2aXNpdG9yKCpzdGF0aWNfY2FzdDx0eXBlbmFtZSBUeXBlQXQ8VExpc3QsIG4+OjpSZXN1bHQqPihzdG9yYWdlKSkKCiNkZWZpbmUgU0VMRUNUT1JfQ0FTRVNfRU5VTShuKSBQUF9SRVBFQVQobixTRUxFQ1RPUl9DQVNFLFBQX1NFTUlDT0xPTikKCiNkZWZpbmUgU0VMRUNUT1JfRU5VTShuKSBcCnRlbXBsYXRlPD4gXApzdHJ1Y3QgU2VsZWN0b3I8bj4gXAp7IFwKCXRlbXBsYXRlPGNsYXNzIFRMaXN0LCBjbGFzcyBWaXNpdG9yPiBcCglzdGF0aWMgdHlwZW5hbWUgVmlzaXRvcjo6UmVzdWx0VHlwZSBhcHBseShWaXNpdG9yIHZpc2l0b3IsIHVuc2lnbmVkIGNoYXIgd2hpY2gsIHZvaWQqIHN0b3JhZ2UpIFwKCXsgXAoJCXN3aXRjaCAod2hpY2gpIFwKCQl7IFwKCQlTRUxFQ1RPUl9DQVNFU19FTlVNKFBQX0RFQyhuKSk7IFwKCQl9IFwKCX0gXAp9Cgp0ZW1wbGF0ZTxzaXplX3Q+IHN0cnVjdCBTZWxlY3RvcjsKClBQX1JFUEVBVF9GUk9NXzFfVE8oNixTRUxFQ1RPUl9FTlVNLFBQX1NFTUlDT0xPTik7CgovLyBWYXJpYW50Ci8vCnRlbXBsYXRlPFRZUEVMSVNUX1BBUkFNU19OVUxMVFlQRT4KY2xhc3MgVmFyaWFudAp7CnB1YmxpYzoKCgl0ZW1wbGF0ZTxjbGFzcyBUPgoJVmFyaWFudChUIGNvbnN0ICZ0KQoJCTogd2hpY2hfKEluZGV4T2Y8aW50ZXJuYWxfdHlwZXMsIFQ+Ojp2YWx1ZSkKCQksIHN0b3JhZ2VfKG5ldyBUKHQpKQoJewoJfQoKCX5WYXJpYW50KCkKCXsKCQlhcHBseShEZXN0cm95ZXIoKSk7Cgl9CgoJVmFyaWFudChWYXJpYW50IGNvbnN0ICZvdGhlcikKCQk6IHdoaWNoXyhvdGhlci53aGljaF8pCgkJLCBzdG9yYWdlXyhvdGhlci5hcHBseShDb3B5Q29uc3RydWN0SGVscGVyKCkpKQkKCXsKCX0KCgl0ZW1wbGF0ZTxjbGFzcyBWaXNpdG9yPgoJdHlwZW5hbWUgVmlzaXRvcjo6UmVzdWx0VHlwZSBhcHBseShWaXNpdG9yIHZpc2l0b3IpIGNvbnN0Cgl7CgkJcmV0dXJuIFNlbGVjdG9yPExlbmd0aDxpbnRlcm5hbF90eXBlcz46OnZhbHVlPjo6dGVtcGxhdGUgYXBwbHk8aW50ZXJuYWxfdHlwZXM+KHZpc2l0b3IsIHdoaWNoXywgc3RvcmFnZV8pOwoJfQoKCXZvaWQgc3dhcChWYXJpYW50ICZvdGhlcikKCXsKCQlzdGQ6OnN3YXAod2hpY2hfLCBvdGhlci53aGljaF8pOwoJCXN0ZDo6c3dhcChzdG9yYWdlXywgb3RoZXIuc3RvcmFnZV8pOwoJfQoKCXRlbXBsYXRlPGNsYXNzIFQ+Cgl2b2lkIG9wZXJhdG9yPShUIGNvbnN0ICZ0KQoJewoJCVZhcmlhbnQodCkuc3dhcCgqdGhpcyk7Cgl9Cgpwcml2YXRlOgoKCXR5cGVkZWYgdHlwZW5hbWUgTWFrZVR5cGVsaXN0PFRZUEVMSVNUX1BBUkFNX05BTUVTPjo6UmVzdWx0IGludGVybmFsX3R5cGVzOwoKCXN0cnVjdCBEZXN0cm95ZXIKCXsKCQl0eXBlZGVmIHZvaWQgUmVzdWx0VHlwZTsKCgkJdGVtcGxhdGU8Y2xhc3MgVD4KCQl2b2lkIG9wZXJhdG9yKCkoVCAmdCkgY29uc3QKCQl7CgkJCWRlbGV0ZSAmdDsKCQl9Cgl9OwoKCXN0cnVjdCBDb3B5Q29uc3RydWN0SGVscGVyCgl7CgkJdHlwZWRlZiB2b2lkKiBSZXN1bHRUeXBlOwoKCQl0ZW1wbGF0ZTxjbGFzcyBUPgoJCXZvaWQqIG9wZXJhdG9yKCkoVCBjb25zdCAmdCkgY29uc3QKCQl7CgkJCXJldHVybiBuZXcgVCh0KTsKCQl9Cgl9OwoKCXVuc2lnbmVkIGNoYXIgd2hpY2hfOwoJdm9pZCogc3RvcmFnZV87Cn07Cgp0ZW1wbGF0ZTxjbGFzcyBUPgpzdHJ1Y3QgU3RhdGljVmlzaXRvcgp7Cgl0eXBlZGVmIFQgUmVzdWx0VHlwZTsKfTsKCnRlbXBsYXRlPGNsYXNzIEE+CnN0cnVjdCBsZXNzX3Zpc2l0b3IgOiBTdGF0aWNWaXNpdG9yPGJvb2w+CnsKCUEgYV87CgoJbGVzc192aXNpdG9yKEEgY29uc3QgJmEpIDogYV8oYSkge30KCgl0ZW1wbGF0ZTxjbGFzcyBVPgoJYm9vbCBvcGVyYXRvcigpKFUgY29uc3QgJnUpIGNvbnN0Cgl7CgkJcmV0dXJuIHUgPCBhXzsKCX0KfTsKCiNkZWZpbmUgVEVNUExBVEVfUEFSQU1fQShuKSBjbGFzcyBBIyNuCiNkZWZpbmUgVEVNUExBVEVfUEFSQU1fTkFNRV9BKG4pIEEjI24KI2RlZmluZSBGVU5DVElPTl9QQVJBTShuKSBBIyNuIGEjI24KI2RlZmluZSBGVU5DVElPTl9BUkcobikgYSMjbgoKdGVtcGxhdGU8VFlQRUxJU1RfUEFSQU1TLCBjbGFzcyBBPgpWYXJpYW50PFRZUEVMSVNUX1BBUkFNX05BTUVTPiYgbWF4X2hlbHBlcihWYXJpYW50PFRZUEVMSVNUX1BBUkFNX05BTUVTPiAmdSwgQSBhKQp7CglpZiAodS5hcHBseShsZXNzX3Zpc2l0b3I8QT4oYSkpKSAvLyB1IDwgYQoJCXUgPSBhOwoJcmV0dXJuIHU7Cn0KCiNkZWZpbmUgTUFYX0hFTFBFUl9FTlVNKG4pIFwKdGVtcGxhdGU8VFlQRUxJU1RfUEFSQU1TLCBQUF9SRVBFQVQobixURU1QTEFURV9QQVJBTV9BLFBQX0NPTU1BKT4gXApWYXJpYW50PFRZUEVMSVNUX1BBUkFNX05BTUVTPiYgbWF4X2hlbHBlcihWYXJpYW50PFRZUEVMSVNUX1BBUkFNX05BTUVTPiAmdSwgUFBfUkVQRUFUKG4sRlVOQ1RJT05fUEFSQU0sUFBfQ09NTUEpKSBcCnsgXAoJcmV0dXJuIG1heF9oZWxwZXIobWF4X2hlbHBlcih1LCBhMCksIFBQX1JFUEVBVF9GUk9NXzFfVE8obixGVU5DVElPTl9BUkcsUFBfQ09NTUEpKTsgXAp9CgojZGVmaW5lIE1BWF9FTlVNKG4pIFwKdGVtcGxhdGU8UFBfUkVQRUFUKG4sVEVNUExBVEVfUEFSQU1fQSxQUF9DT01NQSk+IFwKVmFyaWFudDxQUF9SRVBFQVQobixURU1QTEFURV9QQVJBTV9OQU1FX0EsUFBfQ09NTUEpPiBtYXgoUFBfUkVQRUFUKG4sRlVOQ1RJT05fUEFSQU0sUFBfQ09NTUEpKSBcCnsgXAoJVmFyaWFudDxQUF9SRVBFQVQobixURU1QTEFURV9QQVJBTV9OQU1FX0EsUFBfQ09NTUEpPiB1KGEwKTsgXAoJcmV0dXJuIG1heF9oZWxwZXIodSwgUFBfUkVQRUFUX0ZST01fMV9UTyhuLEZVTkNUSU9OX0FSRyxQUF9DT01NQSkpOyBcCn0KCi8vIFRPRE86IFBQX1JFUEVBVF9GUk9NXzFfVE8oNCxNQVhfSEVMUEVSX0VOVU0sUFBfU1BBQ0UpCk1BWF9IRUxQRVJfRU5VTSgxKQpNQVhfSEVMUEVSX0VOVU0oMikKTUFYX0hFTFBFUl9FTlVNKDMpCk1BWF9IRUxQRVJfRU5VTSg0KQoKLy8gVE9ETzogUFBfUkVQRUFUX0ZST01fMV9UTyg1LE1BWF9FTlVNLFBQX1NQQUNFKQpNQVhfRU5VTSgxKQpNQVhfRU5VTSgyKQpNQVhfRU5VTSgzKQpNQVhfRU5VTSg0KQpNQVhfRU5VTSg1KQoKc3RydWN0IFByaW50bG4gOiBTdGF0aWNWaXNpdG9yPHZvaWQ+CnsKCXZvaWQgb3BlcmF0b3IoKShpbnQgaSkgY29uc3QKCXsKCQlwcmludGYoImludCAlZFxuIiwgaSk7Cgl9CgoJdm9pZCBvcGVyYXRvcigpKGZsb2F0IGYpIGNvbnN0Cgl7CgkJcHJpbnRmKCJmbG9hdCAlZlxuIiwgZik7Cgl9CgoJdm9pZCBvcGVyYXRvcigpKGRvdWJsZSBkKSBjb25zdAoJewoJCXByaW50ZigiZG91YmxlICVmXG4iLCBkKTsKCX0KfTsKCmludCBtYWluKCkKewoJbWF4KDMsIDMuMTRmKS5hcHBseShQcmludGxuKCkpOyAgICAgICAgIC8vIGZsb2F0IDMuMTQwMDAwCgltYXgoMywgMy4xNGYsIDMuMCkuYXBwbHkoUHJpbnRsbigpKTsgICAgLy8gZmxvYXQgMy4xNDAwMDAKCW1heCgzLCAzLjE0ZiwgNC4wKS5hcHBseShQcmludGxuKCkpOyAgICAvLyBkb3VibGUgNC4wMDAwMDAKCW1heCgzLCA1LCAzLjE0ZiwgNC4wKS5hcHBseShQcmludGxuKCkpOyAvLyBpbnQgNQoKCXJldHVybiAwOwp9Cg==