/*
* Because we are using the kindly-provided services of
* http://i...content-available-to-author-only...e.com , we mush together three separate
* files using some preprocessor tricks. The files are
* identified individually so that you can copy and paste
* them into their own files, if you so choose. The
* stuff that only matters for this http://i...content-available-to-author-only...e.com
* paste is every line that contains the text
* 'ALL_IN_ONE'. This very comment section is also not
* part of the three files
*/
#ifndef MULDIM_TEST_C_ /* ALL_IN_ONE */
#define MULDIM_TEST_C_ /* ALL_IN_ONE */
/**** muldim_test.c - Shao Miller, April 4th, 2012 */
#include <stdlib.h>
#include <stdio.h>
#if 0 /* ALL_IN_ONE */
#include "muldim.h"
#else /* ALL_IN_ONE */
#include "prog.c" /* ALL_IN_ONE */
#endif /* ALL_IN_ONE */
/*** Macros */
#define CountOf(array) (sizeof (array) / sizeof *(array))
int main(void) {
int result;
muldim_t arr;
muldim_t end;
int test[2][3][4];
int i, j, k, * ip;
/* Assume failure */
result = EXIT_FAILURE;
/* Same dimensions as 'test' */
arr = muldim_zalloc(sizeof (int), 3, 2, 3, 4);
if (!arr.ptr) {
goto err_arr;
}
muldim_dmp(arr);
end = muldim_get(arr, 3, 1, 2, 4);
if (!end.ptr) {
goto err_end;
}
muldim_dmp(end);
"(\n"
" (char *) (test[1][2] + 4) -\n"
" (char *) test[0][0]\n"
" ) == %d\n",
(
(char *) (test[1][2] + 4) -
(char *) test[0][0]
)
);
"(\n"
" (char *) end.ptr -\n"
" (char *) arr.ptr\n"
" ) == %d\n",
(
(char *) end.ptr -
(char *) arr.ptr
)
);
/* Same dimensions as 'test' */
for (i = 0; i < CountOf(test); ++i) {
for (j = 0; j < CountOf(test[0]); ++j) {
ip = muldim_get(arr, 2, i, j).ptr;
for (k = 0; k < CountOf(test[0][0]); ++k) {
if (ip[k]) {
printf("muldim_zalloc failed!\n"); goto err_nonzero;
}
ip[k] = 42;
continue;
}
continue;
}
continue;
}
/* Success */
result = EXIT_SUCCESS;
err_nonzero:
err_end:
err_arr:
return result;
}
#else /* ALL_IN_ONE */
/**** muldim.h - Shao Miller, April 4th, 2012 */
#ifndef MULDIM_H_
#include <stddef.h>
/*** Macros */
#define MULDIM_H_
/*** Object types */
typedef struct s_muldim s_muldim, muldim_t;
/*** Struct/union definitions */
struct s_muldim {
void * ptr;
size_t dims;
size_t stride;
size_t * dims_at;
void * mem;
};
/*** Function declarations */
extern muldim_t muldim_alloc(size_t base_sz, size_t dims, ...);
extern muldim_t muldim_zalloc(size_t base_sz, size_t dims, ...);
extern muldim_t muldim_get(muldim_t muldim, size_t dims, ...);
extern void muldim_dmp(muldim_t muldim);
#endif /* MULDIM_H_ */
/**** muldim.c - Shao Miller, April 4th, 2012 */
#include <stddef.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#if 0 /* ALL_IN_ONE */
#include "muldim.h"
#endif /* ALL_IN_ONE */
/*** Function declarations */
static size_t sz_add(size_t x, size_t y);
static size_t sz_mul(size_t x, size_t y);
/*** Struct/union definitions */
struct s_muldim_wrapper {
muldim_t muldim;
size_t dims_hdr[1];
};
/*** Object definitions */
static const muldim_t new_muldim;
/*** Function definitions */
muldim_t muldim_alloc(size_t base_sz, size_t dims, ...) {
register const size_t dims_offset
= offsetof( struct s_muldim_wrapper,
dims_hdr
);
muldim_t result;
size_t dims_sz;
size_t hdr_sz;
va_list vargs;
size_t array_sz;
size_t i;
int dim;
size_t total_sz;
char * ptr;
size_t * dims_at;
result = new_muldim;
if (!base_sz) {
goto err_base_sz;
}
dims_sz = sz_mul(dims, sizeof result.dims_at[0]);
if (!dims_sz) {
goto err_dims_sz;
}
hdr_sz = sz_add(dims_offset, dims_sz);
if (!hdr_sz) {
goto err_hdr_sz;
}
hdr_sz = sz_add(base_sz, hdr_sz);
if (!hdr_sz) {
goto err_hdr_sz;
}
hdr_sz = hdr_sz - 1;
hdr_sz = hdr_sz / base_sz;
hdr_sz = hdr_sz * base_sz;
array_sz = base_sz;
for (i = dims; i; --i) {
if (dim < 1) {
goto err_dim;
}
array_sz = sz_mul(array_sz, (size_t) dim);
if (!array_sz) {
goto err_array_sz;
}
continue;
}
total_sz = sz_add(hdr_sz, array_sz);
if (!total_sz) {
goto err_total_sz;
}
if (!ptr) {
goto err_ptr;
}
/* Success */
dims_at = (void *) (ptr + dims_offset);
for (i = 0; i < dims; ++i) {
dims_at[i] = (size_t) dim;
continue;
}
result.ptr = ptr + hdr_sz;
result.dims = dims;
result.stride = array_sz;
result.dims_at = dims_at;
result.mem = ptr;
*(muldim_t *) ptr = result;
return result;
err_ptr:
err_total_sz:
err_array_sz:
err_dim:
err_hdr_sz:
err_dims_sz:
err_base_sz:
return result;
}
muldim_t muldim_zalloc(size_t base_sz, size_t dims, ...) {
register const size_t dims_offset
= offsetof( struct s_muldim_wrapper,
dims_hdr
);
muldim_t result;
size_t dims_sz;
size_t hdr_sz;
va_list vargs;
size_t array_sz;
size_t i;
int dim;
size_t total_sz;
char * ptr;
size_t * dims_at;
result = new_muldim;
if (!base_sz) {
goto err_base_sz;
}
dims_sz = sz_mul(dims, sizeof result.dims_at[0]);
if (!dims_sz) {
goto err_dims_sz;
}
hdr_sz = sz_add(dims_offset, dims_sz);
if (!hdr_sz) {
goto err_hdr_sz;
}
hdr_sz = sz_add(base_sz, hdr_sz);
if (!hdr_sz) {
goto err_hdr_sz;
}
hdr_sz = hdr_sz - 1;
hdr_sz = hdr_sz / base_sz;
hdr_sz = hdr_sz * base_sz;
array_sz = base_sz;
for (i = dims; i; --i) {
if (dim < 1) {
goto err_dim;
}
array_sz = sz_mul(array_sz, (size_t) dim);
if (!array_sz) {
goto err_array_sz;
}
continue;
}
total_sz = sz_add(hdr_sz, array_sz);
if (!total_sz) {
goto err_total_sz;
}
total_sz = total_sz / base_sz;
ptr
= calloc(total_sz
, base_sz
); if (!ptr) {
goto err_ptr;
}
/* Success */
dims_at = (void *) (ptr + dims_offset);
for (i = 0; i < dims; ++i) {
dims_at[i] = (size_t) dim;
continue;
}
result.ptr = ptr + hdr_sz;
result.dims = dims;
result.stride = array_sz;
result.dims_at = dims_at;
result.mem = ptr;
*(muldim_t *) ptr = result;
return result;
err_ptr:
err_total_sz:
err_array_sz:
err_dim:
err_hdr_sz:
err_dims_sz:
err_base_sz:
return result;
}
muldim_t muldim_get(muldim_t muldim, size_t dims, ...) {
char * ptr;
va_list vargs;
int dim;
if (!dims || dims > muldim.dims) {
goto err_dims;
}
ptr = muldim.ptr;
while (dims--) {
if (dim < 0 || dim > muldim.dims_at[0]) {
goto err_dim;
}
muldim.stride = muldim.stride / muldim.dims_at[0];
ptr = ptr + muldim.stride * dim;
--muldim.dims;
++muldim.dims_at;
continue;
}
/* Success */
muldim.ptr = ptr;
return muldim;
err_dim:
err_dims:
return new_muldim;
}
void muldim_dmp(muldim_t muldim) {
"ptr == %p\n"
"dims == %u\n"
"stride == %u\n"
"dims_at == %p\n"
"mem == %p\n",
muldim.ptr,
(unsigned int) muldim.dims,
(unsigned int) muldim.stride,
(void *) muldim.dims_at,
muldim.mem
);
while (muldim.dims--) {
printf("%u, ", (unsigned int) muldim.
dims_at++[0]); continue;
}
return;
}
static size_t sz_add(size_t x, size_t y) {
size_t result;
result = x + y;
if (result <= x || result <= y) {
/* Wrap-around */
return 0;
}
return result;
}
static size_t sz_mul(size_t x, size_t y) {
size_t result;
result = x * y;
if (result <= x || result <= y) {
/* Wrap-around */
return 0;
}
return result;
}
#endif /* ALL_IN_ONE */
LyoKICogQmVjYXVzZSB3ZSBhcmUgdXNpbmcgdGhlIGtpbmRseS1wcm92aWRlZCBzZXJ2aWNlcyBvZgogKiBodHRwOi8vaS4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4uZS5jb20gLCB3ZSBtdXNoIHRvZ2V0aGVyIHRocmVlIHNlcGFyYXRlCiAqIGZpbGVzIHVzaW5nIHNvbWUgcHJlcHJvY2Vzc29yIHRyaWNrcy4gIFRoZSBmaWxlcyBhcmUKICogaWRlbnRpZmllZCBpbmRpdmlkdWFsbHkgc28gdGhhdCB5b3UgY2FuIGNvcHkgYW5kIHBhc3RlCiAqIHRoZW0gaW50byB0aGVpciBvd24gZmlsZXMsIGlmIHlvdSBzbyBjaG9vc2UuICBUaGUKICogc3R1ZmYgdGhhdCBvbmx5IG1hdHRlcnMgZm9yIHRoaXMgaHR0cDovL2kuLi5jb250ZW50LWF2YWlsYWJsZS10by1hdXRob3Itb25seS4uLmUuY29tCiAqIHBhc3RlIGlzIGV2ZXJ5IGxpbmUgdGhhdCBjb250YWlucyB0aGUgdGV4dAogKiAnQUxMX0lOX09ORScuICBUaGlzIHZlcnkgY29tbWVudCBzZWN0aW9uIGlzIGFsc28gbm90CiAqIHBhcnQgb2YgdGhlIHRocmVlIGZpbGVzCiAqLwoKI2lmbmRlZiBNVUxESU1fVEVTVF9DXyAvKiBBTExfSU5fT05FICovCiNkZWZpbmUgTVVMRElNX1RFU1RfQ18gLyogQUxMX0lOX09ORSAqLwoKCgogIC8qKioqIG11bGRpbV90ZXN0LmMgLSBTaGFvIE1pbGxlciwgQXByaWwgNHRoLCAyMDEyICovCgogICNpbmNsdWRlIDxzdGRsaWIuaD4KICAjaW5jbHVkZSA8c3RkaW8uaD4KCiNpZiAwIC8qIEFMTF9JTl9PTkUgKi8KICAjaW5jbHVkZSAibXVsZGltLmgiCiNlbHNlIC8qIEFMTF9JTl9PTkUgKi8KI2luY2x1ZGUgInByb2cuYyIgLyogQUxMX0lOX09ORSAqLwojZW5kaWYgLyogQUxMX0lOX09ORSAqLwoKICAvKioqIE1hY3JvcyAqLwogICNkZWZpbmUgQ291bnRPZihhcnJheSkgKHNpemVvZiAoYXJyYXkpIC8gc2l6ZW9mICooYXJyYXkpKQoKICBpbnQgbWFpbih2b2lkKSB7CiAgICAgIGludCByZXN1bHQ7CiAgICAgIG11bGRpbV90IGFycjsKICAgICAgbXVsZGltX3QgZW5kOwogICAgICBpbnQgdGVzdFsyXVszXVs0XTsKICAgICAgaW50IGksIGosIGssICogaXA7CgogICAgICAvKiBBc3N1bWUgZmFpbHVyZSAqLwogICAgICByZXN1bHQgPSBFWElUX0ZBSUxVUkU7CgogICAgICAvKiBTYW1lIGRpbWVuc2lvbnMgYXMgJ3Rlc3QnICovCiAgICAgIGFyciA9IG11bGRpbV96YWxsb2Moc2l6ZW9mIChpbnQpLCAzLCAyLCAzLCA0KTsKICAgICAgaWYgKCFhcnIucHRyKSB7CiAgICAgICAgICBnb3RvIGVycl9hcnI7CiAgICAgICAgfQoKICAgICAgbXVsZGltX2RtcChhcnIpOwoKICAgICAgZW5kID0gbXVsZGltX2dldChhcnIsIDMsIDEsIDIsIDQpOwogICAgICBpZiAoIWVuZC5wdHIpIHsKICAgICAgICAgIGdvdG8gZXJyX2VuZDsKICAgICAgICB9CgogICAgICBtdWxkaW1fZG1wKGVuZCk7CgogICAgICBwcmludGYoCiAgICAgICAgICAiKFxuIgogICAgICAgICAgIiAgICAoY2hhciAqKSAodGVzdFsxXVsyXSArIDQpIC1cbiIKICAgICAgICAgICIgICAgKGNoYXIgKikgdGVzdFswXVswXVxuIgogICAgICAgICAgIiAgKSA9PSAlZFxuIiwKICAgICAgICAgICgKICAgICAgICAgICAgICAoY2hhciAqKSAodGVzdFsxXVsyXSArIDQpIC0KICAgICAgICAgICAgICAoY2hhciAqKSB0ZXN0WzBdWzBdCiAgICAgICAgICAgICkKICAgICAgICApOwoKICAgICAgcHJpbnRmKAogICAgICAgICAgIihcbiIKICAgICAgICAgICIgICAgKGNoYXIgKikgZW5kLnB0ciAtXG4iCiAgICAgICAgICAiICAgIChjaGFyICopIGFyci5wdHJcbiIKICAgICAgICAgICIgICkgPT0gJWRcbiIsCiAgICAgICAgICAoCiAgICAgICAgICAgICAgKGNoYXIgKikgZW5kLnB0ciAtCiAgICAgICAgICAgICAgKGNoYXIgKikgYXJyLnB0cgogICAgICAgICAgICApCiAgICAgICAgKTsKCiAgICAgIC8qIFNhbWUgZGltZW5zaW9ucyBhcyAndGVzdCcgKi8KICAgICAgZm9yIChpID0gMDsgaSA8IENvdW50T2YodGVzdCk7ICsraSkgewogICAgICAgICAgZm9yIChqID0gMDsgaiA8IENvdW50T2YodGVzdFswXSk7ICsraikgewogICAgICAgICAgICAgIGlwID0gbXVsZGltX2dldChhcnIsIDIsIGksIGopLnB0cjsKICAgICAgICAgICAgICBmb3IgKGsgPSAwOyBrIDwgQ291bnRPZih0ZXN0WzBdWzBdKTsgKytrKSB7CiAgICAgICAgICAgICAgICAgIGlmIChpcFtrXSkgewogICAgICAgICAgICAgICAgICAgICAgcHJpbnRmKCJtdWxkaW1femFsbG9jIGZhaWxlZCFcbiIpOwogICAgICAgICAgICAgICAgICAgICAgZ290byBlcnJfbm9uemVybzsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgIGlwW2tdID0gNDI7CiAgICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICB9CiAgICAgICAgICBjb250aW51ZTsKICAgICAgICB9CgogICAgICAvKiBTdWNjZXNzICovCiAgICAgIHByaW50ZigiWWF5XG4iKTsKICAgICAgcmVzdWx0ID0gRVhJVF9TVUNDRVNTOwoKICAgICAgZXJyX25vbnplcm86CgogICAgICBlcnJfZW5kOgoKICAgICAgZnJlZShhcnIubWVtKTsKICAgICAgZXJyX2FycjoKCiAgICAgIHJldHVybiByZXN1bHQ7CiAgICB9CgoKCiNlbHNlIC8qIEFMTF9JTl9PTkUgKi8KCgoKICAvKioqKiBtdWxkaW0uaCAgLSBTaGFvIE1pbGxlciwgQXByaWwgNHRoLCAyMDEyICovCgogICNpZm5kZWYgTVVMRElNX0hfCgogICNpbmNsdWRlIDxzdGRkZWYuaD4KCiAgLyoqKiBNYWNyb3MgKi8KICAjZGVmaW5lIE1VTERJTV9IXwoKICAvKioqIE9iamVjdCB0eXBlcyAqLwoKICB0eXBlZGVmIHN0cnVjdCBzX211bGRpbSBzX211bGRpbSwgbXVsZGltX3Q7CgogIC8qKiogU3RydWN0L3VuaW9uIGRlZmluaXRpb25zICovCgogIHN0cnVjdCBzX211bGRpbSB7CiAgICAgIHZvaWQgKiBwdHI7CiAgICAgIHNpemVfdCBkaW1zOwogICAgICBzaXplX3Qgc3RyaWRlOwogICAgICBzaXplX3QgKiBkaW1zX2F0OwogICAgICB2b2lkICogbWVtOwogICAgfTsKCiAgLyoqKiBGdW5jdGlvbiBkZWNsYXJhdGlvbnMgKi8KCiAgZXh0ZXJuIG11bGRpbV90IG11bGRpbV9hbGxvYyhzaXplX3QgYmFzZV9zeiwgc2l6ZV90IGRpbXMsIC4uLik7CiAgZXh0ZXJuIG11bGRpbV90IG11bGRpbV96YWxsb2Moc2l6ZV90IGJhc2Vfc3osIHNpemVfdCBkaW1zLCAuLi4pOwogIGV4dGVybiBtdWxkaW1fdCBtdWxkaW1fZ2V0KG11bGRpbV90IG11bGRpbSwgc2l6ZV90IGRpbXMsIC4uLik7CiAgZXh0ZXJuIHZvaWQgbXVsZGltX2RtcChtdWxkaW1fdCBtdWxkaW0pOwoKICAjZW5kaWYgLyogTVVMRElNX0hfICovCgoKCiAgLyoqKiogbXVsZGltLmMgIC0gU2hhbyBNaWxsZXIsIEFwcmlsIDR0aCwgMjAxMiAqLwoKICAjaW5jbHVkZSA8c3RkZGVmLmg+CiAgI2luY2x1ZGUgPHN0ZGFyZy5oPgogICNpbmNsdWRlIDxzdGRsaWIuaD4KICAjaW5jbHVkZSA8c3RkaW8uaD4KCiNpZiAwIC8qIEFMTF9JTl9PTkUgKi8KICAjaW5jbHVkZSAibXVsZGltLmgiCiNlbmRpZiAvKiBBTExfSU5fT05FICovCgogIC8qKiogRnVuY3Rpb24gZGVjbGFyYXRpb25zICovCgogIHN0YXRpYyBzaXplX3Qgc3pfYWRkKHNpemVfdCB4LCBzaXplX3QgeSk7CiAgc3RhdGljIHNpemVfdCBzel9tdWwoc2l6ZV90IHgsIHNpemVfdCB5KTsKCiAgLyoqKiBTdHJ1Y3QvdW5pb24gZGVmaW5pdGlvbnMgKi8KCiAgc3RydWN0IHNfbXVsZGltX3dyYXBwZXIgewogICAgICBtdWxkaW1fdCBtdWxkaW07CiAgICAgIHNpemVfdCBkaW1zX2hkclsxXTsKICAgIH07CgogIC8qKiogT2JqZWN0IGRlZmluaXRpb25zICovCiAgc3RhdGljIGNvbnN0IG11bGRpbV90IG5ld19tdWxkaW07CgogIC8qKiogRnVuY3Rpb24gZGVmaW5pdGlvbnMgKi8KCiAgbXVsZGltX3QgbXVsZGltX2FsbG9jKHNpemVfdCBiYXNlX3N6LCBzaXplX3QgZGltcywgLi4uKSB7CiAgICAgIHJlZ2lzdGVyIGNvbnN0IHNpemVfdCBkaW1zX29mZnNldCA9IG9mZnNldG9mKAogICAgICAgICAgc3RydWN0IHNfbXVsZGltX3dyYXBwZXIsCiAgICAgICAgICBkaW1zX2hkcgogICAgICAgICk7CiAgICAgIG11bGRpbV90IHJlc3VsdDsKICAgICAgc2l6ZV90IGRpbXNfc3o7CiAgICAgIHNpemVfdCBoZHJfc3o7CiAgICAgIHZhX2xpc3QgdmFyZ3M7CiAgICAgIHNpemVfdCBhcnJheV9zejsKICAgICAgc2l6ZV90IGk7CiAgICAgIGludCBkaW07CiAgICAgIHNpemVfdCB0b3RhbF9zejsKICAgICAgY2hhciAqIHB0cjsKICAgICAgc2l6ZV90ICogZGltc19hdDsKCiAgICAgIHJlc3VsdCA9IG5ld19tdWxkaW07CgogICAgICBpZiAoIWJhc2Vfc3opIHsKICAgICAgICAgIGdvdG8gZXJyX2Jhc2Vfc3o7CiAgICAgICAgfQoKICAgICAgZGltc19zeiA9IHN6X211bChkaW1zLCBzaXplb2YgcmVzdWx0LmRpbXNfYXRbMF0pOwogICAgICBpZiAoIWRpbXNfc3opIHsKICAgICAgICAgIGdvdG8gZXJyX2RpbXNfc3o7CiAgICAgICAgfQoKICAgICAgaGRyX3N6ID0gc3pfYWRkKGRpbXNfb2Zmc2V0LCBkaW1zX3N6KTsKICAgICAgaWYgKCFoZHJfc3opIHsKICAgICAgICAgIGdvdG8gZXJyX2hkcl9zejsKICAgICAgICB9CiAgICAgIGhkcl9zeiA9IHN6X2FkZChiYXNlX3N6LCBoZHJfc3opOwogICAgICBpZiAoIWhkcl9zeikgewogICAgICAgICAgZ290byBlcnJfaGRyX3N6OwogICAgICAgIH0KICAgICAgaGRyX3N6ID0gaGRyX3N6IC0gMTsKICAgICAgaGRyX3N6ID0gaGRyX3N6IC8gYmFzZV9zejsKICAgICAgaGRyX3N6ID0gaGRyX3N6ICogYmFzZV9zejsKCiAgICAgIHZhX3N0YXJ0KHZhcmdzLCBkaW1zKTsKICAgICAgYXJyYXlfc3ogPSBiYXNlX3N6OwogICAgICBmb3IgKGkgPSBkaW1zOyBpOyAtLWkpIHsKICAgICAgICAgIGRpbSA9IHZhX2FyZyh2YXJncywgaW50KTsKICAgICAgICAgIGlmIChkaW0gPCAxKSB7CiAgICAgICAgICAgICAgZ290byBlcnJfZGltOwogICAgICAgICAgICB9CgogICAgICAgICAgYXJyYXlfc3ogPSBzel9tdWwoYXJyYXlfc3osIChzaXplX3QpIGRpbSk7CiAgICAgICAgICBpZiAoIWFycmF5X3N6KSB7CiAgICAgICAgICAgICAgZ290byBlcnJfYXJyYXlfc3o7CiAgICAgICAgICAgIH0KCiAgICAgICAgICBjb250aW51ZTsKICAgICAgICB9CiAgICAgIHZhX2VuZCh2YXJncyk7CgogICAgICB0b3RhbF9zeiA9IHN6X2FkZChoZHJfc3osIGFycmF5X3N6KTsKICAgICAgaWYgKCF0b3RhbF9zeikgewogICAgICAgICAgZ290byBlcnJfdG90YWxfc3o7CiAgICAgICAgfQoKICAgICAgcHRyID0gbWFsbG9jKHRvdGFsX3N6KTsKICAgICAgaWYgKCFwdHIpIHsKICAgICAgICAgIGdvdG8gZXJyX3B0cjsKICAgICAgICB9CgogICAgICAvKiBTdWNjZXNzICovCgogICAgICBkaW1zX2F0ID0gKHZvaWQgKikgKHB0ciArIGRpbXNfb2Zmc2V0KTsKCiAgICAgIHZhX3N0YXJ0KHZhcmdzLCBkaW1zKTsKICAgICAgZm9yIChpID0gMDsgaSA8IGRpbXM7ICsraSkgewogICAgICAgICAgZGltID0gdmFfYXJnKHZhcmdzLCBpbnQpOwogICAgICAgICAgZGltc19hdFtpXSA9IChzaXplX3QpIGRpbTsKCiAgICAgICAgICBjb250aW51ZTsKICAgICAgICB9CiAgICAgIHZhX2VuZCh2YXJncyk7CgogICAgICByZXN1bHQucHRyID0gcHRyICsgaGRyX3N6OwogICAgICByZXN1bHQuZGltcyA9IGRpbXM7CiAgICAgIHJlc3VsdC5zdHJpZGUgPSBhcnJheV9zejsKICAgICAgcmVzdWx0LmRpbXNfYXQgPSBkaW1zX2F0OwogICAgICByZXN1bHQubWVtID0gcHRyOwoKICAgICAgKihtdWxkaW1fdCAqKSBwdHIgPSByZXN1bHQ7CiAgICAgIHJldHVybiByZXN1bHQ7CgogICAgICBmcmVlKHB0cik7CiAgICAgIGVycl9wdHI6CgogICAgICBlcnJfdG90YWxfc3o6CgogICAgICBlcnJfYXJyYXlfc3o6CgogICAgICBlcnJfZGltOgoKICAgICAgZXJyX2hkcl9zejoKCiAgICAgIGVycl9kaW1zX3N6OgoKICAgICAgZXJyX2Jhc2Vfc3o6CgogICAgICByZXR1cm4gcmVzdWx0OwogICAgfQoKICBtdWxkaW1fdCBtdWxkaW1femFsbG9jKHNpemVfdCBiYXNlX3N6LCBzaXplX3QgZGltcywgLi4uKSB7CiAgICAgIHJlZ2lzdGVyIGNvbnN0IHNpemVfdCBkaW1zX29mZnNldCA9IG9mZnNldG9mKAogICAgICAgICAgc3RydWN0IHNfbXVsZGltX3dyYXBwZXIsCiAgICAgICAgICBkaW1zX2hkcgogICAgICAgICk7CiAgICAgIG11bGRpbV90IHJlc3VsdDsKICAgICAgc2l6ZV90IGRpbXNfc3o7CiAgICAgIHNpemVfdCBoZHJfc3o7CiAgICAgIHZhX2xpc3QgdmFyZ3M7CiAgICAgIHNpemVfdCBhcnJheV9zejsKICAgICAgc2l6ZV90IGk7CiAgICAgIGludCBkaW07CiAgICAgIHNpemVfdCB0b3RhbF9zejsKICAgICAgY2hhciAqIHB0cjsKICAgICAgc2l6ZV90ICogZGltc19hdDsKCiAgICAgIHJlc3VsdCA9IG5ld19tdWxkaW07CgogICAgICBpZiAoIWJhc2Vfc3opIHsKICAgICAgICAgIGdvdG8gZXJyX2Jhc2Vfc3o7CiAgICAgICAgfQoKICAgICAgZGltc19zeiA9IHN6X211bChkaW1zLCBzaXplb2YgcmVzdWx0LmRpbXNfYXRbMF0pOwogICAgICBpZiAoIWRpbXNfc3opIHsKICAgICAgICAgIGdvdG8gZXJyX2RpbXNfc3o7CiAgICAgICAgfQoKICAgICAgaGRyX3N6ID0gc3pfYWRkKGRpbXNfb2Zmc2V0LCBkaW1zX3N6KTsKICAgICAgaWYgKCFoZHJfc3opIHsKICAgICAgICAgIGdvdG8gZXJyX2hkcl9zejsKICAgICAgICB9CiAgICAgIGhkcl9zeiA9IHN6X2FkZChiYXNlX3N6LCBoZHJfc3opOwogICAgICBpZiAoIWhkcl9zeikgewogICAgICAgICAgZ290byBlcnJfaGRyX3N6OwogICAgICAgIH0KICAgICAgaGRyX3N6ID0gaGRyX3N6IC0gMTsKICAgICAgaGRyX3N6ID0gaGRyX3N6IC8gYmFzZV9zejsKICAgICAgaGRyX3N6ID0gaGRyX3N6ICogYmFzZV9zejsKCiAgICAgIHZhX3N0YXJ0KHZhcmdzLCBkaW1zKTsKICAgICAgYXJyYXlfc3ogPSBiYXNlX3N6OwogICAgICBmb3IgKGkgPSBkaW1zOyBpOyAtLWkpIHsKICAgICAgICAgIGRpbSA9IHZhX2FyZyh2YXJncywgaW50KTsKICAgICAgICAgIGlmIChkaW0gPCAxKSB7CiAgICAgICAgICAgICAgZ290byBlcnJfZGltOwogICAgICAgICAgICB9CgogICAgICAgICAgYXJyYXlfc3ogPSBzel9tdWwoYXJyYXlfc3osIChzaXplX3QpIGRpbSk7CiAgICAgICAgICBpZiAoIWFycmF5X3N6KSB7CiAgICAgICAgICAgICAgZ290byBlcnJfYXJyYXlfc3o7CiAgICAgICAgICAgIH0KCiAgICAgICAgICBjb250aW51ZTsKICAgICAgICB9CiAgICAgIHZhX2VuZCh2YXJncyk7CgogICAgICB0b3RhbF9zeiA9IHN6X2FkZChoZHJfc3osIGFycmF5X3N6KTsKICAgICAgaWYgKCF0b3RhbF9zeikgewogICAgICAgICAgZ290byBlcnJfdG90YWxfc3o7CiAgICAgICAgfQoKICAgICAgdG90YWxfc3ogPSB0b3RhbF9zeiAvIGJhc2Vfc3o7CiAgICAgIHB0ciA9IGNhbGxvYyh0b3RhbF9zeiwgYmFzZV9zeik7CiAgICAgIGlmICghcHRyKSB7CiAgICAgICAgICBnb3RvIGVycl9wdHI7CiAgICAgICAgfQoKICAgICAgLyogU3VjY2VzcyAqLwoKICAgICAgZGltc19hdCA9ICh2b2lkICopIChwdHIgKyBkaW1zX29mZnNldCk7CgogICAgICB2YV9zdGFydCh2YXJncywgZGltcyk7CiAgICAgIGZvciAoaSA9IDA7IGkgPCBkaW1zOyArK2kpIHsKICAgICAgICAgIGRpbSA9IHZhX2FyZyh2YXJncywgaW50KTsKICAgICAgICAgIGRpbXNfYXRbaV0gPSAoc2l6ZV90KSBkaW07CgogICAgICAgICAgY29udGludWU7CiAgICAgICAgfQogICAgICB2YV9lbmQodmFyZ3MpOwoKICAgICAgcmVzdWx0LnB0ciA9IHB0ciArIGhkcl9zejsKICAgICAgcmVzdWx0LmRpbXMgPSBkaW1zOwogICAgICByZXN1bHQuc3RyaWRlID0gYXJyYXlfc3o7CiAgICAgIHJlc3VsdC5kaW1zX2F0ID0gZGltc19hdDsKICAgICAgcmVzdWx0Lm1lbSA9IHB0cjsKCiAgICAgICoobXVsZGltX3QgKikgcHRyID0gcmVzdWx0OwogICAgICByZXR1cm4gcmVzdWx0OwoKICAgICAgZnJlZShwdHIpOwogICAgICBlcnJfcHRyOgoKICAgICAgZXJyX3RvdGFsX3N6OgoKICAgICAgZXJyX2FycmF5X3N6OgoKICAgICAgZXJyX2RpbToKCiAgICAgIGVycl9oZHJfc3o6CgogICAgICBlcnJfZGltc19zejoKCiAgICAgIGVycl9iYXNlX3N6OgoKICAgICAgcmV0dXJuIHJlc3VsdDsKICAgIH0KCiAgbXVsZGltX3QgbXVsZGltX2dldChtdWxkaW1fdCBtdWxkaW0sIHNpemVfdCBkaW1zLCAuLi4pIHsKICAgICAgY2hhciAqIHB0cjsKICAgICAgdmFfbGlzdCB2YXJnczsKICAgICAgaW50IGRpbTsKCiAgICAgIGlmICghZGltcyB8fCBkaW1zID4gbXVsZGltLmRpbXMpIHsKICAgICAgICAgIGdvdG8gZXJyX2RpbXM7CiAgICAgICAgfQoKICAgICAgcHRyID0gbXVsZGltLnB0cjsKICAgICAgdmFfc3RhcnQodmFyZ3MsIGRpbXMpOwogICAgICB3aGlsZSAoZGltcy0tKSB7CiAgICAgICAgICBkaW0gPSB2YV9hcmcodmFyZ3MsIGludCk7CiAgICAgICAgICBpZiAoZGltIDwgMCB8fCBkaW0gPiBtdWxkaW0uZGltc19hdFswXSkgewogICAgICAgICAgICAgIGdvdG8gZXJyX2RpbTsKICAgICAgICAgICAgfQoKICAgICAgICAgIG11bGRpbS5zdHJpZGUgPSBtdWxkaW0uc3RyaWRlIC8gbXVsZGltLmRpbXNfYXRbMF07CiAgICAgICAgICBwdHIgPSBwdHIgKyBtdWxkaW0uc3RyaWRlICogZGltOwogICAgICAgICAgLS1tdWxkaW0uZGltczsKICAgICAgICAgICsrbXVsZGltLmRpbXNfYXQ7CgogICAgICAgICAgY29udGludWU7CiAgICAgICAgfQogICAgICB2YV9lbmQodmFyZ3MpOwoKICAgICAgLyogU3VjY2VzcyAqLwoKICAgICAgbXVsZGltLnB0ciA9IHB0cjsKICAgICAgcmV0dXJuIG11bGRpbTsKCiAgICAgIGVycl9kaW06CgogICAgICBlcnJfZGltczoKCiAgICAgIHJldHVybiBuZXdfbXVsZGltOwogICAgfQoKICB2b2lkIG11bGRpbV9kbXAobXVsZGltX3QgbXVsZGltKSB7CiAgICAgIHByaW50ZigKICAgICAgICAgICJwdHIgPT0gJXBcbiIKICAgICAgICAgICJkaW1zID09ICV1XG4iCiAgICAgICAgICAic3RyaWRlID09ICV1XG4iCiAgICAgICAgICAiZGltc19hdCA9PSAlcFxuIgogICAgICAgICAgIm1lbSA9PSAlcFxuIiwKICAgICAgICAgIG11bGRpbS5wdHIsCiAgICAgICAgICAodW5zaWduZWQgaW50KSBtdWxkaW0uZGltcywKICAgICAgICAgICh1bnNpZ25lZCBpbnQpIG11bGRpbS5zdHJpZGUsCiAgICAgICAgICAodm9pZCAqKSBtdWxkaW0uZGltc19hdCwKICAgICAgICAgIG11bGRpbS5tZW0KICAgICAgICApOwogICAgICBwcmludGYoImRpbWVuc2lvbnM6IHsgIik7CiAgICAgIHdoaWxlIChtdWxkaW0uZGltcy0tKSB7CiAgICAgICAgICBwcmludGYoIiV1LCAiLCAodW5zaWduZWQgaW50KSBtdWxkaW0uZGltc19hdCsrWzBdKTsKICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgIH0KICAgICAgcHJpbnRmKCJ9XG4iKTsKICAgICAgcmV0dXJuOwogICAgfQoKICBzdGF0aWMgc2l6ZV90IHN6X2FkZChzaXplX3QgeCwgc2l6ZV90IHkpIHsKICAgICAgc2l6ZV90IHJlc3VsdDsKCiAgICAgIHJlc3VsdCA9IHggKyB5OwogICAgICBpZiAocmVzdWx0IDw9IHggfHwgcmVzdWx0IDw9IHkpIHsKICAgICAgICAgIC8qIFdyYXAtYXJvdW5kICovCiAgICAgICAgICByZXR1cm4gMDsKICAgICAgICB9CiAgICAgIHJldHVybiByZXN1bHQ7CiAgICB9CgogIHN0YXRpYyBzaXplX3Qgc3pfbXVsKHNpemVfdCB4LCBzaXplX3QgeSkgewogICAgICBzaXplX3QgcmVzdWx0OwoKICAgICAgcmVzdWx0ID0geCAqIHk7CiAgICAgIGlmIChyZXN1bHQgPD0geCB8fCByZXN1bHQgPD0geSkgewogICAgICAgICAgLyogV3JhcC1hcm91bmQgKi8KICAgICAgICAgIHJldHVybiAwOwogICAgICAgIH0KICAgICAgcmV0dXJuIHJlc3VsdDsKICAgIH0KCgoKI2VuZGlmIC8qIEFMTF9JTl9PTkUgKi8=