#include <cstdio>
#include <typeinfo>
#include <utility>
#include <type_traits>
namespace luple_ns {
//type list
template<typename... TT> struct type_list { static const int size = sizeof...(TT); };
//get element type by index
template<typename T, int N, int M = 0> struct tlist_get;
template<int N, int M, typename T, typename... TT> struct tlist_get< type_list<T, TT...>, N, M > {
static_assert(N < (int) sizeof...(TT)+1 + M, "type index out of bounds");
using type = std::conditional_t< N == M, T, typename tlist_get< type_list<TT...>, N, M + 1 >::type >;
};
template<int N, int M> struct tlist_get< type_list<>, N, M > {
using type = void;
};
template<typename T, int N>
using tlist_get_t = typename tlist_get<T, N>::type;
//get element index by type
template<typename T, typename U, int N = 0> struct tlist_get_n;
template<typename U, int N, typename T, typename... TT> struct tlist_get_n< type_list<T, TT...>, U, N > {
static const int value = std::is_same< T, U >::value ? N : tlist_get_n< type_list<TT...>, U, N + 1 >::value;
};
template<typename U, int N> struct tlist_get_n< type_list<>, U, N > {
static const int value = -1;
};
//a building block that is used in multiple inheritane
template<typename T, int N> struct tuple_element {
tlist_get_t<T, N> value;
};
//base of luple and also parent of tuple_element's
template<typename T, typename U> struct tuple_base;
template<typename... TT, int... NN>
struct tuple_base< type_list<TT...>, std::integer_sequence<int, NN...> > : tuple_element< type_list<TT...>, NN >... {
using tlist = type_list<TT...>;
template<typename... UU, typename U = std::enable_if_t< sizeof...(UU) == sizeof...(NN) >>
constexpr tuple_base ( UU&&... args ) : tuple_element< tlist, NN >{ std::forward<UU>(args) }... {}
constexpr tuple_base ( TT const&... args ) : tuple_element< tlist, NN >{ args }... {}
constexpr tuple_base ( TT&&... args ) : tuple_element< tlist, NN >{ std::move(args) }... {}
constexpr tuple_base () {}
};
//tuple=luple
//T: type_list< ... user types ... >
template<typename T> struct tuple : tuple_base< T, std::make_integer_sequence<int, T::size> > {
using type_list = T;
using base = tuple_base< T, std::make_integer_sequence<int, T::size> >;
template<int N> constexpr auto& get() {
static_assert(N < T::size, "tuple::get -> out of bounds access");
return tuple_element< T, N >::value;
}
template<typename U> constexpr auto& get() {
static_assert(tlist_get_n<T, U>::value != -1, "no such type in type list");
return tuple_element< T, tlist_get_n<T, U>::value >::value;
}
template<int N> constexpr auto& get() const {
static_assert(N < T::size, "tuple::get -> out of bounds access");
return tuple_element< T, N >::value;
}
template<typename U> constexpr auto& get() const {
static_assert(tlist_get_n<T, U>::value != -1, "no such type in type list");
return tuple_element< T, tlist_get_n<T, U>::value >::value;
}
using base::base;
};
template<int N, typename T> constexpr auto& get ( tuple<T>& t ) { return t.template get<N>(); }
template<typename U, typename T> constexpr auto& get ( tuple<T>& t ) { return t.template get<U>(); }
template<int N, typename T> constexpr auto& get ( tuple<T> const& t ) { return t.template get<N>(); }
template<typename U, typename T> constexpr auto& get ( tuple<T> const& t ) { return t.template get<U>(); }
template<typename T> constexpr auto size ( tuple<T> const& t ) { return T::size; }
template<typename U, typename T> constexpr auto index ( tuple<T> const& t ) { return tlist_get_n< T, U >::value; }
//type for index
template<typename T, int N>
using element_t = tlist_get_t< typename T::type_list, N >;
//helper to make luple<A, B, C> and luple< type_list<A, B, C> > equivalent
template<typename T> struct luple_impl {
using type = tuple<T>;
};
template<typename... TT> struct luple_impl< type_list< type_list<TT...> > > {
using type = typename luple_impl< type_list<TT...> >::type;
};
//template alias to wrap types into type_list
template<typename... TT>
using luple = typename luple_impl< type_list<TT...> >::type;
//helper to run code for every member of luple
template<int... N, typename T0, typename T1>
void luple_do_impl (std::integer_sequence<int, N...>, T0& t, T1 fn) {
char dummy[]{ (fn( get<N>(t) ), char{})... };
(void)dummy;
}
//helper to run code for every member of tuple
template<typename T0, typename T1>
void luple_do (T0& t, T1 fn) {
luple_do_impl( std::make_integer_sequence< int, T0::type_list::size >{}, t, fn );
}
}
//import into global namespace
using luple_ns::luple;
using luple_ns::get;
using luple_ns::index;
namespace struct_reader {
using namespace luple_ns;
//this is the main type list, add your own types here
using type_list_t = type_list<
void *, bool, char, unsigned char, signed char, short, int, long, long long,
unsigned short, unsigned int, unsigned long, unsigned long long,
float, double, long double,
_IO_marker *,_IO_FILE *
>;
//helper to get type using a templated conversion operator
template<typename T>
struct read_type {
template<typename U>
constexpr operator U() {
using noptr = std::remove_pointer_t<U>;
using nocon = std::remove_const_t<noptr>;
static_assert( tlist_get_n<T, U>::value != -1 || tlist_get_n<T, nocon>::value != -1, "no such type in type list");
constexpr int const tid = 0xFFFF, is_ptr = 1 << 16, is_con = 1 << 17;
data = tlist_get_n<T, U>::value;
if( data == -1 ) {
data = tlist_get_n<T, nocon>::value & tid;
data = data | (std::is_pointer<U>::value ? is_ptr : 0);
data = data | (std::is_const<noptr>::value ? is_con : 0);
}
return {};
}
int data;
};
using read_type_t = read_type< type_list_t >;
//here we're using overload resolution to get a data member type
template<typename T, int... N>
constexpr auto get_type_id(int n) {
read_type_t tid[sizeof...(N)]{};
T d = T{ tid[N]... }; (void)d;
return tid[n].data;
}
//helper to rebuild the type
template<typename T, int tid, int is_pointer, int is_const>
constexpr auto get_type() {
using type = tlist_get_t<T, tid>;
using ctype = std::conditional_t< (bool)is_const, std::add_const_t<type>, type >;
using ptype = std::conditional_t< (bool)is_pointer, std::add_pointer_t<ctype>, ctype >;
return ptype{};
}
//read struct data member types and put it into a type list
template<typename T, int... N>
constexpr auto get_type_list(std::integer_sequence<int, N...>) {
constexpr int t[] = { get_type_id<T, N...>(N)... };
constexpr int const tid = 0xFFFF, is_ptr = 1 << 16, is_con = 1 << 17;
return type_list< decltype(get_type<type_list_t, t[N]&tid, t[N]&is_ptr, t[N]&is_con>())...>{};
}
//get fields number using expression SFINAE
template<typename T, int... N>
constexpr auto fields_number(...) { return sizeof...(N)-1; }
template<typename T, int... N>
constexpr auto fields_number(int) -> decltype(T{ (N,read_type_t{})... }, sizeof(0)) { return fields_number<T, N..., 0>(0); }
//and here is our hot and fresh out of kitchen type list (alias template)
template<typename T>
using as_type_list = decltype(get_type_list< T >(std::make_integer_sequence< int, fields_number<T>(0) >{}));
}
int main() {
using FILE_tlist = struct_reader::as_type_list< FILE >;
//for being able to read out FILE I had to add _IO_marker* and _IO_FILE* to type_list_t
//check notes in the file struct-reader.h at https://g...content-available-to-author-only...b.com/alexpolt/luple
using FILE_luple = luple< FILE_tlist >;
auto& t = reinterpret_cast<FILE_luple&>( *stdout );
printf("sizeof FILE = %zd, sizeof FILE_luple = %zd\n", sizeof(FILE), sizeof(t));
luple_do(t, [i=0](auto& value) mutable { printf("%d. %s: %#zX, \n", i++, typeid(value).name(), (size_t)value); });
}
I2luY2x1ZGUgPGNzdGRpbz4KI2luY2x1ZGUgPHR5cGVpbmZvPgoKI2luY2x1ZGUgPHV0aWxpdHk+CiNpbmNsdWRlIDx0eXBlX3RyYWl0cz4KCm5hbWVzcGFjZSBsdXBsZV9ucyB7CgogIC8vdHlwZSBsaXN0CiAgdGVtcGxhdGU8dHlwZW5hbWUuLi4gVFQ+IHN0cnVjdCB0eXBlX2xpc3QgeyBzdGF0aWMgY29uc3QgaW50IHNpemUgPSBzaXplb2YuLi4oVFQpOyB9OwoKICAvL2dldCBlbGVtZW50IHR5cGUgYnkgaW5kZXgKICB0ZW1wbGF0ZTx0eXBlbmFtZSBULCBpbnQgTiwgaW50IE0gPSAwPiBzdHJ1Y3QgdGxpc3RfZ2V0OwoKICB0ZW1wbGF0ZTxpbnQgTiwgaW50IE0sIHR5cGVuYW1lIFQsIHR5cGVuYW1lLi4uIFRUPiBzdHJ1Y3QgdGxpc3RfZ2V0PCB0eXBlX2xpc3Q8VCwgVFQuLi4+LCBOLCBNID4gewogICAgc3RhdGljX2Fzc2VydChOIDwgKGludCkgc2l6ZW9mLi4uKFRUKSsxICsgTSwgInR5cGUgaW5kZXggb3V0IG9mIGJvdW5kcyIpOwogICAgdXNpbmcgdHlwZSA9IHN0ZDo6Y29uZGl0aW9uYWxfdDwgTiA9PSBNLCBULCB0eXBlbmFtZSB0bGlzdF9nZXQ8IHR5cGVfbGlzdDxUVC4uLj4sIE4sIE0gKyAxID46OnR5cGUgPjsKICB9OwoKICB0ZW1wbGF0ZTxpbnQgTiwgaW50IE0+IHN0cnVjdCB0bGlzdF9nZXQ8IHR5cGVfbGlzdDw+LCBOLCBNID4gewogICAgdXNpbmcgdHlwZSA9IHZvaWQ7CiAgfTsKCiAgdGVtcGxhdGU8dHlwZW5hbWUgVCwgaW50IE4+CiAgdXNpbmcgdGxpc3RfZ2V0X3QgPSB0eXBlbmFtZSB0bGlzdF9nZXQ8VCwgTj46OnR5cGU7CgogIC8vZ2V0IGVsZW1lbnQgaW5kZXggYnkgdHlwZQogIHRlbXBsYXRlPHR5cGVuYW1lIFQsIHR5cGVuYW1lIFUsIGludCBOID0gMD4gc3RydWN0IHRsaXN0X2dldF9uOwoKICB0ZW1wbGF0ZTx0eXBlbmFtZSBVLCBpbnQgTiwgdHlwZW5hbWUgVCwgdHlwZW5hbWUuLi4gVFQ+IHN0cnVjdCB0bGlzdF9nZXRfbjwgdHlwZV9saXN0PFQsIFRULi4uPiwgVSwgTiA+IHsKICAgIHN0YXRpYyBjb25zdCBpbnQgdmFsdWUgPSBzdGQ6OmlzX3NhbWU8IFQsIFUgPjo6dmFsdWUgPyBOIDogdGxpc3RfZ2V0X248IHR5cGVfbGlzdDxUVC4uLj4sIFUsIE4gKyAxID46OnZhbHVlOwogIH07CiAgdGVtcGxhdGU8dHlwZW5hbWUgVSwgaW50IE4+IHN0cnVjdCB0bGlzdF9nZXRfbjwgdHlwZV9saXN0PD4sIFUsIE4gPiB7CiAgICBzdGF0aWMgY29uc3QgaW50IHZhbHVlID0gLTE7CiAgfTsKCiAgLy9hIGJ1aWxkaW5nIGJsb2NrIHRoYXQgaXMgdXNlZCBpbiBtdWx0aXBsZSBpbmhlcml0YW5lCiAgdGVtcGxhdGU8dHlwZW5hbWUgVCwgaW50IE4+IHN0cnVjdCB0dXBsZV9lbGVtZW50IHsKICAgIHRsaXN0X2dldF90PFQsIE4+IHZhbHVlOwogIH07CgogIC8vYmFzZSBvZiBsdXBsZSBhbmQgYWxzbyBwYXJlbnQgb2YgdHVwbGVfZWxlbWVudCdzCiAgdGVtcGxhdGU8dHlwZW5hbWUgVCwgdHlwZW5hbWUgVT4gc3RydWN0IHR1cGxlX2Jhc2U7CgogIHRlbXBsYXRlPHR5cGVuYW1lLi4uIFRULCBpbnQuLi4gTk4+CiAgc3RydWN0IHR1cGxlX2Jhc2U8IHR5cGVfbGlzdDxUVC4uLj4sIHN0ZDo6aW50ZWdlcl9zZXF1ZW5jZTxpbnQsIE5OLi4uPiA+IDogdHVwbGVfZWxlbWVudDwgdHlwZV9saXN0PFRULi4uPiwgTk4gPi4uLiB7CgogICAgdXNpbmcgdGxpc3QgPSB0eXBlX2xpc3Q8VFQuLi4+OwoKICAgIHRlbXBsYXRlPHR5cGVuYW1lLi4uIFVVLCB0eXBlbmFtZSBVID0gc3RkOjplbmFibGVfaWZfdDwgc2l6ZW9mLi4uKFVVKSA9PSBzaXplb2YuLi4oTk4pID4+CiAgICBjb25zdGV4cHIgdHVwbGVfYmFzZSAoIFVVJiYuLi4gYXJncyApIDogdHVwbGVfZWxlbWVudDwgdGxpc3QsIE5OID57IHN0ZDo6Zm9yd2FyZDxVVT4oYXJncykgfS4uLiB7fQogICAgY29uc3RleHByIHR1cGxlX2Jhc2UgKCBUVCBjb25zdCYuLi4gYXJncyApIDogdHVwbGVfZWxlbWVudDwgdGxpc3QsIE5OID57IGFyZ3MgfS4uLiB7fQogICAgY29uc3RleHByIHR1cGxlX2Jhc2UgKCBUVCYmLi4uIGFyZ3MgKSA6IHR1cGxlX2VsZW1lbnQ8IHRsaXN0LCBOTiA+eyBzdGQ6Om1vdmUoYXJncykgfS4uLiB7fQogICAgY29uc3RleHByIHR1cGxlX2Jhc2UgKCkge30KICB9OwoKICAvL3R1cGxlPWx1cGxlCiAgLy9UOiB0eXBlX2xpc3Q8IC4uLiB1c2VyIHR5cGVzIC4uLiA+CiAgdGVtcGxhdGU8dHlwZW5hbWUgVD4gc3RydWN0IHR1cGxlIDogdHVwbGVfYmFzZTwgVCwgc3RkOjptYWtlX2ludGVnZXJfc2VxdWVuY2U8aW50LCBUOjpzaXplPiA+IHsKCiAgICB1c2luZyB0eXBlX2xpc3QgPSBUOwogICAgdXNpbmcgYmFzZSA9IHR1cGxlX2Jhc2U8IFQsIHN0ZDo6bWFrZV9pbnRlZ2VyX3NlcXVlbmNlPGludCwgVDo6c2l6ZT4gPjsKCiAgICB0ZW1wbGF0ZTxpbnQgTj4gY29uc3RleHByIGF1dG8mIGdldCgpIHsKICAgICAgc3RhdGljX2Fzc2VydChOIDwgVDo6c2l6ZSwgInR1cGxlOjpnZXQgLT4gb3V0IG9mIGJvdW5kcyBhY2Nlc3MiKTsKICAgICAgcmV0dXJuIHR1cGxlX2VsZW1lbnQ8IFQsIE4gPjo6dmFsdWU7CiAgICB9CgogICAgdGVtcGxhdGU8dHlwZW5hbWUgVT4gY29uc3RleHByIGF1dG8mIGdldCgpIHsKICAgICAgc3RhdGljX2Fzc2VydCh0bGlzdF9nZXRfbjxULCBVPjo6dmFsdWUgIT0gLTEsICJubyBzdWNoIHR5cGUgaW4gdHlwZSBsaXN0Iik7CiAgICAgIHJldHVybiB0dXBsZV9lbGVtZW50PCBULCB0bGlzdF9nZXRfbjxULCBVPjo6dmFsdWUgPjo6dmFsdWU7CiAgICB9CgogICAgdGVtcGxhdGU8aW50IE4+IGNvbnN0ZXhwciBhdXRvJiBnZXQoKSBjb25zdCB7CiAgICAgIHN0YXRpY19hc3NlcnQoTiA8IFQ6OnNpemUsICJ0dXBsZTo6Z2V0IC0+IG91dCBvZiBib3VuZHMgYWNjZXNzIik7CiAgICAgIHJldHVybiB0dXBsZV9lbGVtZW50PCBULCBOID46OnZhbHVlOwogICAgfQoKICAgIHRlbXBsYXRlPHR5cGVuYW1lIFU+IGNvbnN0ZXhwciBhdXRvJiBnZXQoKSBjb25zdCB7CiAgICAgIHN0YXRpY19hc3NlcnQodGxpc3RfZ2V0X248VCwgVT46OnZhbHVlICE9IC0xLCAibm8gc3VjaCB0eXBlIGluIHR5cGUgbGlzdCIpOwogICAgICByZXR1cm4gdHVwbGVfZWxlbWVudDwgVCwgdGxpc3RfZ2V0X248VCwgVT46OnZhbHVlID46OnZhbHVlOwogICAgfQoKICAgIHVzaW5nIGJhc2U6OmJhc2U7CiAgfTsKCiAgdGVtcGxhdGU8aW50IE4sIHR5cGVuYW1lIFQ+IGNvbnN0ZXhwciBhdXRvJiBnZXQgKCB0dXBsZTxUPiYgdCApIHsgcmV0dXJuIHQudGVtcGxhdGUgZ2V0PE4+KCk7IH0KICB0ZW1wbGF0ZTx0eXBlbmFtZSBVLCB0eXBlbmFtZSBUPiBjb25zdGV4cHIgYXV0byYgZ2V0ICggdHVwbGU8VD4mIHQgKSB7IHJldHVybiB0LnRlbXBsYXRlIGdldDxVPigpOyB9CgogIHRlbXBsYXRlPGludCBOLCB0eXBlbmFtZSBUPiBjb25zdGV4cHIgYXV0byYgZ2V0ICggdHVwbGU8VD4gY29uc3QmIHQgKSB7IHJldHVybiB0LnRlbXBsYXRlIGdldDxOPigpOyB9CiAgdGVtcGxhdGU8dHlwZW5hbWUgVSwgdHlwZW5hbWUgVD4gY29uc3RleHByIGF1dG8mIGdldCAoIHR1cGxlPFQ+IGNvbnN0JiB0ICkgeyByZXR1cm4gdC50ZW1wbGF0ZSBnZXQ8VT4oKTsgfQoKICB0ZW1wbGF0ZTx0eXBlbmFtZSBUPiBjb25zdGV4cHIgYXV0byBzaXplICggdHVwbGU8VD4gY29uc3QmIHQgKSB7IHJldHVybiBUOjpzaXplOyB9CiAgdGVtcGxhdGU8dHlwZW5hbWUgVSwgdHlwZW5hbWUgVD4gY29uc3RleHByIGF1dG8gaW5kZXggKCB0dXBsZTxUPiBjb25zdCYgdCApIHsgcmV0dXJuIHRsaXN0X2dldF9uPCBULCBVID46OnZhbHVlOyB9CgogIC8vdHlwZSBmb3IgaW5kZXgKICB0ZW1wbGF0ZTx0eXBlbmFtZSBULCBpbnQgTj4KICB1c2luZyBlbGVtZW50X3QgPSB0bGlzdF9nZXRfdDwgdHlwZW5hbWUgVDo6dHlwZV9saXN0LCBOID47CgogIC8vaGVscGVyIHRvIG1ha2UgbHVwbGU8QSwgQiwgQz4gYW5kIGx1cGxlPCB0eXBlX2xpc3Q8QSwgQiwgQz4gPiBlcXVpdmFsZW50CiAgdGVtcGxhdGU8dHlwZW5hbWUgVD4gc3RydWN0IGx1cGxlX2ltcGwgewogICAgdXNpbmcgdHlwZSA9IHR1cGxlPFQ+OwogIH07CgogIHRlbXBsYXRlPHR5cGVuYW1lLi4uIFRUPiBzdHJ1Y3QgbHVwbGVfaW1wbDwgdHlwZV9saXN0PCB0eXBlX2xpc3Q8VFQuLi4+ID4gPiB7CiAgICB1c2luZyB0eXBlID0gdHlwZW5hbWUgbHVwbGVfaW1wbDwgdHlwZV9saXN0PFRULi4uPiA+Ojp0eXBlOwogIH07CgogIC8vdGVtcGxhdGUgYWxpYXMgdG8gd3JhcCB0eXBlcyBpbnRvIHR5cGVfbGlzdAogIHRlbXBsYXRlPHR5cGVuYW1lLi4uIFRUPgogIHVzaW5nIGx1cGxlID0gdHlwZW5hbWUgbHVwbGVfaW1wbDwgdHlwZV9saXN0PFRULi4uPiA+Ojp0eXBlOwoKICAvL2hlbHBlciB0byBydW4gY29kZSBmb3IgZXZlcnkgbWVtYmVyIG9mIGx1cGxlCiAgdGVtcGxhdGU8aW50Li4uIE4sIHR5cGVuYW1lIFQwLCB0eXBlbmFtZSBUMT4KICB2b2lkIGx1cGxlX2RvX2ltcGwgKHN0ZDo6aW50ZWdlcl9zZXF1ZW5jZTxpbnQsIE4uLi4+LCBUMCYgdCwgVDEgZm4pIHsKICAgIGNoYXIgZHVtbXlbXXsgKGZuKCBnZXQ8Tj4odCkgKSwgY2hhcnt9KS4uLiB9OwogICAgKHZvaWQpZHVtbXk7CiAgfQoKICAvL2hlbHBlciB0byBydW4gY29kZSBmb3IgZXZlcnkgbWVtYmVyIG9mIHR1cGxlCiAgdGVtcGxhdGU8dHlwZW5hbWUgVDAsIHR5cGVuYW1lIFQxPgogIHZvaWQgbHVwbGVfZG8gKFQwJiB0LCBUMSBmbikgewogICAgbHVwbGVfZG9faW1wbCggc3RkOjptYWtlX2ludGVnZXJfc2VxdWVuY2U8IGludCwgVDA6OnR5cGVfbGlzdDo6c2l6ZSA+e30sIHQsIGZuICk7CiAgfQogIAp9CgovL2ltcG9ydCBpbnRvIGdsb2JhbCBuYW1lc3BhY2UKdXNpbmcgbHVwbGVfbnM6Omx1cGxlOwp1c2luZyBsdXBsZV9uczo6Z2V0Owp1c2luZyBsdXBsZV9uczo6aW5kZXg7CgoKCm5hbWVzcGFjZSBzdHJ1Y3RfcmVhZGVyIHsKCiAgdXNpbmcgbmFtZXNwYWNlIGx1cGxlX25zOwoKICAvL3RoaXMgaXMgdGhlIG1haW4gdHlwZSBsaXN0LCBhZGQgeW91ciBvd24gdHlwZXMgaGVyZQogIHVzaW5nIHR5cGVfbGlzdF90ID0gdHlwZV9saXN0PAogICAgICAgICAgICB2b2lkICosIGJvb2wsIGNoYXIsIHVuc2lnbmVkIGNoYXIsIHNpZ25lZCBjaGFyLCBzaG9ydCwgaW50LCBsb25nLCBsb25nIGxvbmcsIAogICAgICAgICAgICB1bnNpZ25lZCBzaG9ydCwgdW5zaWduZWQgaW50LCB1bnNpZ25lZCBsb25nLCB1bnNpZ25lZCBsb25nIGxvbmcsIAogICAgICAgICAgICBmbG9hdCwgZG91YmxlLCBsb25nIGRvdWJsZSwKICAgICAgICAgICAgX0lPX21hcmtlciAqLF9JT19GSUxFICoKICAgICAgICAgID47CgogIC8vaGVscGVyIHRvIGdldCB0eXBlIHVzaW5nIGEgdGVtcGxhdGVkIGNvbnZlcnNpb24gb3BlcmF0b3IKICB0ZW1wbGF0ZTx0eXBlbmFtZSBUPgogIHN0cnVjdCByZWFkX3R5cGUgewogICAgdGVtcGxhdGU8dHlwZW5hbWUgVT4KICAgIGNvbnN0ZXhwciBvcGVyYXRvciBVKCkgewogICAgICB1c2luZyBub3B0ciA9IHN0ZDo6cmVtb3ZlX3BvaW50ZXJfdDxVPjsKICAgICAgdXNpbmcgbm9jb24gPSBzdGQ6OnJlbW92ZV9jb25zdF90PG5vcHRyPjsKICAgICAgc3RhdGljX2Fzc2VydCggdGxpc3RfZ2V0X248VCwgVT46OnZhbHVlICE9IC0xIHx8IHRsaXN0X2dldF9uPFQsIG5vY29uPjo6dmFsdWUgIT0gLTEsICJubyBzdWNoIHR5cGUgaW4gdHlwZSBsaXN0Iik7CiAgICAgIGNvbnN0ZXhwciBpbnQgY29uc3QgdGlkID0gMHhGRkZGLCBpc19wdHIgPSAxIDw8IDE2LCBpc19jb24gPSAxIDw8IDE3OwogICAgICBkYXRhID0gdGxpc3RfZ2V0X248VCwgVT46OnZhbHVlOwogICAgICBpZiggZGF0YSA9PSAtMSApIHsKICAgICAgICBkYXRhID0gdGxpc3RfZ2V0X248VCwgbm9jb24+Ojp2YWx1ZSAmIHRpZDsKICAgICAgICBkYXRhID0gZGF0YSB8IChzdGQ6OmlzX3BvaW50ZXI8VT46OnZhbHVlID8gaXNfcHRyIDogMCk7CiAgICAgICAgZGF0YSA9IGRhdGEgfCAoc3RkOjppc19jb25zdDxub3B0cj46OnZhbHVlID8gaXNfY29uIDogMCk7CiAgICAgIH0KICAgICAgcmV0dXJuIHt9OwogICAgfQogICAgaW50IGRhdGE7CiAgfTsKCiAgdXNpbmcgcmVhZF90eXBlX3QgPSByZWFkX3R5cGU8IHR5cGVfbGlzdF90ID47CgogIC8vaGVyZSB3ZSdyZSB1c2luZyBvdmVybG9hZCByZXNvbHV0aW9uIHRvIGdldCBhIGRhdGEgbWVtYmVyIHR5cGUKICB0ZW1wbGF0ZTx0eXBlbmFtZSBULCBpbnQuLi4gTj4KICBjb25zdGV4cHIgYXV0byBnZXRfdHlwZV9pZChpbnQgbikgewogICAgcmVhZF90eXBlX3QgdGlkW3NpemVvZi4uLihOKV17fTsKICAgIFQgZCA9IFR7IHRpZFtOXS4uLiB9OyAodm9pZClkOwogICAgcmV0dXJuIHRpZFtuXS5kYXRhOwogIH0KCiAgLy9oZWxwZXIgdG8gcmVidWlsZCB0aGUgdHlwZQogIHRlbXBsYXRlPHR5cGVuYW1lIFQsIGludCB0aWQsIGludCBpc19wb2ludGVyLCBpbnQgaXNfY29uc3Q+CiAgY29uc3RleHByIGF1dG8gZ2V0X3R5cGUoKSB7CiAgICB1c2luZyB0eXBlID0gdGxpc3RfZ2V0X3Q8VCwgdGlkPjsKICAgIHVzaW5nIGN0eXBlID0gc3RkOjpjb25kaXRpb25hbF90PCAoYm9vbClpc19jb25zdCwgc3RkOjphZGRfY29uc3RfdDx0eXBlPiwgdHlwZSA+OwogICAgdXNpbmcgcHR5cGUgPSBzdGQ6OmNvbmRpdGlvbmFsX3Q8IChib29sKWlzX3BvaW50ZXIsIHN0ZDo6YWRkX3BvaW50ZXJfdDxjdHlwZT4sIGN0eXBlID47CiAgICByZXR1cm4gcHR5cGV7fTsKICB9CgogIC8vcmVhZCBzdHJ1Y3QgZGF0YSBtZW1iZXIgdHlwZXMgYW5kIHB1dCBpdCBpbnRvIGEgdHlwZSBsaXN0CiAgdGVtcGxhdGU8dHlwZW5hbWUgVCwgaW50Li4uIE4+CiAgY29uc3RleHByIGF1dG8gZ2V0X3R5cGVfbGlzdChzdGQ6OmludGVnZXJfc2VxdWVuY2U8aW50LCBOLi4uPikgewogICAgY29uc3RleHByIGludCB0W10gPSB7IGdldF90eXBlX2lkPFQsIE4uLi4+KE4pLi4uIH07CiAgICBjb25zdGV4cHIgaW50IGNvbnN0IHRpZCA9IDB4RkZGRiwgaXNfcHRyID0gMSA8PCAxNiwgaXNfY29uID0gMSA8PCAxNzsKICAgIHJldHVybiB0eXBlX2xpc3Q8IGRlY2x0eXBlKGdldF90eXBlPHR5cGVfbGlzdF90LCB0W05dJnRpZCwgdFtOXSZpc19wdHIsIHRbTl0maXNfY29uPigpKS4uLj57fTsKICB9CgogIC8vZ2V0IGZpZWxkcyBudW1iZXIgdXNpbmcgZXhwcmVzc2lvbiBTRklOQUUKICB0ZW1wbGF0ZTx0eXBlbmFtZSBULCBpbnQuLi4gTj4KICBjb25zdGV4cHIgYXV0byBmaWVsZHNfbnVtYmVyKC4uLikgeyByZXR1cm4gc2l6ZW9mLi4uKE4pLTE7IH0KCiAgdGVtcGxhdGU8dHlwZW5hbWUgVCwgaW50Li4uIE4+CiAgY29uc3RleHByIGF1dG8gZmllbGRzX251bWJlcihpbnQpIC0+IGRlY2x0eXBlKFR7IChOLHJlYWRfdHlwZV90e30pLi4uIH0sIHNpemVvZigwKSkgeyByZXR1cm4gZmllbGRzX251bWJlcjxULCBOLi4uLCAwPigwKTsgfQoKICAvL2FuZCBoZXJlIGlzIG91ciBob3QgYW5kIGZyZXNoIG91dCBvZiBraXRjaGVuIHR5cGUgbGlzdCAoYWxpYXMgdGVtcGxhdGUpCiAgdGVtcGxhdGU8dHlwZW5hbWUgVD4KICB1c2luZyBhc190eXBlX2xpc3QgPSBkZWNsdHlwZShnZXRfdHlwZV9saXN0PCBUID4oc3RkOjptYWtlX2ludGVnZXJfc2VxdWVuY2U8IGludCwgZmllbGRzX251bWJlcjxUPigwKSA+e30pKTsKCn0KCmludCBtYWluKCkgewoKICB1c2luZyBGSUxFX3RsaXN0ID0gc3RydWN0X3JlYWRlcjo6YXNfdHlwZV9saXN0PCBGSUxFID47CgogIC8vZm9yIGJlaW5nIGFibGUgdG8gcmVhZCBvdXQgRklMRSBJIGhhZCB0byBhZGQgX0lPX21hcmtlciogYW5kIF9JT19GSUxFKiB0byB0eXBlX2xpc3RfdAogIC8vY2hlY2sgbm90ZXMgaW4gdGhlIGZpbGUgc3RydWN0LXJlYWRlci5oIGF0IGh0dHBzOi8vZy4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4uYi5jb20vYWxleHBvbHQvbHVwbGUKCiAgdXNpbmcgRklMRV9sdXBsZSA9IGx1cGxlPCBGSUxFX3RsaXN0ID47CgogIGF1dG8mIHQgPSByZWludGVycHJldF9jYXN0PEZJTEVfbHVwbGUmPiggKnN0ZG91dCApOwoKICBwcmludGYoInNpemVvZiBGSUxFID0gJXpkLCBzaXplb2YgRklMRV9sdXBsZSA9ICV6ZFxuIiwgc2l6ZW9mKEZJTEUpLCBzaXplb2YodCkpOwoKICBsdXBsZV9kbyh0LCBbaT0wXShhdXRvJiB2YWx1ZSkgbXV0YWJsZSB7IHByaW50ZigiJWQuICVzOiAlI3pYLCBcbiIsIGkrKywgdHlwZWlkKHZhbHVlKS5uYW1lKCksIChzaXplX3QpdmFsdWUpOyB9KTsKCn0=