From c9501805b648e3a03246c20464b0ec40c27897ba Mon Sep 17 00:00:00 2001 From: Snaipe Date: Thu, 3 Sep 2015 06:38:44 +0200 Subject: [PATCH] Added support for theories --- CMakeLists.txt | 4 + include/criterion/theories.h | 79 ++++++++++++++++++++ samples/CMakeLists.txt | 1 + samples/theories.c | 19 +++++ src/theories.c | 137 +++++++++++++++++++++++++++++++++++ 5 files changed, 240 insertions(+) create mode 100644 include/criterion/theories.h create mode 100644 samples/theories.c create mode 100644 src/theories.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 8dfa056..ba5c894 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,6 +68,7 @@ set(SOURCE_FILES src/i18n.h src/ordered-set.c src/posix-compat.c + src/theories.c src/main.c ) @@ -91,6 +92,7 @@ set(INTERFACE_FILES include/criterion/options.h include/criterion/ordered-set.h include/criterion/stats.h + include/criterion/theories.h ) # Generate the configure file @@ -120,6 +122,8 @@ if (COVERALLS) coveralls_setup("${SOURCE_FILES}" ${COVERALLS_UPLOAD}) endif() +target_link_libraries(criterion dyncall_s) + install(FILES ${INTERFACE_FILES} DESTINATION include/criterion) install(TARGETS criterion RUNTIME DESTINATION bin diff --git a/include/criterion/theories.h b/include/criterion/theories.h new file mode 100644 index 0000000..4da3527 --- /dev/null +++ b/include/criterion/theories.h @@ -0,0 +1,79 @@ +/* + * The MIT License (MIT) + * + * Copyright © 2015 Franklin "Snaipe" Mathieu + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef CRITERION_THEORIES_H_ +# define CRITERION_THEORIES_H_ + +# include +# include "criterion.h" + +struct criterion_theory_context; + +struct criterion_theory_context* cr_theory_init(void); +void cr_theory_push_arg(struct criterion_theory_context *ctx, bool is_float, size_t size, void *ptr); +void cr_theory_free(struct criterion_theory_context *ctx); +void cr_theory_abort(void); +int cr_theory_mark(void); + +void cr_theory_reset(struct criterion_theory_context *ctx); +void cr_theory_call(struct criterion_theory_context *ctx, void (*fnptr)(void)); + +# define TheoryDataPoints(Category, Name) \ + static struct criterion_datapoints IDENTIFIER_(Category, Name, dps)[] + +# define DataPoints(Type, ...) \ + { sizeof (Type), sizeof ((Type[]) { __VA_ARGS__ }) / sizeof (Type), #Type, &(Type[]) { __VA_ARGS__ } } + +struct criterion_datapoints { + size_t size; + size_t len; + const char *name; + void *arr; +}; + +# define CR_NB_DATAPOINTS(Var) \ + (sizeof (Var) / sizeof (struct criterion_datapoints)) + +# define cr_assume(Condition) \ + do { \ + if (!(Condition)) \ + cr_theory_abort(); \ + } while (0); + +void cr_theory_main(struct criterion_datapoints *dps, size_t datapoints, void (*fnptr)(void)); + +# define CR_VAARG_ID(Suffix, Category, Name, ...) \ + IDENTIFIER_(Category, Name, Suffix) + +# define Theory(Args, ...) \ + void CR_VAARG_ID(theory, __VA_ARGS__,)Args; \ + Test_(__VA_ARGS__, .sentinel_ = 0) { \ + cr_theory_main( \ + CR_VAARG_ID(dps, __VA_ARGS__,), \ + CR_NB_DATAPOINTS(CR_VAARG_ID(dps, __VA_ARGS__,)), \ + (void(*)(void)) CR_VAARG_ID(theory, __VA_ARGS__,) \ + ); \ + } \ + void CR_VAARG_ID(theory, __VA_ARGS__,)Args + +#endif /* !CRITERION_THEORIES_H_ */ diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 17edd70..b33b9b2 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -13,6 +13,7 @@ set(SAMPLES description other-crashes simple + theories ) set(SCRIPTS diff --git a/samples/theories.c b/samples/theories.c new file mode 100644 index 0000000..eb36d66 --- /dev/null +++ b/samples/theories.c @@ -0,0 +1,19 @@ +#include + +TheoryDataPoints(theory, simple) = { + DataPoints(int, 1, 2, 3), + DataPoints(long, 314, 42) +}; + +Theory((int a, long b), theory, simple) { + cr_assume(a == 2); + printf("%d, %ld\n", a, b); +} + +TheoryDataPoints(theory, float) = { + DataPoints(float, 3.14, 42), +}; + +Theory((float a), theory, float) { + printf("%f\n", (double) a); +} diff --git a/src/theories.c b/src/theories.c new file mode 100644 index 0000000..e846543 --- /dev/null +++ b/src/theories.c @@ -0,0 +1,137 @@ +/* + * The MIT License (MIT) + * + * Copyright © 2015 Franklin "Snaipe" Mathieu + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include "criterion/theories.h" + +struct criterion_theory_context { + DCCallVM* vm; +}; + +void cr_theory_push_arg(struct criterion_theory_context *ctx, bool is_float, size_t size, void *ptr) { + if (is_float) { + if (size == sizeof (float)) { + dcArgFloat(ctx->vm, *(float*)ptr); + } else if (size == sizeof (double)) { + dcArgDouble(ctx->vm, *(double*)ptr); + } else if (size == sizeof (long double)) { + dcArgDouble(ctx->vm, *(long double*)ptr); + } + } else { + if (size == sizeof (char)) { + dcArgChar(ctx->vm, *(char*)ptr); + } else if (size == sizeof (short)) { + dcArgShort(ctx->vm, *(short*)ptr); + } else if (size == sizeof (int)) { + dcArgInt(ctx->vm, *(int*)ptr); + } else if (size == sizeof (bool)) { + dcArgBool(ctx->vm, *(bool*)ptr); + } else if (size == sizeof (long)) { + dcArgLong(ctx->vm, *(long*)ptr); + } else if (size == sizeof (long long)) { + dcArgLongLong(ctx->vm, *(long long*)ptr); + } else if (size == sizeof (void*)) { + dcArgPointer(ctx->vm, *(void**)ptr); + } else { + dcArgPointer(ctx->vm, ptr); + } + } +} + +struct criterion_theory_context* cr_theory_init(void) { + struct criterion_theory_context* ctx = malloc(sizeof (struct criterion_theory_context)); + ctx->vm = dcNewCallVM(4096); + dcMode(ctx->vm, DC_CALL_C_DEFAULT); + return ctx; +} + +void cr_theory_free(struct criterion_theory_context *ctx) { + dcFree(ctx->vm); +} + +static jmp_buf theory_jmp; + +void cr_theory_abort(void) { + longjmp(theory_jmp, 1); +} + +int cr_theory_mark(void) { + return setjmp(theory_jmp); +} + +void cr_theory_reset(struct criterion_theory_context *ctx) { + dcReset(ctx->vm); +} + +void cr_theory_call(struct criterion_theory_context *ctx, void (*fnptr)(void)) { + dcCallVoid(ctx->vm, (DCpointer) fnptr); +} + +static bool contains_word(const char *str, const char *pattern, size_t sz) { + char *res = strstr(str, pattern); + + return res + && (res == str || (res > str && res[-1] == ' ')) + && (!res[sz - 1] || res[sz - 1] == ' '); +} + +void cr_theory_main(struct criterion_datapoints *dps, size_t datapoints, void (*fnptr)(void)) { + struct criterion_theory_context *ctx = cr_theory_init(); + + size_t indices[datapoints]; + memset(indices, 0, datapoints * sizeof (size_t)); + + bool has_next = true; + while (has_next) { + if (!cr_theory_mark()) { + cr_theory_reset(ctx); + for (size_t i = 0; i < datapoints; ++i) { + + bool is_float = contains_word(dps[i].name, "float", sizeof ("float")) + || contains_word(dps[i].name, "double", sizeof ("double")); + + cr_theory_push_arg(ctx, + is_float, + dps[i].size, + ((char*) dps[i].arr) + dps[i].size * indices[i]); + } + cr_theory_call(ctx, fnptr); + } + + for (size_t i = 0; i < datapoints; ++i) { + if (indices[i] == dps[i].len - 1) { + indices[i] = 0; + has_next = i != (datapoints - 1); + } else { + ++indices[i]; + break; + } + } + } + + cr_theory_free(ctx); +}